changeset 4:ce11bbd8f642

added modules
author danieleb <danielebarchiesi@me.com>
date Thu, 19 Sep 2013 10:38:44 +0100
parents b28be78d8160
children 49b8ebaaad78
files modules/rules/DEVELOPER.txt modules/rules/LICENSE.txt modules/rules/README.txt modules/rules/includes/faces.inc modules/rules/includes/rules.core.inc modules/rules/includes/rules.event.inc modules/rules/includes/rules.plugins.inc modules/rules/includes/rules.processor.inc modules/rules/includes/rules.state.inc modules/rules/includes/rules.upgrade.inc modules/rules/modules/comment.rules.inc modules/rules/modules/data.eval.inc modules/rules/modules/data.rules.inc modules/rules/modules/entity.eval.inc modules/rules/modules/entity.rules.inc modules/rules/modules/events.inc modules/rules/modules/node.eval.inc modules/rules/modules/node.rules.inc modules/rules/modules/path.eval.inc modules/rules/modules/path.rules.inc modules/rules/modules/php.eval.inc modules/rules/modules/php.rules.inc modules/rules/modules/rules_core.eval.inc modules/rules/modules/rules_core.rules.inc modules/rules/modules/system.eval.inc modules/rules/modules/system.rules.inc modules/rules/modules/taxonomy.rules.inc modules/rules/modules/user.eval.inc modules/rules/modules/user.rules.inc modules/rules/rules.api.php modules/rules/rules.features.inc modules/rules/rules.info modules/rules/rules.install modules/rules/rules.module modules/rules/rules.rules.inc modules/rules/rules_admin/rules_admin.inc modules/rules/rules_admin/rules_admin.info modules/rules/rules_admin/rules_admin.module modules/rules/rules_i18n/rules_i18n.i18n.inc modules/rules/rules_i18n/rules_i18n.info modules/rules/rules_i18n/rules_i18n.module modules/rules/rules_i18n/rules_i18n.rules.inc modules/rules/rules_i18n/rules_i18n.test modules/rules/rules_scheduler/includes/rules_scheduler.handler.inc modules/rules/rules_scheduler/includes/rules_scheduler.views.inc modules/rules/rules_scheduler/includes/rules_scheduler.views_default.inc modules/rules/rules_scheduler/includes/rules_scheduler_views_filter.inc modules/rules/rules_scheduler/rules_scheduler.admin.inc modules/rules/rules_scheduler/rules_scheduler.info modules/rules/rules_scheduler/rules_scheduler.install modules/rules/rules_scheduler/rules_scheduler.module modules/rules/rules_scheduler/rules_scheduler.rules.inc modules/rules/rules_scheduler/rules_scheduler.test modules/rules/rules_scheduler/tests/rules_scheduler_test.inc modules/rules/rules_scheduler/tests/rules_scheduler_test.info modules/rules/rules_scheduler/tests/rules_scheduler_test.module modules/rules/tests/rules.test modules/rules/tests/rules_test.info modules/rules/tests/rules_test.module modules/rules/tests/rules_test.rules.inc modules/rules/tests/rules_test.rules_defaults.inc modules/rules/tests/rules_test.test.inc modules/rules/ui/rules.autocomplete.js modules/rules/ui/rules.debug.js modules/rules/ui/rules.ui.css modules/rules/ui/rules.ui.seven.css modules/rules/ui/ui.controller.inc modules/rules/ui/ui.core.inc modules/rules/ui/ui.data.inc modules/rules/ui/ui.forms.inc modules/rules/ui/ui.plugins.inc modules/rules/ui/ui.theme.inc sites/all/.DS_Store sites/all/libraries/ARC2/.DS_Store sites/all/libraries/ARC2/arc/.gitignore sites/all/libraries/ARC2/arc/ARC2.php sites/all/libraries/ARC2/arc/ARC2_Class.php sites/all/libraries/ARC2/arc/ARC2_Graph.php sites/all/libraries/ARC2/arc/ARC2_Reader.php sites/all/libraries/ARC2/arc/ARC2_Resource.php sites/all/libraries/ARC2/arc/ARC2_getFormat.php sites/all/libraries/ARC2/arc/ARC2_getPreferredFormat.php sites/all/libraries/ARC2/arc/README.md sites/all/libraries/ARC2/arc/build.xml sites/all/libraries/ARC2/arc/composer.json sites/all/libraries/ARC2/arc/extractors/ARC2_DcExtractor.php sites/all/libraries/ARC2/arc/extractors/ARC2_ErdfExtractor.php sites/all/libraries/ARC2/arc/extractors/ARC2_MicroformatsExtractor.php sites/all/libraries/ARC2/arc/extractors/ARC2_OpenidExtractor.php sites/all/libraries/ARC2/arc/extractors/ARC2_PoshRdfExtractor.php sites/all/libraries/ARC2/arc/extractors/ARC2_RDFExtractor.php sites/all/libraries/ARC2/arc/extractors/ARC2_RdfaExtractor.php sites/all/libraries/ARC2/arc/extractors/ARC2_TwitterProfilePicExtractor.php sites/all/libraries/ARC2/arc/parsers/ARC2_AtomParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_CBJSONParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_JSONParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_LegacyXMLParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_RDFParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_RDFXMLParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_RSSParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_SGAJSONParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_SPARQLParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_SPARQLPlusParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_SPARQLXMLResultParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_SPOGParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_SemHTMLParser.php sites/all/libraries/ARC2/arc/parsers/ARC2_TurtleParser.php sites/all/libraries/ARC2/arc/serializers/ARC2_LegacyHTMLSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_LegacyJSONSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_LegacyXMLSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_MicroRDFSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_NTriplesSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_POSHRDFSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_RDFJSONSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_RDFSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_RDFXMLSerializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_RSS10Serializer.php sites/all/libraries/ARC2/arc/serializers/ARC2_TurtleSerializer.php sites/all/libraries/ARC2/arc/sparqlscript/ARC2_SPARQLScriptParser.php sites/all/libraries/ARC2/arc/sparqlscript/ARC2_SPARQLScriptProcessor.php sites/all/libraries/ARC2/arc/store/ARC2_MemStore.php sites/all/libraries/ARC2/arc/store/ARC2_RemoteStore.php sites/all/libraries/ARC2/arc/store/ARC2_Store.php sites/all/libraries/ARC2/arc/store/ARC2_StoreAskQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreAtomLoader.php sites/all/libraries/ARC2/arc/store/ARC2_StoreCBJSONLoader.php sites/all/libraries/ARC2/arc/store/ARC2_StoreConstructQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreDeleteQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreDescribeQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreDumpQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreDumper.php sites/all/libraries/ARC2/arc/store/ARC2_StoreEndpoint.php sites/all/libraries/ARC2/arc/store/ARC2_StoreHelper.php sites/all/libraries/ARC2/arc/store/ARC2_StoreInsertQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreLoadQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreRDFXMLLoader.php sites/all/libraries/ARC2/arc/store/ARC2_StoreRSSLoader.php sites/all/libraries/ARC2/arc/store/ARC2_StoreSGAJSONLoader.php sites/all/libraries/ARC2/arc/store/ARC2_StoreSPOGLoader.php sites/all/libraries/ARC2/arc/store/ARC2_StoreSelectQueryHandler.php sites/all/libraries/ARC2/arc/store/ARC2_StoreSemHTMLLoader.php sites/all/libraries/ARC2/arc/store/ARC2_StoreTableManager.php sites/all/libraries/ARC2/arc/store/ARC2_StoreTurtleLoader.php sites/all/libraries/ARC2/arc/tests/ARC2_TestCase.php sites/all/libraries/ARC2/arc/tests/ARC2_TestHandler.php sites/all/libraries/ARC2/arc/tests/data/atom/feed.atom sites/all/libraries/ARC2/arc/tests/data/json/crunchbase-facebook.js sites/all/libraries/ARC2/arc/tests/data/json/sparql-select-result.json sites/all/libraries/ARC2/arc/tests/data/nt/test.nt sites/all/libraries/ARC2/arc/tests/data/rdfxml/planetrdf-bloggers.rdf sites/all/libraries/ARC2/arc/tests/data/turtle/manifest.ttl sites/all/libraries/ARC2/arc/tests/functional/ARC2_ReaderTest.php sites/all/libraries/ARC2/arc/tests/unit/ARC2_ClassTest.php sites/all/libraries/ARC2/arc/tests/unit/ARC2_GraphTest.php sites/all/libraries/ARC2/arc/tests/unit/ARC2_Test.php sites/all/libraries/ARC2/arc/tests/unit/ARC2_getFormatTest.php sites/all/libraries/ARC2/arc/tests/unit/ARC2_getPreferredFormatTest.php sites/all/libraries/ARC2/arc/tests/unit/phpunit.xml sites/all/modules/.DS_Store sites/all/modules/admin_menu/CHANGELOG.txt sites/all/modules/admin_menu/LICENSE.txt sites/all/modules/admin_menu/README.txt sites/all/modules/admin_menu/admin_devel/admin_devel.info sites/all/modules/admin_menu/admin_devel/admin_devel.js sites/all/modules/admin_menu/admin_devel/admin_devel.module sites/all/modules/admin_menu/admin_menu-rtl.css sites/all/modules/admin_menu/admin_menu.admin.js sites/all/modules/admin_menu/admin_menu.api.php sites/all/modules/admin_menu/admin_menu.color.css sites/all/modules/admin_menu/admin_menu.css sites/all/modules/admin_menu/admin_menu.inc sites/all/modules/admin_menu/admin_menu.info sites/all/modules/admin_menu/admin_menu.install sites/all/modules/admin_menu/admin_menu.js sites/all/modules/admin_menu/admin_menu.map.inc sites/all/modules/admin_menu/admin_menu.module sites/all/modules/admin_menu/admin_menu.uid1.css sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.css sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.info sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.install sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.js sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.module sites/all/modules/admin_menu/admin_menu_toolbar/toolbar.png sites/all/modules/admin_menu/images/arrow-rtl.png sites/all/modules/admin_menu/images/arrow.png sites/all/modules/admin_menu/images/bkg-red.png sites/all/modules/admin_menu/images/bkg.png sites/all/modules/admin_menu/images/bkg_tab.png sites/all/modules/admin_menu/images/icon_users.png sites/all/modules/admin_menu/tests/admin_menu.test sites/all/modules/autocomplete_deluxe/LICENSE.txt sites/all/modules/autocomplete_deluxe/README.txt sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.api.php sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.css sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.info sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.js sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.module sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.seven.css sites/all/modules/autocomplete_deluxe/throbber.gif sites/all/modules/autocomplete_deluxe/x.gif sites/all/modules/biblio/LICENSE.txt sites/all/modules/biblio/README.txt sites/all/modules/biblio/biblio.css sites/all/modules/biblio/biblio.info sites/all/modules/biblio/biblio.install sites/all/modules/biblio/biblio.module sites/all/modules/biblio/biblio.tokens.inc sites/all/modules/biblio/changelog.html sites/all/modules/biblio/includes/Name.php sites/all/modules/biblio/includes/Parser.php sites/all/modules/biblio/includes/biblio.admin.inc sites/all/modules/biblio/includes/biblio.contributors.inc sites/all/modules/biblio/includes/biblio.feeds.inc sites/all/modules/biblio/includes/biblio.fields.inc sites/all/modules/biblio/includes/biblio.import.export.inc sites/all/modules/biblio/includes/biblio.keywords.inc sites/all/modules/biblio/includes/biblio.pages.inc sites/all/modules/biblio/includes/biblio.search.inc sites/all/modules/biblio/includes/biblio.util.inc sites/all/modules/biblio/includes/biblio_theme.inc sites/all/modules/biblio/includes/biblio_xml.inc sites/all/modules/biblio/misc/arrow-asc.png sites/all/modules/biblio/misc/arrow-desc.png sites/all/modules/biblio/misc/biblio.field.link.data.csv sites/all/modules/biblio/misc/biblio.field.type.data.csv sites/all/modules/biblio/misc/biblio.highlight.js sites/all/modules/biblio/misc/biblio.nodeformbuttonhide.js sites/all/modules/biblio/misc/minus.png sites/all/modules/biblio/misc/plus-minus.png sites/all/modules/biblio/misc/plus.png sites/all/modules/biblio/modules/CiteProc/CSL.inc sites/all/modules/biblio/modules/CiteProc/biblio_citeproc.admin.inc sites/all/modules/biblio/modules/CiteProc/biblio_citeproc.info sites/all/modules/biblio/modules/CiteProc/biblio_citeproc.install sites/all/modules/biblio/modules/CiteProc/biblio_citeproc.module sites/all/modules/biblio/modules/CiteProc/locale/locales-af-ZA.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-ar-AR.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-bg-BG.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-ca-AD.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-cs-CZ.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-da-DK.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-de-AT.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-de-CH.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-de-DE.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-el-GR.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-en-GB.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-en-US.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-es-ES.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-et-EE.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-eu.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-fa-IR.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-fi-FI.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-fr-FR.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-he-IL.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-hu-HU.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-is-IS.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-it-IT.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-ja-JP.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-km-KH.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-ko-KR.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-mn-MN.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-nb-NO.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-nl-NL.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-nn-NO.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-pl-PL.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-pt-BR.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-pt-PT.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-ro-RO.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-ru-RU.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-sk-SK.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-sl-SI.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-sr-RS.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-sv-SE.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-th-TH.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-tr-TR.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-uk-UA.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-vi-VN.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-zh-CN.xml sites/all/modules/biblio/modules/CiteProc/locale/locales-zh-TW.xml sites/all/modules/biblio/modules/CiteProc/schema/csl-categories.rng sites/all/modules/biblio/modules/CiteProc/schema/csl-terms.rng sites/all/modules/biblio/modules/CiteProc/schema/csl-types.rng sites/all/modules/biblio/modules/CiteProc/schema/csl-variables.rng sites/all/modules/biblio/modules/CiteProc/schema/csl.rng sites/all/modules/biblio/modules/CiteProc/style/american-medical-association.csl sites/all/modules/biblio/modules/CiteProc/style/apa.csl sites/all/modules/biblio/modules/CiteProc/style/apsa.csl sites/all/modules/biblio/modules/CiteProc/style/asa.csl sites/all/modules/biblio/modules/CiteProc/style/chicago-author-date.csl sites/all/modules/biblio/modules/CiteProc/style/chicago-fullnote-bibliography.csl sites/all/modules/biblio/modules/CiteProc/style/chicago-note-bibliography.csl sites/all/modules/biblio/modules/CiteProc/style/council-of-science-editors.csl sites/all/modules/biblio/modules/CiteProc/style/harvard1.csl sites/all/modules/biblio/modules/CiteProc/style/ieee.csl sites/all/modules/biblio/modules/CiteProc/style/mhra.csl sites/all/modules/biblio/modules/CiteProc/style/mla.csl sites/all/modules/biblio/modules/CiteProc/style/national-library-of-medicine-grant.csl sites/all/modules/biblio/modules/CiteProc/style/nature.csl sites/all/modules/biblio/modules/CiteProc/style/vancouver.csl sites/all/modules/biblio/modules/RIS/biblio_ris.info sites/all/modules/biblio/modules/RIS/biblio_ris.install sites/all/modules/biblio/modules/RIS/biblio_ris.module sites/all/modules/biblio/modules/bibtexParse/CHANGELOG sites/all/modules/biblio/modules/bibtexParse/LICENSE sites/all/modules/biblio/modules/bibtexParse/PARSECREATORS.php sites/all/modules/biblio/modules/bibtexParse/PARSEENTRIES.php sites/all/modules/biblio/modules/bibtexParse/PARSEMONTH.php sites/all/modules/biblio/modules/bibtexParse/PARSEPAGE.php sites/all/modules/biblio/modules/bibtexParse/README sites/all/modules/biblio/modules/bibtexParse/bib.bib sites/all/modules/biblio/modules/bibtexParse/biblio_bibtex.info sites/all/modules/biblio/modules/bibtexParse/biblio_bibtex.install sites/all/modules/biblio/modules/bibtexParse/biblio_bibtex.module sites/all/modules/biblio/modules/bibtexParse/transtab_latex_unicode.inc.php sites/all/modules/biblio/modules/bibtexParse/transtab_unicode_bibtex.inc.php sites/all/modules/biblio/modules/crossref/biblio.crossref.client.php sites/all/modules/biblio/modules/crossref/biblio_crossref.info sites/all/modules/biblio/modules/crossref/biblio_crossref.install sites/all/modules/biblio/modules/crossref/biblio_crossref.module sites/all/modules/biblio/modules/endnote/biblio_tagged.info sites/all/modules/biblio/modules/endnote/biblio_tagged.install sites/all/modules/biblio/modules/endnote/biblio_tagged.module sites/all/modules/biblio/modules/endnote/biblio_xml.info sites/all/modules/biblio/modules/endnote/biblio_xml.install sites/all/modules/biblio/modules/endnote/biblio_xml.module sites/all/modules/biblio/modules/endnote/endnote8_export.inc sites/all/modules/biblio/modules/endnote/endnote_xml_parser.inc sites/all/modules/biblio/modules/marcParse/biblio_marc.info sites/all/modules/biblio/modules/marcParse/biblio_marc.install sites/all/modules/biblio/modules/marcParse/biblio_marc.module sites/all/modules/biblio/modules/marcParse/example.mrc sites/all/modules/biblio/modules/marcParse/example.php sites/all/modules/biblio/modules/marcParse/php-marc.php sites/all/modules/biblio/modules/pubmed/EntrezClient.php sites/all/modules/biblio/modules/pubmed/EntrezPubmedArticle.php sites/all/modules/biblio/modules/pubmed/biblio_pm.admin.inc sites/all/modules/biblio/modules/pubmed/biblio_pm.info sites/all/modules/biblio/modules/pubmed/biblio_pm.install sites/all/modules/biblio/modules/pubmed/biblio_pm.module sites/all/modules/biblio/modules/pubmed/biblio_pm.views.inc sites/all/modules/biblio/modules/rtf/biblio_rtf.info sites/all/modules/biblio/modules/rtf/biblio_rtf.install sites/all/modules/biblio/modules/rtf/biblio_rtf.module sites/all/modules/biblio/modules/rtf/rtf_export.inc sites/all/modules/biblio/styles/biblio_style_ama.inc sites/all/modules/biblio/styles/biblio_style_apa.inc sites/all/modules/biblio/styles/biblio_style_chicago.inc sites/all/modules/biblio/styles/biblio_style_classic.inc sites/all/modules/biblio/styles/biblio_style_cse.inc sites/all/modules/biblio/styles/biblio_style_ieee.inc sites/all/modules/biblio/styles/biblio_style_mla.inc sites/all/modules/biblio/styles/biblio_style_vancouver.inc sites/all/modules/biblio/tests/biblio.test sites/all/modules/biblio/tests/contributor.test sites/all/modules/biblio/tests/import.export.test sites/all/modules/biblio/tests/keyword.test sites/all/modules/biblio/tests/test.bib sites/all/modules/biblio/tests/test.ens sites/all/modules/biblio/tests/test.xml sites/all/modules/biblio/todo.txt sites/all/modules/biblio/views/biblio.views.inc sites/all/modules/biblio/views/biblio.views_default.inc sites/all/modules/biblio/views/biblio_handler_argument_many_to_one.inc sites/all/modules/biblio/views/biblio_handler_citation.inc sites/all/modules/biblio/views/biblio_handler_field.inc sites/all/modules/biblio/views/biblio_handler_field_biblio_keyword_data_word.inc sites/all/modules/biblio/views/biblio_handler_field_biblio_keyword_kid.inc sites/all/modules/biblio/views/biblio_handler_field_biblio_type.inc sites/all/modules/biblio/views/biblio_handler_field_contributor.inc sites/all/modules/biblio/views/biblio_handler_field_export_link.inc sites/all/modules/biblio/views/biblio_handler_field_keyword.inc sites/all/modules/biblio/views/biblio_handler_field_markup.inc sites/all/modules/biblio/views/biblio_handler_filter_biblio_contributor_auth_type.inc sites/all/modules/biblio/views/biblio_handler_filter_biblio_keyword_kid.inc sites/all/modules/biblio/views/biblio_handler_filter_biblio_keyword_word.inc sites/all/modules/biblio/views/biblio_handler_filter_biblio_type.inc sites/all/modules/biblio/views/biblio_handler_filter_contributor.inc sites/all/modules/biblio/views/biblio_handler_filter_contributor_lastname.inc sites/all/modules/biblio/views/biblio_handler_filter_contributor_uid.inc sites/all/modules/biblio/views/biblio_handler_sort_contributor_lastname.inc sites/all/modules/biblio_advanced_import/.gitignore sites/all/modules/biblio_advanced_import/CHANGELOG.txt sites/all/modules/biblio_advanced_import/LICENSE.txt sites/all/modules/biblio_advanced_import/README.txt sites/all/modules/biblio_advanced_import/biblio_advanced_import.admin.inc sites/all/modules/biblio_advanced_import/biblio_advanced_import.batch.inc sites/all/modules/biblio_advanced_import/biblio_advanced_import.info sites/all/modules/biblio_advanced_import/biblio_advanced_import.module sites/all/modules/biblio_advanced_import/lib/isbntest.class.php sites/all/modules/biblio_autocomplete/LICENSE.txt sites/all/modules/biblio_autocomplete/biblio_autocomplete.info sites/all/modules/biblio_autocomplete/biblio_autocomplete.module sites/all/modules/biblio_autocomplete/plugins/biblio_ipni/biblio_ipni.info sites/all/modules/biblio_autocomplete/plugins/biblio_ipni/biblio_ipni.module sites/all/modules/biblio_autocomplete/plugins/biblio_self/biblio_self.info sites/all/modules/biblio_autocomplete/plugins/biblio_self/biblio_self.module sites/all/modules/biblio_autocomplete/plugins/biblio_zoobank/biblio_zoobank.info sites/all/modules/biblio_autocomplete/plugins/biblio_zoobank/biblio_zoobank.module sites/all/modules/biblio_scholar/LICENSE.txt sites/all/modules/biblio_scholar/biblio_scholar.info sites/all/modules/biblio_scholar/biblio_scholar.module sites/all/modules/bundle_inherit/LICENSE.txt sites/all/modules/bundle_inherit/README.txt sites/all/modules/bundle_inherit/bundle_inherit.info sites/all/modules/bundle_inherit/bundle_inherit.install sites/all/modules/bundle_inherit/bundle_inherit.module sites/all/modules/bundle_inherit/bundle_inherit.test sites/all/modules/bundle_inherit/bundle_inherit_node/bundle_inherit_node.info sites/all/modules/bundle_inherit/bundle_inherit_node/bundle_inherit_node.module sites/all/modules/bundle_inherit/bundle_inherit_node/bundle_inherit_node.test sites/all/modules/entity/LICENSE.txt sites/all/modules/entity/README.txt sites/all/modules/entity/ctools/content_types/entity_view.inc sites/all/modules/entity/entity.api.php sites/all/modules/entity/entity.features.inc sites/all/modules/entity/entity.i18n.inc sites/all/modules/entity/entity.info sites/all/modules/entity/entity.info.inc sites/all/modules/entity/entity.install sites/all/modules/entity/entity.module sites/all/modules/entity/entity.rules.inc sites/all/modules/entity/entity.test sites/all/modules/entity/entity_token.info sites/all/modules/entity/entity_token.module sites/all/modules/entity/entity_token.tokens.inc sites/all/modules/entity/includes/entity.controller.inc sites/all/modules/entity/includes/entity.inc sites/all/modules/entity/includes/entity.property.inc sites/all/modules/entity/includes/entity.ui.inc sites/all/modules/entity/includes/entity.wrapper.inc sites/all/modules/entity/modules/book.info.inc sites/all/modules/entity/modules/callbacks.inc sites/all/modules/entity/modules/comment.info.inc sites/all/modules/entity/modules/field.info.inc sites/all/modules/entity/modules/locale.info.inc sites/all/modules/entity/modules/node.info.inc sites/all/modules/entity/modules/poll.info.inc sites/all/modules/entity/modules/statistics.info.inc sites/all/modules/entity/modules/system.info.inc sites/all/modules/entity/modules/taxonomy.info.inc sites/all/modules/entity/modules/user.info.inc sites/all/modules/entity/tests/entity_feature.info sites/all/modules/entity/tests/entity_feature.module sites/all/modules/entity/tests/entity_test.info sites/all/modules/entity/tests/entity_test.install sites/all/modules/entity/tests/entity_test.module sites/all/modules/entity/tests/entity_test_i18n.info sites/all/modules/entity/tests/entity_test_i18n.module sites/all/modules/entity/theme/entity.theme.css sites/all/modules/entity/theme/entity.theme.inc sites/all/modules/entity/theme/entity.tpl.php sites/all/modules/entity/views/entity.views.inc sites/all/modules/entity/views/entity_views_example_query.php sites/all/modules/entity/views/handlers/entity_views_field_handler_helper.inc sites/all/modules/entity/views/handlers/entity_views_handler_area_entity.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_boolean.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_date.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_duration.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_entity.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_field.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_numeric.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_options.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_text.inc sites/all/modules/entity/views/handlers/entity_views_handler_field_uri.inc sites/all/modules/entity/views/handlers/entity_views_handler_relationship.inc sites/all/modules/entity/views/handlers/entity_views_handler_relationship_by_bundle.inc sites/all/modules/entity/views/plugins/entity_views_plugin_row_entity_view.inc sites/all/modules/entityreference/LICENSE.txt sites/all/modules/entityreference/README.txt sites/all/modules/entityreference/entityreference.admin.css sites/all/modules/entityreference/entityreference.devel_generate.inc sites/all/modules/entityreference/entityreference.diff.inc sites/all/modules/entityreference/entityreference.feeds.inc sites/all/modules/entityreference/entityreference.info sites/all/modules/entityreference/entityreference.install sites/all/modules/entityreference/entityreference.migrate.inc sites/all/modules/entityreference/entityreference.module sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.module sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceFieldBehaviorExample.class.php sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceInstanceBehaviorExample.class.php sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_field_behavior.inc sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_instance_behavior.inc sites/all/modules/entityreference/plugins/behavior/EntityReferenceBehavior_TaxonomyIndex.class.php sites/all/modules/entityreference/plugins/behavior/EntityReferenceBehavior_ViewsFilterSelect.class.php sites/all/modules/entityreference/plugins/behavior/abstract.inc sites/all/modules/entityreference/plugins/behavior/taxonomy-index.inc sites/all/modules/entityreference/plugins/behavior/views-select-list.inc sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php sites/all/modules/entityreference/plugins/selection/abstract.inc sites/all/modules/entityreference/plugins/selection/base.inc sites/all/modules/entityreference/plugins/selection/views.inc sites/all/modules/entityreference/tests/entityreference.admin.test sites/all/modules/entityreference/tests/entityreference.handlers.test sites/all/modules/entityreference/tests/entityreference.taxonomy.test sites/all/modules/entityreference/views/entityreference.views.inc sites/all/modules/entityreference/views/entityreference_plugin_display.inc sites/all/modules/entityreference/views/entityreference_plugin_row_fields.inc sites/all/modules/entityreference/views/entityreference_plugin_style.inc sites/all/modules/entityreference_prepopulate/LICENSE.txt sites/all/modules/entityreference_prepopulate/README.txt sites/all/modules/entityreference_prepopulate/entityreference_prepopulate.info sites/all/modules/entityreference_prepopulate/entityreference_prepopulate.module sites/all/modules/entityreference_prepopulate/entityreference_prepopulate.test sites/all/modules/entityreference_prepopulate/plugins/behavior/EntityReferencePrepopulateInstanceBehavior.class.php sites/all/modules/entityreference_prepopulate/plugins/behavior/prepopulate.inc sites/all/modules/entityreference_prepopulate/plugins/content_types/node_prepopulate.inc sites/all/modules/entityreference_prepopulate/tests/entityreference_prepopulate_test.info sites/all/modules/entityreference_prepopulate/tests/entityreference_prepopulate_test.module sites/all/modules/features/API.txt sites/all/modules/features/CHANGELOG.txt sites/all/modules/features/LICENSE.txt sites/all/modules/features/README.txt sites/all/modules/features/features.admin.inc sites/all/modules/features/features.api.php sites/all/modules/features/features.css sites/all/modules/features/features.drush.inc sites/all/modules/features/features.export.inc sites/all/modules/features/features.info sites/all/modules/features/features.install sites/all/modules/features/features.js sites/all/modules/features/features.module sites/all/modules/features/includes/features.block.inc sites/all/modules/features/includes/features.context.inc sites/all/modules/features/includes/features.ctools.inc sites/all/modules/features/includes/features.features.inc sites/all/modules/features/includes/features.field.inc sites/all/modules/features/includes/features.filter.inc sites/all/modules/features/includes/features.image.inc sites/all/modules/features/includes/features.locale.inc sites/all/modules/features/includes/features.menu.inc sites/all/modules/features/includes/features.node.inc sites/all/modules/features/includes/features.taxonomy.inc sites/all/modules/features/includes/features.user.inc sites/all/modules/features/tests/features.test sites/all/modules/features/tests/features_test/features_test.features.field_base.inc sites/all/modules/features/tests/features_test/features_test.features.field_instance.inc sites/all/modules/features/tests/features_test/features_test.features.filter.inc sites/all/modules/features/tests/features_test/features_test.features.inc sites/all/modules/features/tests/features_test/features_test.features.taxonomy.inc sites/all/modules/features/tests/features_test/features_test.features.user_permission.inc sites/all/modules/features/tests/features_test/features_test.info sites/all/modules/features/tests/features_test/features_test.module sites/all/modules/features/tests/features_test/features_test.views_default.inc sites/all/modules/features/theme/features-admin-components.tpl.php sites/all/modules/features/theme/theme.inc sites/all/modules/field_collection/LICENSE.txt sites/all/modules/field_collection/README.txt sites/all/modules/field_collection/field-collection-item.tpl.php sites/all/modules/field_collection/field_collection.admin.inc sites/all/modules/field_collection/field_collection.api.php sites/all/modules/field_collection/field_collection.info sites/all/modules/field_collection/field_collection.info.inc sites/all/modules/field_collection/field_collection.install sites/all/modules/field_collection/field_collection.module sites/all/modules/field_collection/field_collection.pages.inc sites/all/modules/field_collection/field_collection.test sites/all/modules/field_collection/field_collection.theme.css sites/all/modules/field_collection/views/field_collection.views.inc sites/all/modules/field_collection/views/field_collection_handler_relationship.inc sites/all/modules/field_group/CHANGELOG.txt sites/all/modules/field_group/LICENSE.txt sites/all/modules/field_group/README.txt sites/all/modules/field_group/field_group-rtl.css sites/all/modules/field_group/field_group.api.php sites/all/modules/field_group/field_group.css sites/all/modules/field_group/field_group.features.inc sites/all/modules/field_group/field_group.field_ui.css sites/all/modules/field_group/field_group.field_ui.inc sites/all/modules/field_group/field_group.field_ui.js sites/all/modules/field_group/field_group.info sites/all/modules/field_group/field_group.install sites/all/modules/field_group/field_group.js sites/all/modules/field_group/field_group.module sites/all/modules/field_group/field_group.test sites/all/modules/field_group/horizontal-tabs/horizontal-tabs-rtl.css sites/all/modules/field_group/horizontal-tabs/horizontal-tabs.css sites/all/modules/field_group/horizontal-tabs/horizontal-tabs.js sites/all/modules/field_group/multipage/multipage-rtl.css sites/all/modules/field_group/multipage/multipage.css sites/all/modules/field_group/multipage/multipage.js sites/all/modules/github/LICENSE.txt sites/all/modules/github/README.txt sites/all/modules/github/github.admin.inc sites/all/modules/github/github.info sites/all/modules/github/github.module sites/all/modules/github/github_ribbon.tpl.php sites/all/modules/github/ribbons/forkme_left_darkblue_121621.png sites/all/modules/github/ribbons/forkme_left_gray_6d6d6d.png sites/all/modules/github/ribbons/forkme_left_green_007200.png sites/all/modules/github/ribbons/forkme_left_orange_ff7600.png sites/all/modules/github/ribbons/forkme_left_red_aa0000.png sites/all/modules/github/ribbons/forkme_left_white_ffffff.png sites/all/modules/github/ribbons/forkme_right_darkblue_121621.png sites/all/modules/github/ribbons/forkme_right_gray_6d6d6d.png sites/all/modules/github/ribbons/forkme_right_green_007200.png sites/all/modules/github/ribbons/forkme_right_orange_ff7600.png sites/all/modules/github/ribbons/forkme_right_red_aa0000.png sites/all/modules/github/ribbons/forkme_right_white_ffffff.png sites/all/modules/link/LICENSE.txt sites/all/modules/link/link.css sites/all/modules/link/link.devel_generate.inc sites/all/modules/link/link.diff.inc sites/all/modules/link/link.info sites/all/modules/link/link.install sites/all/modules/link/link.migrate.inc sites/all/modules/link/link.module sites/all/modules/link/tests/link.attribute.test sites/all/modules/link/tests/link.crud.test sites/all/modules/link/tests/link.crud_browser.test sites/all/modules/link/tests/link.test sites/all/modules/link/tests/link.token.test sites/all/modules/link/tests/link.validate.test sites/all/modules/link/views/link.views.inc sites/all/modules/link/views/link_views_handler_argument_target.inc sites/all/modules/link/views/link_views_handler_filter_protocol.inc sites/all/modules/pathologic/LICENSE.txt sites/all/modules/pathologic/README.txt sites/all/modules/pathologic/pathologic.api.php sites/all/modules/pathologic/pathologic.info sites/all/modules/pathologic/pathologic.install sites/all/modules/pathologic/pathologic.module sites/all/modules/pathologic/pathologic.test sites/all/modules/pdf_to_imagefield/LICENSE.txt sites/all/modules/pdf_to_imagefield/README.txt sites/all/modules/pdf_to_imagefield/pdf_document/pdf_document.features.field.inc sites/all/modules/pdf_to_imagefield/pdf_document/pdf_document.features.inc sites/all/modules/pdf_to_imagefield/pdf_document/pdf_document.info sites/all/modules/pdf_to_imagefield/pdf_document/pdf_document.module sites/all/modules/pdf_to_imagefield/pdf_to_image.info sites/all/modules/pdf_to_imagefield/pdf_to_image.install sites/all/modules/pdf_to_imagefield/pdf_to_image.module sites/all/modules/pdf_to_imagefield/pdf_to_image_demo.make.stub sites/all/modules/prepopulate/CHANGELOG.txt sites/all/modules/prepopulate/INSTALL.txt sites/all/modules/prepopulate/LICENSE.txt sites/all/modules/prepopulate/README.txt sites/all/modules/prepopulate/USAGE.txt sites/all/modules/prepopulate/prepopulate.info sites/all/modules/prepopulate/prepopulate.install sites/all/modules/prepopulate/prepopulate.module sites/all/modules/rdf_example/rdf_example.info sites/all/modules/rdf_example/rdf_example.install sites/all/modules/rdf_example/rdf_example.module sites/all/modules/rdfx/.DS_Store sites/all/modules/rdfx/LICENSE.txt sites/all/modules/rdfx/README.txt sites/all/modules/rdfx/drush/rdfx.drush.inc sites/all/modules/rdfx/evoc/evoc.info sites/all/modules/rdfx/evoc/evoc.install sites/all/modules/rdfx/evoc/evoc.load_vocab.inc sites/all/modules/rdfx/evoc/evoc.module sites/all/modules/rdfx/evoc/evoc.pages.inc sites/all/modules/rdfx/evoc/evoc.test sites/all/modules/rdfx/evoc/tests/evoc_test.info sites/all/modules/rdfx/evoc/tests/evoc_test.module sites/all/modules/rdfx/rdfui/css/rdfui.css sites/all/modules/rdfx/rdfui/rdfui.info sites/all/modules/rdfx/rdfui/rdfui.js sites/all/modules/rdfx/rdfui/rdfui.module sites/all/modules/rdfx/rdfui/rdfui.test sites/all/modules/rdfx/rdfx.admin.inc sites/all/modules/rdfx/rdfx.api.php sites/all/modules/rdfx/rdfx.features.inc sites/all/modules/rdfx/rdfx.import.inc sites/all/modules/rdfx/rdfx.inc sites/all/modules/rdfx/rdfx.info sites/all/modules/rdfx/rdfx.install sites/all/modules/rdfx/rdfx.module sites/all/modules/rdfx/rdfx.query.inc sites/all/modules/rdfx/rdfx.restws.formats.inc sites/all/modules/rdfx/rdfx.terms.inc sites/all/modules/rdfx/rdfx.test sites/all/modules/references/CHANGELOG.txt sites/all/modules/references/LICENSE.txt sites/all/modules/references/README.txt sites/all/modules/references/node_reference/node_reference.devel_generate.inc sites/all/modules/references/node_reference/node_reference.info sites/all/modules/references/node_reference/node_reference.install sites/all/modules/references/node_reference/node_reference.module sites/all/modules/references/node_reference/node_reference.test sites/all/modules/references/references.feeds.inc sites/all/modules/references/references.info sites/all/modules/references/references.module sites/all/modules/references/user_reference/user_reference.devel_generate.inc sites/all/modules/references/user_reference/user_reference.info sites/all/modules/references/user_reference/user_reference.install sites/all/modules/references/user_reference/user_reference.module sites/all/modules/references/user_reference/user_reference.test sites/all/modules/references/views/references_handler_argument.inc sites/all/modules/references/views/references_handler_relationship.inc sites/all/modules/references/views/references_plugin_display.inc sites/all/modules/references/views/references_plugin_row_fields.inc sites/all/modules/references/views/references_plugin_style.inc sites/all/modules/relation/CONCEPTS.txt sites/all/modules/relation/LICENSE.txt sites/all/modules/relation/README.txt sites/all/modules/relation/UNINSTALL.txt sites/all/modules/relation/relation.api.php sites/all/modules/relation/relation.ctools.inc sites/all/modules/relation/relation.database.inc sites/all/modules/relation/relation.drush.inc sites/all/modules/relation/relation.info sites/all/modules/relation/relation.install sites/all/modules/relation/relation.module sites/all/modules/relation/relation.rules.inc sites/all/modules/relation/relation.tokens.inc sites/all/modules/relation/relation_dummy_field/relation_dummy_field.info sites/all/modules/relation/relation_dummy_field/relation_dummy_field.module sites/all/modules/relation/relation_dummy_field/tests/relation_dummy_field.test sites/all/modules/relation/relation_endpoint.info sites/all/modules/relation/relation_endpoint.install sites/all/modules/relation/relation_endpoint.module sites/all/modules/relation/relation_entity_collector/relation_entity_collector.css sites/all/modules/relation/relation_entity_collector/relation_entity_collector.info sites/all/modules/relation/relation_entity_collector/relation_entity_collector.module sites/all/modules/relation/relation_entity_collector/tests/relation_entity_collector.test sites/all/modules/relation/relation_migrate/relation_migrate.destination.inc sites/all/modules/relation/relation_migrate/relation_migrate.info sites/all/modules/relation/relation_migrate/relation_migrate.install sites/all/modules/relation/relation_migrate/relation_migrate.migration.inc sites/all/modules/relation/relation_migrate/relation_migrate.module sites/all/modules/relation/relation_migrate/relation_migrate.modules.inc sites/all/modules/relation/relation_migrate/relation_migrate.source.inc sites/all/modules/relation/relation_migrate/tests/relation.migrate.test sites/all/modules/relation/relation_migrate/tests/relation_migrate_test.info sites/all/modules/relation/relation_migrate/tests/relation_migrate_test.module sites/all/modules/relation/relation_ui.css sites/all/modules/relation/relation_ui.info sites/all/modules/relation/relation_ui.module sites/all/modules/relation/tests/relation.rules.test sites/all/modules/relation/tests/relation.test sites/all/modules/relation/tests/relation.views.test sites/all/modules/relation/tests/relation_rules_test.info sites/all/modules/relation/tests/relation_rules_test.module sites/all/modules/relation/tests/relation_ui.test sites/all/modules/relation/views/relation.views.inc sites/all/modules/relation/views/relation.views_default.inc sites/all/modules/relation/views/relation_handler_relationship.inc sites/all/modules/relation/views/views_handler_field_relation_link.inc sites/all/modules/relation/views/views_handler_field_relation_link_delete.inc sites/all/modules/relation/views/views_handler_field_relation_link_edit.inc sites/all/modules/restws/LICENSE.txt sites/all/modules/restws/README.txt sites/all/modules/restws/example_exports/README.txt sites/all/modules/restws/example_exports/node.1.json sites/all/modules/restws/example_exports/node.1.xml sites/all/modules/restws/example_exports/node.json sites/all/modules/restws/example_exports/node.xml sites/all/modules/restws/example_exports/user.1.json sites/all/modules/restws/example_exports/user.1.xml sites/all/modules/restws/restws.api.php sites/all/modules/restws/restws.entity.inc sites/all/modules/restws/restws.formats.inc sites/all/modules/restws/restws.info sites/all/modules/restws/restws.install sites/all/modules/restws/restws.module sites/all/modules/restws/restws.test sites/all/modules/restws/restws_basic_auth/README.txt sites/all/modules/restws/restws_basic_auth/restws_basic_auth.info sites/all/modules/restws/restws_basic_auth/restws_basic_auth.install sites/all/modules/restws/restws_basic_auth/restws_basic_auth.module sites/all/modules/restws/tests/restws_test.info sites/all/modules/restws/tests/restws_test.module sites/all/modules/schemaorg/LICENSE.txt sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.features.field.inc sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.features.inc sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.info sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.install sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.module sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.strongarm.inc sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.views_default.inc sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.features.field.inc sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.features.inc sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.info sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.install sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.module sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.strongarm.inc sites/all/modules/schemaorg/example/schemaorg_recipe/schemaorg_recipe.features.field.inc sites/all/modules/schemaorg/example/schemaorg_recipe/schemaorg_recipe.features.inc sites/all/modules/schemaorg/example/schemaorg_recipe/schemaorg_recipe.info sites/all/modules/schemaorg/example/schemaorg_recipe/schemaorg_recipe.module sites/all/modules/schemaorg/schemaorg.drush.inc sites/all/modules/schemaorg/schemaorg.features.inc sites/all/modules/schemaorg/schemaorg.info sites/all/modules/schemaorg/schemaorg.install sites/all/modules/schemaorg/schemaorg.module sites/all/modules/schemaorg/schemaorg.test sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_flat_0_aaaaaa_40x100.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_flat_75_ffffff_40x100.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_55_fbf9ee_1x400.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_65_ffffff_1x400.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_75_dadada_1x400.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_75_e6e6e6_1x400.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_95_fef1ec_1x400.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_222222_256x240.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_2e83ff_256x240.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_454545_256x240.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_888888_256x240.png sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_cd0a0a_256x240.png sites/all/modules/schemaorg/schemaorg_ui/css/schemaorg_ui.jquery.ui.theme.css sites/all/modules/schemaorg/schemaorg_ui/js/schemaorg_ui.js sites/all/modules/schemaorg/schemaorg_ui/js/schemaorg_ui.terms.json sites/all/modules/schemaorg/schemaorg_ui/schemaorg_ui.info sites/all/modules/schemaorg/schemaorg_ui/schemaorg_ui.module sites/all/modules/search_autocomplete/LICENSE.txt sites/all/modules/search_autocomplete/README.txt sites/all/modules/search_autocomplete/css/MAKE YOUR THEME.css_ sites/all/modules/search_autocomplete/css/classic.css sites/all/modules/search_autocomplete/css/full paper brown.css sites/all/modules/search_autocomplete/css/images/help.png sites/all/modules/search_autocomplete/css/images/throbber.gif sites/all/modules/search_autocomplete/css/images/ui-bg_fine-grain_10_eceadf_60x60.png sites/all/modules/search_autocomplete/css/images/ui-bg_fine-grain_65_654b24_60x60.png sites/all/modules/search_autocomplete/css/images/ui-bg_glass_100_fdf5ce_1x400.png sites/all/modules/search_autocomplete/css/images/ui-bg_glass_55_1c1c1c_1x400.png sites/all/modules/search_autocomplete/css/images/ui-bg_glass_75_79c9ec_1x400.png sites/all/modules/search_autocomplete/css/images/ui-bg_highlight-hard_100_f9f9f9_1x100.png sites/all/modules/search_autocomplete/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png sites/all/modules/search_autocomplete/css/images/ui-bg_inset-hard_100_fcfdfd_1x100.png sites/all/modules/search_autocomplete/css/nice black.css sites/all/modules/search_autocomplete/css/nice blue.css sites/all/modules/search_autocomplete/css/nice green.css sites/all/modules/search_autocomplete/css/nice orange.css sites/all/modules/search_autocomplete/js/jquery.autocomplete.js sites/all/modules/search_autocomplete/search_autocomplete.admin.inc sites/all/modules/search_autocomplete/search_autocomplete.form.add.inc sites/all/modules/search_autocomplete/search_autocomplete.form.configure.inc sites/all/modules/search_autocomplete/search_autocomplete.form.delete.inc sites/all/modules/search_autocomplete/search_autocomplete.form.treelist.inc sites/all/modules/search_autocomplete/search_autocomplete.info sites/all/modules/search_autocomplete/search_autocomplete.install sites/all/modules/search_autocomplete/search_autocomplete.module sites/all/modules/search_autocomplete/search_autocomplete.view_autocomplete.inc sites/all/modules/search_autocomplete/views/plugins/views_plugin_style_autocomplete.inc sites/all/modules/search_autocomplete/views/search_autocomplete.views.inc sites/all/modules/search_autocomplete/views/theme/views-search-autocomplete-style.tpl.php sites/all/modules/search_autocomplete/views/theme/views_search_autocomplete_style.theme.inc sites/all/modules/semanticviews/LICENSE.txt sites/all/modules/semanticviews/README.txt sites/all/modules/semanticviews/help/output-style-options.png sites/all/modules/semanticviews/help/row-style-options.png sites/all/modules/semanticviews/help/semanticviews-help.html sites/all/modules/semanticviews/help/semanticviews-tutorial.html sites/all/modules/semanticviews/help/semanticviews.help.ini sites/all/modules/semanticviews/help/style-row-fields.html sites/all/modules/semanticviews/help/style-unformatted.html sites/all/modules/semanticviews/semanticviews-view-fields.tpl.php sites/all/modules/semanticviews/semanticviews-view-unformatted.tpl.php sites/all/modules/semanticviews/semanticviews.info sites/all/modules/semanticviews/semanticviews.module sites/all/modules/semanticviews/semanticviews.theme.inc sites/all/modules/semanticviews/semanticviews.views.inc sites/all/modules/semanticviews/semanticviews.views_default.inc sites/all/modules/semanticviews/semanticviews_plugin_row_fields.inc sites/all/modules/semanticviews/semanticviews_plugin_style_default.inc sites/all/modules/sparql/CHANGELOG.txt sites/all/modules/sparql/LICENSE.txt sites/all/modules/sparql/README.txt sites/all/modules/sparql/sparql.info sites/all/modules/sparql/sparql.install sites/all/modules/sparql/sparql.module sites/all/modules/sparql/sparql.test sites/all/modules/sparql/sparql_endpoint/sparql_endpoint.info sites/all/modules/sparql/sparql_endpoint/sparql_endpoint.install sites/all/modules/sparql/sparql_endpoint/sparql_endpoint.module sites/all/modules/sparql/sparql_registry/sparql_registry.info sites/all/modules/sparql/sparql_registry/sparql_registry.install sites/all/modules/sparql/sparql_registry/sparql_registry.module sites/all/modules/sparql_views/CHANGELOG.txt sites/all/modules/sparql_views/LICENSE.txt sites/all/modules/sparql_views/README.txt sites/all/modules/sparql_views/handlers/sparql_views_handler_argument.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_field.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_field_rdftype.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_field_subject.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_filter.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_filter_field_value.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_filter_language.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_filter_rdftype.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_relationship.inc sites/all/modules/sparql_views/handlers/sparql_views_handler_sort.inc sites/all/modules/sparql_views/includes/sparql_views.controller.inc sites/all/modules/sparql_views/plugins/sparql_views_plugin_argument_default_field.inc sites/all/modules/sparql_views/plugins/sparql_views_plugin_query_sparql.inc sites/all/modules/sparql_views/sparql_views.admin.inc sites/all/modules/sparql_views/sparql_views.info sites/all/modules/sparql_views/sparql_views.install sites/all/modules/sparql_views/sparql_views.module sites/all/modules/sparql_views/sparql_views.views.inc sites/all/modules/sparql_views/sparql_views_related_resource/sparql_views_related_resource.info sites/all/modules/sparql_views/sparql_views_related_resource/sparql_views_related_resource.module sites/all/modules/sparql_views/tests/sparql_views.test sites/all/modules/sparql_views/tests/sparql_views_basic.test sites/all/modules/sparql_views/tests/sparql_views_formatter.test sites/all/modules/sparql_views/tests/sparql_views_query.test sites/all/modules/sparql_views/tests/sparql_views_test.info sites/all/modules/sparql_views/tests/sparql_views_test.install sites/all/modules/sparql_views/tests/sparql_views_test.module sites/all/modules/sparql_views/tests/sparql_views_test.rdf sites/all/modules/sparql_views/tests/sparql_views_test.views_default.inc sites/all/modules/url/LICENSE.txt sites/all/modules/url/url.field.css sites/all/modules/url/url.info sites/all/modules/url/url.install sites/all/modules/url/url.module sites/all/modules/url/url.test
diffstat 910 files changed, 193120 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/DEVELOPER.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,26 @@
+---------------------------------------------------
+Some notes for developers working on the rules code
+---------------------------------------------------
+
+Terminology & Overview
+-----------------------
+  * Rules plugins extend the "rules language". Thus conditions and actions are
+    implemented with a plugin, but also loops or ORs are plugins. Each plugin is
+    declared to be used in the condition or the action part - specified by the
+    interface.
+  * The action and condition plugin are a so called "AbstractPlugin" which means
+    they have to be implemented by modules to be actually usable. In fact the
+    callbacks provided by the action or condition implementation are
+    incorporated in the plugin object using faces. That way an action or
+    condition element behaves exactly like any other plugin instance. 
+  * Any rule element is an instance of a RulesPlugin. 
+  * A rules configuration consists of multiple rule elements while one is the
+    root element, which may be a 'rule' but also any other plugin.
+  * Each rules configuration may be persistently saved to the db using the
+    entity CRUD API. Using the API on contained rule elements is working too and
+    results in the whole configuration being updated.
+  * Rules provides per plugin UI components, what makes the UI parts re-usable
+    outside of the rule admin module too. In fact the rules admin module is
+    pretty small, as it just relies on the provided UI of the components.
+  * The UI is incorporated using the faces object extension mechanism, see
+    rules_rules_plugin_info() for an overview of the used UI extenders.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,91 @@
+
+--------------------------------------------------------------------------------
+                                 Rules
+--------------------------------------------------------------------------------
+
+Maintainers:
+ * Wolfgang Ziegler (fago), nuppla@zites.net
+
+The Rules module allows site administrators to define conditionally executed
+actions based on occurring events (ECA-rules).
+
+Project homepage: http://drupal.org/project/rules
+
+
+Installation
+------------
+
+*Before* starting, make sure that you have read at least the introduction - so
+you know at least the basic concepts. You can find it here:
+
+                      http://drupal.org/node/298480
+
+ * Rules depends on the Entity API module, download and install it from
+   http://drupal.org/project/entity
+ * Copy the whole rules directory to your modules directory
+   (e.g. DRUPAL_ROOT/sites/all/modules) and activate the Rules and Rules UI
+   modules.
+ * The administrative user interface can be found at admin/config/workflow/rules
+
+
+Documentation
+-------------
+* Check out the general docs at http://drupal.org/node/298476
+* Check out the developer targeted docs at http://drupal.org/node/878718
+
+
+Rules Scheduler
+---------------
+
+ * If you enable the Rules scheduler module, you get new actions that allow you
+   to schedule the execution of Rules components.
+ * Make sure that you have configured cron for your drupal installation as cron
+   is used for scheduling the Rules components. For help see
+   http://drupal.org/cron
+ * If the Views module (http://drupal.org/project/views) is installed, the module
+   displays the list of scheduled tasks in the UI.
+
+
+Upgrade from Rules 6.x-1.x to Rules 7.x-2.x
+--------------------------------------------
+
+ * In order to upgrade Rules from 6.x-1.x to 7.x-2.x just run "update.php". This
+   is going to make sure Rules 2.x is properly installed, but it will leave your
+   Rules 1.x configurations untouched. Thus, your rules won't be upgraded yet.
+ * To convert your Rules 1.x configurations to Rules 2.x go to
+   'admin/config/workflow/rules/upgrade'.
+     * At this page, you may choose the Rules 1.x rules and rule sets to upgrade
+       and whether the converted configurations should be immediately saved to
+       your database or whether the configuration export should be generated.
+     * Note that for importing an export the export needs to pass the
+       configuration integrity check, what might be troublesome if the
+       conversion was not 100% successful. In that case, try choosing the
+       immediate saving method and correct the configuration after conversion.  
+     * A rule configuration might require multiple modules to be in place and
+       upgraded to work properly. E.g. if you used an action provided
+       by a third party module, make sure the module is in place and upgraded
+       before you convert the rule.
+     * If all required modules are installed and have been upgraded but the rule
+       conversion still fails, the cause might be that a module has not yet
+       upgraded its Rules integration or does not implement the Rules conversion
+       functionality. In that case, file an issue for the module that provided
+       the action or condition causing the conversion to fail.
+     * Note that any rule configurations containing token replacements or PHP
+       input evaluations might need some manual corrections in order to stay
+       working. This is, as some used token replacements might not be available
+       in Drupal 7 any more and the PHP code might need to be updated in order
+       to be compatible with Drupal 7.
+     * Once the upgrade was successful, you may delete the left over Rules 1.x
+       configurations by going to 'admin/config/workflow/rules/upgrade/clear'.
+  * The Rules Scheduler module also comes with an upgrade routine that is
+    invoked as usual via "update.php". Its actions can be upgraded via the usual
+    Rules upgrade tool, see above.
+    However, there is currently no support for upgrading already scheduled
+    tasks. That means, all previously on Drupal 6 scheduled tasks won't apply
+    for Drupal 7. The Drupal 6 tasks are preserved in the database as long as
+    you do not clear your Rules 1.x configuration though.
+  * The Rules Forms module has not been updated to Drupal 7 and there are no
+    plans to do so, as unfortuntely the module's design does not allow for
+    automatic configuration updates.
+    Thus, a possible future Rules 2.x Forms module is likely to work
+    different, e.g. by working only for entity forms on the field level.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/includes/faces.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,311 @@
+<?php
+
+/**
+ * @file Extendable Object Faces API. Provided by the faces module.
+ */
+
+if (!interface_exists('FacesExtenderInterface', FALSE)) {
+
+  /**
+   * Interface for extenders.
+   */
+  interface FacesExtenderInterface {
+
+    /**
+     * Constructs an instance of the extender.
+     */
+    function __construct(FacesExtendable $object);
+
+    /**
+     * Returns the extended object.
+     */
+    public function getExtendable();
+  }
+
+  /**
+   * The Exception thrown by the FacesExtendable.
+   */
+  class FacesExtendableException extends ErrorException {}
+
+}
+
+if (!class_exists('FacesExtender', FALSE)) {
+  /**
+   * A common base class for FacesExtenders. Extenders may access protected
+   * methods and properties of the extendable using the property() and call()
+   * methods.
+   */
+  abstract class FacesExtender implements FacesExtenderInterface {
+
+    /**
+     * @var FacesExtendable
+     */
+    protected $object;
+
+
+    function __construct(FacesExtendable $object) {
+      $this->object = $object;
+    }
+
+    /**
+     * Returns the extended object.
+     */
+    public function getExtendable() {
+      return $this->object;
+    }
+
+    /**
+     * Makes protected properties of the extendable accessible.
+     */
+    protected function &property($name) {
+      $var =& $this->object->property($name);
+      return $var;
+    }
+
+    /**
+     * Invokes any method on the extended object. May be used to invoke
+     * protected methods.
+     *
+     * @param $name
+     *   The method name.
+     * @param $arguments
+     *   An array of arguments to pass to the method.
+     */
+    protected function call($name, array $args = array()) {
+      return $this->object->call($name, $args);
+    }
+  }
+}
+
+
+if (!class_exists('FacesExtendable', FALSE)) {
+
+  /**
+   * An extendable base class.
+   */
+  abstract class FacesExtendable {
+
+    protected $facesMethods = array();
+    protected $faces = array();
+    protected $facesIncludes = array();
+    protected $facesClassInstances = array();
+    static protected $facesIncluded = array();
+
+    /**
+     * Wraps calls to module_load_include() to prevent multiple inclusions.
+     *
+     * @see module_load_include()
+     */
+    protected static function load_include($args) {
+      $args += array('type' => 'inc', 'module' => '', 'name' => NULL);
+      $key = implode(':', $args);
+      if (!isset(self::$facesIncluded[$key])) {
+        self::$facesIncluded[$key] = TRUE;
+        module_load_include($args['type'], $args['module'], $args['name']);
+      }
+    }
+
+    /**
+     * Magic method: Invoke the dynamically implemented methods.
+     */
+    function __call($name, $arguments = array()) {
+      if (isset($this->facesMethods[$name])) {
+        $method = $this->facesMethods[$name];
+        // Include code, if necessary.
+        if (isset($this->facesIncludes[$name])) {
+          self::load_include($this->facesIncludes[$name]);
+          $this->facesIncludes[$name] = NULL;
+        }
+        if (isset($method[0])) {
+          // We always pass the object reference and the name of the method.
+          $arguments[] = $this;
+          $arguments[] = $name;
+          return call_user_func_array($method[0], $arguments);
+        }
+        // Call the method on the extender object, but don't use extender()
+        // for performance reasons.
+        if (!isset($this->facesClassInstances[$method[1]])) {
+          $this->facesClassInstances[$method[1]] = new $method[1]($this);
+        }
+        return call_user_func_array(array($this->facesClassInstances[$method[1]], $name), $arguments);
+      }
+      $class = check_plain(get_class($this));
+      throw new FacesExtendableException("There is no method $name for this instance of the class $class.");
+    }
+
+    /**
+     * Returns the extender object for the given class. May be used to
+     * explicitly invoke a specific extender, e.g. a function overriding a
+     * method may use that to explicitly invoke the original extender.
+     */
+    public function extender($class) {
+      if (!isset($this->facesClassInstances[$class])) {
+        $this->facesClassInstances[$class] = new $class($this);
+      }
+      return $this->facesClassInstances[$class];
+    }
+
+    /**
+     * Returns whether the object can face as the given interface, thus it
+     * returns TRUE if this oject has been extended by an appropriate
+     * implementation.
+     *
+     * @param $interface
+     *   Optional. A interface to test for. If it's omitted, all interfaces that
+     *   the object can be faced as are returned.
+     * @return
+     *   Whether the object can face as the interface or an array of interface
+     *   names.
+     */
+    public function facesAs($interface = NULL) {
+      if (!isset($interface)) {
+        return array_values($this->faces);
+      }
+      return in_array($interface, $this->faces) || $this instanceof $interface;
+    }
+
+    /**
+     * Extend the object by a class to implement the given interfaces.
+     *
+     * @param $interface
+     *   The interface name or an array of interface names.
+     * @param $class
+     *   The extender class, which has to implement the FacesExtenderInterface.
+     * @param $include
+     *   An optional array describing the file to include before invoking the
+     *   class. The array entries known are 'type', 'module', and 'name'
+     *   matching the parameters of module_load_include(). Only 'module' is
+     *   required as 'type' defaults to 'inc' and 'name' to NULL.
+     */
+    public function extendByClass($interface, $className, array $includes = array()) {
+      $parents = class_implements($className);
+      if (!in_array('FacesExtenderInterface', $parents)) {
+        throw new FacesExtendableException("The class " . check_plain($className) . " doesn't implement the FacesExtenderInterface.");
+      }
+      $interfaces = is_array($interface) ? $interface : array($interface);
+
+      foreach ($interfaces as $interface) {
+        if (!in_array($interface, $parents)) {
+          throw new FacesExtendableException("The class " . check_plain($className) . " doesn't implement the interface " . check_plain($interface) . ".");
+        }
+        $this->faces[$interface] = $interface;
+        $this->faces += class_implements($interface);
+        $face_methods = get_class_methods($interface);
+        $this->addIncludes($face_methods, $includes);
+        foreach ($face_methods as $method) {
+          $this->facesMethods[$method] = array(1 => $className);
+        }
+      }
+    }
+
+    /**
+     * Extend the object by the given functions to implement the given
+     * interface. There has to be an implementation function for each method of
+     * the interface.
+     *
+     * @param $interface
+     *   The interface name or FALSE to extend the object without a given
+     *   interface.
+     * @param $methods
+     *   An array, where the keys are methods of the given interface and the
+     *   values the callback functions to use.
+     * @param $includes
+     *   An optional array to describe files to include before invoking the
+     *   callbacks. You may pass a single array describing one include for all
+     *   callbacks or an array of arrays, keyed by the method names. Look at the
+     *   extendByClass() $include parameter for more details about how to
+     *   describe a single file.
+     */
+    public function extend($interface, array $callbacks = array(), array $includes = array()) {
+      $face_methods = $interface ? get_class_methods($interface) : array_keys($callbacks);
+      if ($interface) {
+        if (array_diff($face_methods, array_keys($callbacks))) {
+          throw new FacesExtendableException("Missing methods for implementing the interface " . check_plain($interface) . ".");
+        }
+        $this->faces[$interface] = $interface;
+        $this->faces += class_implements($interface);
+      }
+      $this->addIncludes($face_methods, $includes);
+      foreach ($face_methods as $method) {
+        $this->facesMethods[$method] = array(0 => $callbacks[$method]);
+      }
+    }
+
+    /**
+     * Override the implementation of an extended method.
+     *
+     * @param $methods
+     *   An array of methods of the interface, that should be overriden, where
+     *   the keys are methods to override and the values the callback functions
+     *   to use.
+     * @param $includes
+     *   An optional array to describe files to include before invoking the
+     *   callbacks. You may pass a single array describing one include for all
+     *   callbacks or an array of arrays, keyed by the method names. Look at the
+     *   extendByClass() $include parameter for more details about how to
+     *   describe a single file.
+     */
+    public function override(array $callbacks = array(), array $includes = array()) {
+      if (array_diff_key($callbacks, $this->facesMethods)) {
+        throw new FacesExtendableException("A not implemented method is to be overridden.");
+      }
+      $this->addIncludes(array_keys($callbacks), $includes);
+      foreach ($callbacks as $method => $callback) {
+        $this->facesMethods[$method] = array(0 => $callback);
+      }
+    }
+
+    /**
+     * Adds in include files for the given methods while removing any old files.
+     * If a single include file is described, it's added for all methods.
+     */
+    protected function addIncludes($methods, $includes) {
+      $includes = isset($includes['module']) && is_string($includes['module']) ? array_fill_keys($methods, $includes) : $includes;
+      $this->facesIncludes = $includes + array_diff_key($this->facesIncludes, array_flip($methods));
+    }
+
+    /**
+     * Only serialize what is really necessary.
+     */
+    public function __sleep() {
+      return array('facesMethods', 'faces', 'facesIncludes');
+    }
+
+    /**
+     * Destroys all references to created instances so that PHP's garbage
+     * collection can do its work. This is needed as PHP's gc has troubles with
+     * circular references until PHP < 5.3.
+     */
+    public function destroy() {
+      // Avoid circular references.
+      $this->facesClassInstances = array();
+    }
+
+    /**
+     * Makes protected properties accessible.
+     */
+    public function &property($name) {
+      if (property_exists($this, $name)) {
+        return $this->$name;
+      }
+    }
+
+    /**
+     * Invokes any method.
+     *
+     * This also allows to pass arguments by reference, so it may be used to
+     * pass arguments by reference to dynamically extended methods.
+     *
+     * @param $name
+     *   The method name.
+     * @param $arguments
+     *   An array of arguments to pass to the method.
+     */
+    public function call($name, array $args = array()) {
+      if (method_exists($this, $name)) {
+        return call_user_func_array(array($this, $name), $args);
+      }
+      return $this->__call($name, $args);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/includes/rules.core.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,2808 @@
+<?php
+
+/**
+ * @file
+ * Rules base classes and interfaces needed for any rule evaluation.
+ */
+
+// This is not necessary as the classes are autoloaded via the registry. However
+// it saves some possible update headaches until the registry is rebuilt.
+// @todo
+//   Remove for a future release.
+require_once dirname(__FILE__) . '/faces.inc';
+
+/**
+ * Make sure loaded rule configs are instantiated right.
+ */
+class RulesEntityController extends EntityAPIControllerExportable {
+
+  /**
+   * Overridden.
+   *
+   * @see EntityAPIController::create()
+   */
+  public function create(array $values = array()) {
+    // Default to rules as owning module.
+    $values += array('owner' => 'rules');
+    return parent::create($values);
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController::attachLoad()
+   */
+  protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
+    // Retrieve stdClass records and turn them in rules objects stored in 'data'
+    $ids = array_keys($queried_entities);
+    $result = db_select('rules_tags')
+      ->fields('rules_tags', array('id', 'tag'))
+      ->condition('id', $ids, 'IN')
+      ->execute();
+    foreach ($result as $row) {
+      $tags[$row->id][] = $row->tag;
+    }
+    $result = db_select('rules_dependencies')
+      ->fields('rules_dependencies', array('id', 'module'))
+      ->condition('id', $ids, 'IN')
+      ->execute();
+    foreach ($result as $row) {
+      $modules[$row->id][] = $row->module;
+    }
+
+    $entities = array();
+    foreach ($queried_entities as $record) {
+      $entity = $record->data;
+      // Set the values of the other columns.
+      foreach ($this->entityInfo['schema_fields_sql']['base table'] as $field) {
+        $entity->$field = $record->$field;
+      }
+      unset($entity->data, $entity->plugin);
+      // Add any tags or dependencies.
+      $entity->dependencies = isset($modules[$entity->id]) ? $modules[$entity->id] : array();
+      $entity->tags = isset($tags[$entity->id]) ? $tags[$entity->id] : array();
+      $entities[$entity->id] = $entity;
+    }
+    $queried_entities = $entities;
+    parent::attachLoad($queried_entities, $revision_id);
+  }
+
+  /**
+   * Override to support having events and tags as conditions.
+   * @see EntityAPIController::applyConditions($entities, $conditions)
+   * @see rules_query_rules_config_load_multiple_alter()
+   */
+  protected function applyConditions($entities, $conditions = array()) {
+    if (isset($conditions['event']) || isset($conditions['plugin'])) {
+      foreach ($entities as $key => $entity) {
+        if (isset($conditions['event']) && (!($entity instanceof RulesTriggerableInterface) || !in_array($conditions['event'], $entity->events()))) {
+          unset($entities[$key]);
+        }
+        if (isset($conditions['plugin']) && !is_array($conditions['plugin'])) {
+          $conditions['plugin'] = array($conditions['plugin']);
+        }
+        if (isset($conditions['plugin']) && !in_array($entity->plugin(), $conditions['plugin'])) {
+          unset($entities[$key]);
+        }
+      }
+      unset($conditions['event'], $conditions['plugin']);
+    }
+    if (!empty($conditions['tags'])) {
+      foreach ($entities as $key => $entity) {
+        foreach ($conditions['tags'] as $tag) {
+          if (in_array($tag, $entity->tags)) {
+            continue 2;
+          }
+        }
+        unset($entities[$key]);
+      }
+      unset($conditions['tags']);
+    }
+    return parent::applyConditions($entities, $conditions);
+  }
+
+  /**
+   * Overridden to work with Rules' custom export format.
+   *
+   * @param $export
+   *   A serialized string in JSON format as produced by the
+   *   RulesPlugin::export() method, or the PHP export as usual PHP array.
+   */
+  public function import($export, &$error_msg = '') {
+    $export = is_array($export) ? $export : drupal_json_decode($export);
+    if (!is_array($export)) {
+      $error_msg = t('Unable to parse the pasted export.');
+      return FALSE;
+    }
+    // The key ist the configuration name and the value the actual export.
+    list($name, $export) = each($export);
+    if (!isset($export['PLUGIN'])) {
+      $error_msg = t('Export misses plugin information.');
+      return FALSE;
+    }
+    // Create an empty configuration, re-set basic keys and import.
+    $config = rules_plugin_factory($export['PLUGIN']);
+    $config->name = $name;
+    foreach (array('label', 'active', 'weight', 'tags', 'access_exposed') as $key) {
+      if (isset($export[strtoupper($key)])) {
+        $config->$key = $export[strtoupper($key)];
+      }
+    }
+    if (!empty($export['REQUIRES'])) {
+      foreach ($export['REQUIRES'] as $module) {
+        if (!module_exists($module)) {
+          $error_msg = t('Missing the required module %module.', array('%module' => $module));
+          return FALSE;
+        }
+      }
+      $config->dependencies = $export['REQUIRES'];
+    }
+    $config->import($export);
+    return $config;
+  }
+
+  public function save($rules_config, DatabaseTransaction $transaction = NULL) {
+    $transaction = isset($transaction) ? $transaction : db_transaction();
+
+    // Load the stored entity, if any.
+    if (!isset($rules_config->original) && $rules_config->{$this->idKey}) {
+      $rules_config->original = entity_load_unchanged($this->entityType, $rules_config->{$this->idKey});
+    }
+    $original = isset($rules_config->original) ? $rules_config->original : NULL;
+
+    $return = parent::save($rules_config, $transaction);
+    $this->storeTags($rules_config);
+    if ($rules_config instanceof RulesTriggerableInterface) {
+      $this->storeEvents($rules_config);
+    }
+    $this->storeDependencies($rules_config);
+
+    // See if there are any events that have been removed.
+    if ($original && $rules_config->plugin == 'reaction rule') {
+      foreach (array_diff($original->events(), $rules_config->events()) as $event_name) {
+        // Check if the event handler implements the event dispatcher interface.
+        $handler = rules_get_event_handler($event_name, $rules_config->getEventSettings($event_name));
+        if (!$handler instanceof RulesEventDispatcherInterface) {
+          continue;
+        }
+
+        // Only stop an event dispatcher if there are no rules for it left.
+        if (!rules_config_load_multiple(FALSE, array('event' => $event_name, 'plugin' => 'reaction rule', 'active' => TRUE)) && $handler->isWatching()) {
+          $handler->stopWatching();
+        }
+      }
+    }
+
+    return $return;
+  }
+
+  /**
+   * Save tagging information to the rules_tags table.
+   */
+  protected function storeTags($rules_config) {
+    db_delete('rules_tags')
+      ->condition('id', $rules_config->id)
+      ->execute();
+    if (!empty($rules_config->tags)) {
+      foreach ($rules_config->tags as $tag) {
+        db_insert('rules_tags')
+          ->fields(array('id', 'tag'), array($rules_config->id, $tag))
+          ->execute();
+      }
+    }
+  }
+
+  /**
+   * Save event information to the rules_trigger table.
+   */
+  protected function storeEvents(RulesTriggerableInterface $rules_config) {
+    db_delete('rules_trigger')
+      ->condition('id', $rules_config->id)
+      ->execute();
+    foreach ($rules_config->events() as $event) {
+      db_insert('rules_trigger')
+        ->fields(array(
+        'id' => $rules_config->id,
+        'event' => $event,
+      ))
+      ->execute();
+    }
+  }
+
+  protected function storeDependencies($rules_config) {
+    db_delete('rules_dependencies')
+      ->condition('id', $rules_config->id)
+      ->execute();
+    if (!empty($rules_config->dependencies)) {
+      foreach ($rules_config->dependencies as $dependency) {
+        db_insert('rules_dependencies')
+          ->fields(array(
+          'id' => $rules_config->id,
+          'module' => $dependency,
+        ))
+        ->execute();
+      }
+    }
+  }
+
+  /**
+   * Overridden to support tags and events in $conditions.
+   * @see EntityAPIControllerExportable::buildQuery()
+   */
+  protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
+    $query = parent::buildQuery($ids, $conditions, $revision_id);
+    $query_conditions =& $query->conditions();
+    foreach ($query_conditions as &$condition) {
+      // One entry in $query_conditions is a string with key '#conjunction'.
+      // @see QueryConditionInterface::conditions().
+      if (is_array($condition)) {
+        // Support using 'tags' => array('tag1', 'tag2') as condition.
+        if ($condition['field'] == 'base.tags') {
+          $query->join('rules_tags', 'rt', 'base.id = rt.id');
+          $condition['field'] = 'rt.tag';
+        }
+        // Support using 'event' => $name as condition.
+        if ($condition['field'] == 'base.event') {
+          $query->join('rules_trigger', 'tr', "base.id = tr.id");
+          $condition['field'] = 'tr.event';
+          // Use like operator to support % wildcards also.
+          $condition['operator'] = 'LIKE';
+        }
+      }
+    }
+    return $query;
+  }
+
+  /**
+   * Overridden to also delete tags and events.
+   * @see EntityAPIControllerExportable::delete()
+   */
+  public function delete($ids, DatabaseTransaction $transaction = NULL) {
+    $transaction = isset($transaction) ? $transaction : db_transaction();
+    // Use entity-load as ids may be the names as well as the ids.
+    $configs = $ids ? entity_load('rules_config', $ids) : array();
+    if ($configs) {
+      foreach ($configs as $config) {
+        db_delete('rules_trigger')
+          ->condition('id', $config->id)
+          ->execute();
+        db_delete('rules_tags')
+          ->condition('id', $config->id)
+          ->execute();
+        db_delete('rules_dependencies')
+          ->condition('id', $config->id)
+          ->execute();
+      }
+    }
+    $return = parent::delete($ids, $transaction);
+
+    // Stop event dispatchers when deleting the last rule of an event set.
+    $processed = array();
+    foreach ($configs as $config) {
+      if ($config->getPluginName() != 'reaction rule') {
+        continue;
+      }
+
+      foreach ($config->events() as $event_name) {
+        // Only process each event once.
+        if (!empty($processed[$event_name])) {
+          continue;
+        }
+        $processed[$event_name] = TRUE;
+
+        // Check if the event handler implements the event dispatcher interface.
+        $handler = rules_get_event_handler($event_name, $config->getEventSettings($event_name));
+        if (!$handler instanceof RulesEventDispatcherInterface) {
+          continue;
+        }
+
+        // Only stop an event dispatcher if there are no rules for it left.
+        if ($handler->isWatching() && !rules_config_load_multiple(FALSE, array('event' => $event_name, 'plugin' => 'reaction rule', 'active' => TRUE))) {
+          $handler->stopWatching();
+        }
+      }
+    }
+
+    return $return;
+  }
+}
+
+/**
+ * The RulesExtendable uses the rules cache to setup the defined extenders
+ * and overrides automatically.
+ * As soon faces is used the faces information is autoloaded using setUp().
+ */
+abstract class RulesExtendable extends FacesExtendable {
+
+  /**
+   * The name of the info definitions associated with info about this class.
+   * This would be defined abstract, if possible. Common rules hooks with class
+   * info are e.g. plugin_info and data_info.
+   */
+  protected $hook;
+
+  /**
+   * The name of the item this class represents in the info hook.
+   */
+  protected $itemName;
+
+  protected $cache, $itemInfo = array();
+
+
+  public function __construct() {
+    $this->setUp();
+  }
+
+  protected function setUp() {
+    // Keep a reference on the cache, so elements created during cache
+    // rebuilding end up with a complete cache in the end too.
+    $this->cache = &rules_get_cache();
+    if (isset($this->cache[$this->hook][$this->itemName])) {
+      $this->itemInfo = &$this->cache[$this->hook][$this->itemName];
+    }
+    // Set up the Faces Extenders
+    if (!empty($this->itemInfo['faces_cache'])) {
+      list($this->facesMethods, $this->facesIncludes, $this->faces) = $this->itemInfo['faces_cache'];
+    }
+  }
+
+  /**
+   * Force the object to be setUp, this executes setUp() if not done yet.
+   */
+  public function forceSetUp() {
+    if (!isset($this->cache) || (!empty($this->itemInfo['faces_cache']) && !$this->faces)) {
+      $this->setUp();
+    }
+  }
+
+  /**
+   * Magic method: Invoke the dynamically implemented methods.
+   */
+  public function __call($name, $arguments = array()) {
+    $this->forceSetUp();
+    return parent::__call($name, $arguments);
+  }
+
+  public function facesAs($interface = NULL) {
+    $this->forceSetUp();
+    return parent::facesAs($interface);
+  }
+
+  /**
+   * Allows items to add something to the rules cache.
+   */
+  public function rebuildCache(&$itemInfo, &$cache) {
+    // Speed up setting up items by caching the faces methods.
+    if (!empty($itemInfo['extenders'])) {
+      // Apply extenders and overrides.
+      $itemInfo += array('overrides' => array());
+      foreach ($itemInfo['extenders'] as $face => $data) {
+        $data += array('file' => array());
+        if (isset($data['class'])) {
+          $this->extendByClass($face, $data['class'], $data['file']);
+        }
+        elseif (isset($data['methods'])) {
+          $this->extend($face, $data['methods'], $data['file']);
+        }
+      }
+      foreach ($itemInfo['overrides'] as $data) {
+        $data += array('file' => array());
+        $this->override($data['methods'], $data['file']);
+      }
+      $itemInfo['faces_cache'] = array($this->facesMethods, $this->facesIncludes, $this->faces);
+      // We don't need that any more.
+      unset($itemInfo['extenders'], $itemInfo['overrides']);
+    }
+  }
+
+  /**
+   * Returns whether the a RuleExtendable supports the given interface.
+   *
+   * @param $itemInfo
+   *   The info about the item as specified in the hook.
+   * @param $interface
+   *   The interface to check for.
+   * @return
+   *   Whether it supports the given interface.
+   */
+  public static function itemFacesAs(&$itemInfo, $interface) {
+    return in_array($interface, class_implements($itemInfo['class'])) || isset($itemInfo['faces_cache'][2][$interface]);
+  }
+}
+
+/**
+ * Base class for rules plugins.
+ *
+ * We cannot inherit from EntityDB at the same time, so we implement our own
+ * entity related methods. Any CRUD related actions performed on contained
+ * plugins are applied and the root element representing the configuration is
+ * saved.
+ */
+abstract class RulesPlugin extends RulesExtendable {
+
+  /**
+   * If this is a configuration saved to the db, the id of it.
+   */
+  public $id = NULL;
+  public $weight = 0;
+  public $name = NULL;
+
+  /**
+   * An array of settings for this element.
+   */
+  public $settings = array();
+
+  /**
+   * Info about this element. Usage depends on the plugin.
+   */
+  protected $info = array();
+
+  /**
+   * The parent element, if any.
+   * @var RulesContainerPlugin
+   */
+  protected $parent = NULL;
+
+  protected $cache = NULL, $hook = 'plugin_info';
+
+  /**
+   * Identifies an element inside a configuration.
+   */
+  protected $elementId = NULL;
+
+  /**
+   * Static cache for availableVariables().
+   */
+  protected $availableVariables;
+
+
+  /**
+   * Sets a new parent element.
+   */
+  public function setParent(RulesContainerPlugin $parent) {
+    if ($this->parent == $parent) {
+      return;
+    }
+    if (isset($this->parent) && ($key = array_search($this, $this->parent->children)) !== FALSE) {
+      // Remove element from any previous parent.
+      unset($this->parent->children[$key]);
+      $this->parent->resetInternalCache();
+    }
+    // Make sure the interface matches the type of the container.
+    if (($parent instanceof RulesActionContainer && $this instanceof RulesActionInterface) ||
+       ($parent instanceof RulesConditionContainer && $this instanceof RulesConditionInterface)) {
+
+      $this->parent = $parent;
+      $parent->children[] = $this;
+      $this->parent->resetInternalCache();
+    }
+    else {
+      throw new RulesEvaluationException('The given container is incompatible with this element.', array(), $this, RulesLog::ERROR);
+    }
+  }
+
+  /**
+   * Gets the root element of the configuration.
+   */
+  public function root() {
+    $element = $this;
+    while (!$element->isRoot()) {
+      $element = $element->parent;
+    }
+    return $element;
+  }
+
+  /**
+   * Returns whether the element is the root of the configuration.
+   */
+  public function isRoot() {
+    return empty($this->parent) || isset($this->name);
+  }
+
+  /**
+   * Returns the element's parent.
+   */
+  public function parentElement() {
+    return $this->parent;
+  }
+
+  /**
+   * Returns the element id, which identifies the element inside the config.
+   */
+  public function elementId() {
+    if (!isset($this->elementId)) {
+      $this->elementMap()->index();
+    }
+    return $this->elementId;
+  }
+
+  /**
+   * Gets the element map helper object, which helps mapping elements to ids.
+   *
+   * @return RulesElementMap
+   */
+  public function elementMap() {
+    $config = $this->root();
+    if (empty($config->map)) {
+      $config->map = new RulesElementMap($config);
+    }
+    return $config->map;
+  }
+
+  /**
+   * Iterate over all elements nested below the current element.
+   *
+   * This helper can be used to recursively iterate over all elements of a
+   * configuration. To iterate over the children only, just regulary iterate
+   * over the object.
+   *
+   * @param $mode
+   *   (optional) The iteration mode used. See
+   *   RecursiveIteratorIterator::construct(). Defaults to SELF_FIRST.
+   *
+   * @return RecursiveIteratorIterator
+   */
+  public function elements($mode = RecursiveIteratorIterator::SELF_FIRST) {
+    return new RecursiveIteratorIterator($this, $mode);
+  }
+
+  /**
+   * Do a deep clone.
+   */
+  public function __clone() {
+    // Make sure the element map is cleared.
+    // @see self::elementMap()
+    unset($this->map);
+  }
+
+  /**
+   * Returns the depth of this element in the configuration.
+   */
+  public function depth() {
+    $element = $this;
+    $i = 0;
+    while (!empty($element->parent)) {
+      $element = $element->parent;
+      $i++;
+    }
+    return $i;
+  }
+
+  /**
+   * Execute the configuration.
+   *
+   * @param ...
+   *   Arguments to pass to the configuration.
+   */
+  public function execute() {
+    return $this->executeByArgs(func_get_args());
+  }
+
+  /**
+   * Execute the configuration by passing arguments in a single array.
+   */
+  abstract public function executeByArgs($args = array());
+
+  /**
+   * Evaluate the element on a given rules evaluation state.
+   */
+  abstract function evaluate(RulesState $state);
+
+  protected static function compare(RulesPlugin $a, RulesPlugin $b) {
+    if ($a->weight == $b->weight) {
+      return 0;
+    }
+    return ($a->weight < $b->weight) ? -1 : 1;
+  }
+
+  /**
+   * Returns info about parameters needed by the plugin.
+   *
+   * Note that not necessarily all parameters are needed when executing the
+   * plugin, as values for the parameter might have been already configured via
+   * the element settings.
+   *
+   * @see self::parameterInfo()
+   */
+  public function pluginParameterInfo() {
+    return isset($this->info['parameter']) ? $this->info['parameter'] : array();
+  }
+
+  /**
+   * Returns info about parameters needed for executing the configured plugin.
+   *
+   * @param $optional
+   *   Whether optional parameters should be included.
+   *
+   * @see self::pluginParameterInfo()
+   */
+  public function parameterInfo($optional = FALSE) {
+    // We have to filter out parameters that are already configured.
+    foreach ($this->pluginParameterInfo() as $name => $info) {
+      if (!isset($this->settings[$name . ':select']) && !isset($this->settings[$name]) && ($optional || (empty($info['optional']) && $info['type'] != 'hidden'))) {
+        $vars[$name] = $info;
+      }
+    }
+    return isset($vars) ? $vars : array();
+  }
+
+  /**
+   * Returns the about variables the plugin provides for later evaluated elements.
+   *
+   * Note that this method returns info about the provided variables as defined
+   * by the plugin. Thus this resembles the original info, which may be
+   * adapted via configuration.
+   *
+   * @see self::providesVariables()
+   */
+  public function pluginProvidesVariables() {
+    return isset($this->info['provides']) ? $this->info['provides'] : array();
+  }
+
+  /**
+   * Returns info about all variables provided for later evaluated elements.
+   *
+   * @see self::pluginProvidesVariables()
+   */
+  public function providesVariables() {
+    foreach ($this->pluginProvidesVariables() as $name => $info) {
+      $info['source name'] = $name;
+      $info['label'] = isset($this->settings[$name . ':label']) ? $this->settings[$name . ':label'] : $info['label'];
+      if (isset($this->settings[$name . ':var'])) {
+        $name = $this->settings[$name . ':var'];
+      }
+      $provides[$name] = $info;
+    }
+    return isset($provides) ? $provides : array();
+  }
+
+  /**
+   * Returns the info of the plugin.
+   */
+  public function info() {
+    return $this->info;
+  }
+
+  /**
+   * When converted to a string, just use the export format.
+   */
+  public function __toString() {
+    return $this->isRoot() ? $this->export() : entity_var_json_export($this->export());
+  }
+
+  /**
+   * Gets variables to return once the configuration has been executed.
+   */
+  protected function returnVariables(RulesState $state, $result = NULL) {
+    $var_info = $this->providesVariables();
+    foreach ($var_info as $name => $info) {
+      try {
+        $vars[$name] = $this->getArgument($name, $info, $state);
+      }
+      catch (RulesEvaluationException $e) {
+        // Ignore not existing variables.
+        $vars[$name] = NULL;
+      }
+      $var_info[$name] += array('allow null' => TRUE);
+    }
+    return isset($vars) ? array_values(rules_unwrap_data($vars, $var_info)) : array();
+  }
+
+  /**
+   * Sets up the execution state for the given arguments.
+   */
+  public function setUpState(array $args) {
+    $state = new RulesState();
+    $vars = $this->setUpVariables();
+    // Fix numerically indexed args to start with 0.
+    if (!isset($args[rules_array_key($vars)])) {
+      $args = array_values($args);
+    }
+    $offset = 0;
+    foreach (array_keys($vars) as $i => $name) {
+      $info = $vars[$name];
+      if (!empty($info['handler']) || (isset($info['parameter']) && $info['parameter'] === FALSE)) {
+        $state->addVariable($name, NULL, $info);
+        // Count the variables that are not passed as parameters.
+        $offset++;
+      }
+      // Support numerically indexed arrays as well as named parameter style.
+      // The index is reduced to exclude non-parameter variables.
+      elseif (isset($args[$i - $offset])) {
+        $state->addVariable($name, $args[$i - $offset], $info);
+      }
+      elseif (isset($args[$name])) {
+        $state->addVariable($name, $args[$name], $info);
+      }
+      elseif (empty($info['optional']) && $info['type'] != 'hidden') {
+        throw new RulesEvaluationException('Argument %name is missing.', array('%name' => $name), $this, RulesLog::ERROR);
+      }
+    }
+    return $state;
+  }
+
+  /**
+   * Returns info about all variables that have to be setup in the state.
+   */
+  protected function setUpVariables() {
+    return $this->parameterInfo(TRUE);
+  }
+
+  /**
+   * Returns info about variables available to be used as arguments for this element.
+   *
+   * As this is called very often, e.g. during integrity checks, we statically
+   * cache the results.
+   *
+   * @see RulesPlugin::resetInternalCache()
+   */
+  public function availableVariables() {
+    if (!isset($this->availableVariables)) {
+      $this->availableVariables = !$this->isRoot() ? $this->parent->stateVariables($this) : RulesState::defaultVariables();
+    }
+    return $this->availableVariables;
+  }
+
+  /**
+   * Returns asserted additions to the available variable info. Any returned
+   * info is merged into the variable info, in case the execution flow passes
+   * the element.
+   * E.g. this is used to assert the content type of a node if the condition
+   * is met, such that the per node type properties are available.
+   */
+  protected function variableInfoAssertions() {
+    return array();
+  }
+
+  /**
+   * Get the name of this plugin instance. The returned name should identify
+   * the code which drives this plugin.
+   */
+  public function getPluginName() {
+    return $this->itemName;
+  }
+
+  /**
+   * Calculates an array of required modules.
+   *
+   * You can use $this->dependencies to access dependencies for saved
+   * configurations.
+   */
+  public function dependencies() {
+    $this->processSettings();
+    $modules = isset($this->itemInfo['module']) && $this->itemInfo['module'] != 'rules' ? array($this->itemInfo['module'] => 1) : array();
+    foreach ($this->pluginParameterInfo() as $name => $info) {
+      if (isset($this->settings[$name . ':process']) && $this->settings[$name . ':process'] instanceof RulesDataProcessor) {
+        $modules += array_flip($this->settings[$name . ':process']->dependencies());
+      }
+    }
+    return array_keys($modules);
+  }
+
+  /**
+   * Whether the currently logged in user has access to all configured elements.
+   *
+   * Note that this only checks whether the current user has permission to all
+   * configured elements, but not whether a user has access to configure Rule
+   * configurations in general. Use rules_config_access() for that.
+   *
+   * Use this to determine access permissions for configuring or triggering the
+   * execution of certain configurations independent of the Rules UI.
+   *
+   * @see rules_config_access()
+   */
+  public function access() {
+    $this->processSettings();
+    foreach ($this->pluginParameterInfo() as $name => $info) {
+      if (isset($this->settings[$name . ':select']) && $wrapper = $this->applyDataSelector($this->settings[$name . ':select'])) {
+        if ($wrapper->access('view') === FALSE) {
+          return FALSE;
+        }
+      }
+      // Incorporate access checks for data processors and input evaluators.
+      if (isset($this->settings[$name . ':process']) && $this->settings[$name . ':process'] instanceof RulesDataProcessor && !$this->settings[$name . ':process']->editAccess()) {
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  /**
+   * Processes the settings e.g. to prepare input evaluators.
+   *
+   * Usually settings get processed automatically, however if $this->settings
+   * has been altered manually after element construction, it needs to be
+   * invoked explicitly with $force set to TRUE.
+   *
+   */
+  public function processSettings($force = FALSE) {
+    // Process if not done yet.
+    if ($force || !empty($this->settings['#_needs_processing'])) {
+      $var_info = $this->availableVariables();
+      foreach ($this->pluginParameterInfo() as $name => $info) {
+        // Prepare input evaluators.
+        if (isset($this->settings[$name])) {
+          $this->settings[$name . ':process'] = $this->settings[$name];
+          RulesDataInputEvaluator::prepareSetting($this->settings[$name . ':process'], $info, $var_info);
+        }
+        // Prepare data processors.
+        elseif (isset($this->settings[$name . ':select']) && !empty($this->settings[$name . ':process'])) {
+          RulesDataProcessor::prepareSetting($this->settings[$name . ':process'], $info, $var_info);
+        }
+        // Clean up.
+        if (empty($this->settings[$name . ':process'])) {
+          unset($this->settings[$name . ':process']);
+        }
+      }
+      unset($this->settings['#_needs_processing']);
+    }
+  }
+
+  /**
+   * Makes sure the plugin is configured right, e.g. all needed variables
+   * are available in the element's scope and dependent modules are enabled.
+   *
+   * @return RulesPlugin
+   *   Returns $this to support chained usage.
+   *
+   * @throws RulesIntegrityException
+   *   In case of a failed integraty check, a RulesIntegrityException exception
+   *   is thrown.
+   */
+  public function integrityCheck() {
+    // First process the settings if not done yet.
+    $this->processSettings();
+    // Check dependencies using the pre-calculated dependencies stored in
+    // $this->dependencies. Fail back to calculation them on the fly, e.g.
+    // during creation.
+    $dependencies = empty($this->dependencies) ? $this->dependencies() : $this->dependencies;
+    foreach ($dependencies as $module) {
+      if (!module_exists($module)) {
+        throw new RulesDependencyException(t('Missing required module %name.', array('%name' => $module)));
+      }
+    }
+    // Check the parameter settings.
+    $this->checkParameterSettings();
+    // Check variable names for provided variables to be valid.
+    foreach ($this->pluginProvidesVariables() as $name => $info) {
+      if (isset($this->settings[$name . ':var'])) {
+        $this->checkVarName($this->settings[$name . ':var']);
+      }
+    }
+    return $this;
+  }
+
+  protected function checkVarName($name) {
+    if (!preg_match('/^[0-9a-zA-Z_]*$/', $name)) {
+      throw new RulesIntegrityException(t('%plugin: The variable name %name contains not allowed characters.', array('%plugin' => $this->getPluginName(), '%name' => $name)), $this);
+    }
+  }
+
+  /**
+   * Checks whether parameters are correctly configured.
+   */
+  protected function checkParameterSettings() {
+    foreach ($this->pluginParameterInfo() as $name => $info) {
+      if (isset($info['restriction']) && $info['restriction'] == 'selector' && isset($this->settings[$name])) {
+        throw new RulesIntegrityException(t("The parameter %name may only be configured using a selector.", array('%name' => $name)), array($this, 'parameter', $name));
+      }
+      elseif (isset($info['restriction']) && $info['restriction'] == 'input' && isset($this->settings[$name . ':select'])) {
+        throw new RulesIntegrityException(t("The parameter %name may not be configured using a selector.", array('%name' => $name)), array($this, 'parameter', $name));
+      }
+      elseif (!empty($this->settings[$name . ':select']) && !$this->applyDataSelector($this->settings[$name . ':select'])) {
+        throw new RulesIntegrityException(t("Data selector %selector for parameter %name is invalid.", array('%selector' => $this->settings[$name . ':select'], '%name' => $name)), array($this, 'parameter', $name));
+      }
+      elseif ($arg_info = $this->getArgumentInfo($name)) {
+        // If we have enough metadata, check whether the types match.
+        if (!RulesData::typesMatch($arg_info, $info)) {
+          throw new RulesIntegrityException(t("The data type of the configured argument does not match the parameter's %name requirement.", array('%name' => $name)), array($this, 'parameter', $name));
+        }
+      }
+      elseif (!$this->isRoot() && !isset($this->settings[$name]) && empty($info['optional']) && $info['type'] != 'hidden') {
+        throw new RulesIntegrityException(t('Missing configuration for parameter %name.', array('%name' => $name)), array($this, 'parameter', $name));
+      }
+      //TODO: Make sure used values are allowed. (key/value pairs + allowed values)
+    }
+  }
+
+  /**
+   * Returns the argument as configured in the element settings for the
+   * parameter $name described with $info.
+   *
+   * @param $name
+   *   The name of the parameter for which to get the argument.
+   * @param $info
+   *   Info about the parameter.
+   * @param RulesState $state
+   *   The current evaluation state.
+   * @param $langcode
+   *   (optional) The language code used to get the argument value if the
+   *   argument value should be translated. By default (NULL) the current
+   *   interface language will be used.
+   *
+   * @return
+   *   The argument, possibly wrapped.
+   *
+   * @throws RulesEvaluationException
+   *   In case the argument cannot be retrieved an exception is thrown.
+   */
+  protected function getArgument($name, $info, RulesState $state, $langcode = NULL) {
+    // Only apply the langcode if the parameter has been marked translatable.
+    if (empty($info['translatable'])) {
+      $langcode = LANGUAGE_NONE;
+    }
+    elseif (!isset($langcode)) {
+      $langcode = $GLOBALS['language']->language;
+    }
+
+    if (!empty($this->settings[$name . ':select'])) {
+      $arg = $state->applyDataSelector($this->settings[$name . ':select'], $langcode);
+    }
+    elseif (isset($this->settings[$name])) {
+      $arg = rules_wrap_data($this->settings[$name], $info);
+      // We don't sanitize directly specified values.
+      $skip_sanitize = TRUE;
+    }
+    elseif ($state->varinfo($name)) {
+      $arg = $state->get($name);
+    }
+    elseif (empty($info['optional']) && $info['type'] != 'hidden') {
+      throw new RulesEvaluationException('Required parameter %name is missing.', array('%name' => $name), $this, RulesLog::ERROR);
+    }
+    else {
+      $arg = isset($info['default value']) ? $info['default value'] : NULL;
+      $skip_sanitize = TRUE;
+      $info['allow null'] = TRUE;
+    }
+    // Make sure the given value is set if required (default).
+    if (!isset($arg) && empty($info['allow null'])) {
+      throw new RulesEvaluationException('The provided argument for parameter %name is empty.', array('%name' => $name), $this);
+    }
+
+    // Support passing already sanitized values.
+    if ($info['type'] == 'text' && !isset($skip_sanitize) && !empty($info['sanitize']) && !($arg instanceof EntityMetadataWrapper)) {
+      $arg = check_plain((string) $arg);
+    }
+
+    // Apply any configured data processors.
+    if (!empty($this->settings[$name . ':process'])) {
+      // For processing, make sure the data is unwrapped now.
+      $return = rules_unwrap_data(array($arg), array($info));
+      // @todo for Drupal 8: Refactor to add the name and language code as
+      // separate parameter to process().
+      $info['#name'] = $name;
+      $info['#langcode'] = $langcode;
+      return isset($return[0]) ? $this->settings[$name . ':process']->process($return[0], $info, $state, $this) : NULL;
+    }
+    return $arg;
+  }
+
+  /**
+   * Gets the right arguments for executing the element.
+   *
+   * @throws RulesEvaluationException
+   *   If case an argument cannot be retrieved an exception is thrown.
+   */
+  protected function getExecutionArguments(RulesState $state) {
+    $parameters = $this->pluginParameterInfo();
+    // If there is language parameter, get its value first so it can be used
+    // for getting other translatable values.
+    $langcode = NULL;
+    if (isset($parameters['language'])) {
+      $lang_arg = $this->getArgument('language', $parameters['language'], $state);
+      $langcode = $lang_arg instanceof EntityMetadataWrapper ? $lang_arg->value() : $lang_arg;
+    }
+    // Now get all arguments.
+    foreach ($parameters as $name => $info) {
+      $args[$name] = $name == 'language' ? $lang_arg : $this->getArgument($name, $info, $state, $langcode);
+    }
+    // Append the settings and the execution state. Faces will append $this.
+    $args['settings'] = $this->settings;
+    $args['state'] = $state;
+    // Make the wrapped variables for the arguments available in the state.
+    $state->currentArguments = $args;
+    return rules_unwrap_data($args, $parameters);
+  }
+
+  /**
+   * Apply the given data selector by using the info about available variables.
+   * Thus it doesn't require an actual evaluation state.
+   *
+   * @param $selector
+   *   The selector string, e.g. "node:author:mail".
+   *
+   * @return EntityMetadataWrapper
+   *   An empty wrapper for the given selector or FALSE if the selector couldn't
+   *   be applied.
+   */
+  public function applyDataSelector($selector) {
+    $parts = explode(':', str_replace('-', '_', $selector), 2);
+    if (($vars = $this->availableVariables()) && isset($vars[$parts[0]]['type'])) {
+      $wrapper = rules_wrap_data(NULL, $vars[$parts[0]], TRUE);
+      if (count($parts) > 1 && $wrapper instanceof EntityMetadataWrapper) {
+        try {
+          foreach (explode(':', $parts[1]) as $name) {
+            if ($wrapper instanceof EntityListWrapper || $wrapper instanceof EntityStructureWrapper) {
+              $wrapper = $wrapper->get($name);
+            }
+            else {
+              return FALSE;
+            }
+          }
+        }
+        // In case of an exception or we were unable to get a wrapper, return FALSE.
+        catch (EntityMetadataWrapperException $e) {
+          return FALSE;
+        }
+      }
+    }
+    return isset($wrapper) ? $wrapper : FALSE;
+  }
+
+  /**
+   * Returns info about the configured argument.
+   *
+   * @return
+   *   The determined info. If it's not known NULL is returned.
+   */
+  public function getArgumentInfo($name) {
+    $vars = $this->availableVariables();
+    if (!empty($this->settings[$name . ':select']) && !empty($vars[$this->settings[$name . ':select']])) {
+      return $vars[$this->settings[$name . ':select']];
+    }
+    elseif (!empty($this->settings[$name . ':select'])) {
+      if ($wrapper = $this->applyDataSelector($this->settings[$name . ':select'])) {
+        return $wrapper->info();
+      }
+      return;
+    }
+    elseif (isset($this->settings[$name . ':type'])) {
+      return array('type' => $this->settings[$name . ':type']);
+    }
+    elseif (!isset($this->settings[$name]) && isset($vars[$name])) {
+      return $vars[$name];
+    }
+  }
+
+  /**
+   * Saves the configuration to the database, regardless whether this is invoked
+   * on the rules configuration or a contained rule element.
+   */
+  public function save($name = NULL, $module = 'rules') {
+    if (isset($this->parent)) {
+      $this->parent->sortChildren();
+      return $this->parent->save($name, $module);
+    }
+    else {
+      // Update the dirty flag before saving.
+      // However, this operation depends on a fully built Rules-cache, so skip
+      // it when entities in code are imported to the database.
+      // @see _rules_rebuild_cache()
+      if (empty($this->is_rebuild)) {
+        rules_config_update_dirty_flag($this, FALSE);
+        // In case the config is not dirty, pre-calculate the dependencies for
+        // later checking. Note that this also triggers processing settings if
+        // necessary.
+        // @see rules_modules_enabled()
+        if (empty($this->dirty)) {
+          $this->dependencies = $this->dependencies();
+        }
+      }
+
+      $this->plugin = $this->itemName;
+      $this->name = isset($name) ? $name : $this->name;
+      // Module stores the module via which the rule is configured and is used
+      // for generating machine names with the right prefix. However, for
+      // default configurations 'module' points to the module providing the
+      // default configuration, so the module via which the rules is configured
+      // is stored in the "owner" property.
+      // @todo: For Drupal 8 use "owner" for generating machine names also and
+      // module only for the modules providing default configurations.
+      $this->module = !isset($this->module) || $module != 'rules' ? $module : $this->module;
+      $this->owner = !isset($this->owner) || $module != 'rules' ? $module : $this->module;
+      $this->ensureNameExists();
+      $this->data = $this;
+      $return = entity_get_controller('rules_config')->save($this);
+      unset($this->data);
+
+      // Care about clearing necessary caches.
+      if (!empty($this->is_rebuild)) {
+        rules_clear_cache();
+      }
+      else {
+        $plugin_info = $this->pluginInfo();
+        if (!empty($plugin_info['component'])) {
+          // When component variables changes rebuild the complete cache so the
+          // changes to the provided action/condition take affect.
+          if (empty($this->original) || $this->componentVariables() != $this->original->componentVariables()) {
+            rules_clear_cache();
+          }
+          // Clear components cached for evaluation.
+          cache_clear_all('comp_', 'cache_rules', TRUE);
+        }
+        elseif ($this->plugin == 'reaction rule') {
+          // Clear event sets cached for evaluation.
+          cache_clear_all('event_', 'cache_rules', TRUE);
+          variable_del('rules_event_whitelist');
+        }
+        drupal_static_reset('rules_get_cache');
+        drupal_static_reset('rules_config_update_dirty_flag');
+      }
+
+      return $return;
+    }
+  }
+
+  /**
+   * Ensure the configuration has a name. If not, generate one.
+   */
+  protected function ensureNameExists() {
+    if (!isset($this->module)) {
+      $this->module = 'rules';
+    }
+    if (!isset($this->name)) {
+      // Find a unique name for this configuration.
+      $this->name = $this->module . '_';
+      for ($i = 0; $i < 8; $i++) {
+        // Alphanumeric name generation.
+        $rnd = mt_rand(97, 122);
+        $this->name .= chr($rnd);
+      }
+    }
+  }
+
+  public function __sleep() {
+    // Keep the id always as we need it for the recursion prevention.
+    $array = drupal_map_assoc(array('parent', 'id', 'elementId', 'weight', 'settings'));
+    // Keep properties related to configurations if they are there.
+    $info = entity_get_info('rules_config');
+    $fields = array_merge($info['schema_fields_sql']['base table'], array('recursion', 'tags'));
+    foreach ($fields as $key) {
+      if (isset($this->$key)) {
+        $array[$key] = $key;
+      }
+    }
+    return $array;
+  }
+
+  /**
+   * Optimizes a rule configuration in order to speed up evaluation.
+   *
+   * Additional optimization methods may be inserted by an extender
+   * implementing the RulesOptimizationInterface. By default, there is no
+   * optimization extender.
+   *
+   * An optimization method may rearrange the internal structure of a
+   * configuration in order to speed up the evaluation. As the configuration may
+   * change optimized configurations should not be saved permanently, except
+   * when saving it temporary, for later execution only.
+   *
+   * @see RulesOptimizationInterface
+   */
+  public function optimize() {
+    // Make sure settings are processed before configs are cached.
+    $this->processSettings();
+    if ($this->facesAs('RulesOptimizationInterface')) {
+      $this->__call('optimize');
+    }
+  }
+
+  /**
+   * If invoked on a rules configuration it is deleted from database. If
+   * invoked on a contained rule element, it's removed from the configuration.
+   */
+  public function delete() {
+    if (isset($this->parent)) {
+      foreach ($this->parent->children as $key => $child) {
+        if ($child === $this) {
+          unset($this->parent->children[$key]);
+          break;
+        }
+      }
+    }
+    elseif (isset($this->id)) {
+      entity_get_controller('rules_config')->delete(array($this->name));
+      rules_clear_cache();
+    }
+  }
+
+  public function internalIdentifier() {
+    return isset($this->id) ? $this->id : NULL;
+  }
+
+  /**
+   * Returns the config name.
+   */
+  public function identifier() {
+    return isset($this->name) ? $this->name : NULL;
+  }
+
+  public function entityInfo() {
+    return entity_get_info('rules_config');
+  }
+
+  public function entityType() {
+    return 'rules_config';
+  }
+
+  /**
+   * Checks if the configuration has a certain exportable status.
+   *
+   * @param $status
+   *   A status constant, i.e. one of ENTITY_CUSTOM, ENTITY_IN_CODE,
+   *   ENTITY_OVERRIDDEN or ENTITY_FIXED.
+   *
+   * @return
+   *   TRUE if the configuration has the status, else FALSE.
+   *
+   * @see entity_has_status()
+   */
+  public function hasStatus($status) {
+    return $this->isRoot() && isset($this->status) && ($this->status & $status) == $status;
+  }
+
+  /**
+   * Remove circular object references so the PHP garbage collector does its
+   * work.
+   */
+  public function destroy() {
+    parent::destroy();
+    $this->parent = NULL;
+  }
+
+  /**
+   * Seamlessy invokes the method implemented via faces without having to think
+   * about references.
+   */
+  public function form(&$form, &$form_state, array $options = array()) {
+    $this->__call('form', array(&$form, &$form_state, $options));
+  }
+
+  public function form_validate($form, &$form_state) {
+    $this->__call('form_validate', array($form, &$form_state));
+  }
+
+  public function form_submit($form, &$form_state) {
+    $this->__call('form_submit', array($form, &$form_state));
+  }
+
+  /**
+   * Returns the label of the element.
+   */
+  public function label() {
+    if (!empty($this->label) && $this->label != t('unlabeled')) {
+      return $this->label;
+    }
+    $info = $this->info();
+    return isset($info['label']) ? $info['label'] : (!empty($this->name) ? $this->name : t('unlabeled'));
+  }
+
+  /**
+   * Returns the name of the element's plugin.
+   */
+  public function plugin() {
+    return $this->itemName;
+  }
+
+  /**
+   * Returns info about the element's plugin.
+   */
+  public function pluginInfo() {
+    $this->forceSetUp();
+    return $this->itemInfo;
+  }
+
+  /**
+   * Applies the given export.
+   */
+  public function import(array $export) {
+    $this->importSettings($export[strtoupper($this->plugin())]);
+  }
+
+  protected function importSettings($export) {
+    // Import parameter settings.
+    $export += array('USING' => array(), 'PROVIDE' => array());
+    foreach ($export['USING'] as $name => $param_export) {
+      $this->importParameterSetting($name, $param_export);
+    }
+    foreach ($export['PROVIDE'] as $name => $var_export) {
+      // The key of $var_export is the variable name, the value the label.
+      $this->settings[$name . ':var'] = rules_array_key($var_export);
+      $this->settings[$name . ':label'] = reset($var_export);
+    }
+  }
+
+  protected function importParameterSetting($name, $export) {
+    if (is_array($export) && isset($export['select'])) {
+      $this->settings[$name . ':select'] = $export['select'];
+      if (count($export) > 1) {
+        // Add in processor settings.
+        unset($export['select']);
+        $this->settings[$name . ':process'] = $export;
+      }
+    }
+    // Convert back the [selector] strings being an array with one entry.
+    elseif (is_array($export) && count($export) == 1 && isset($export[0])) {
+      $this->settings[$name . ':select'] = $export[0];
+    }
+    elseif (is_array($export) && isset($export['value'])) {
+      $this->settings[$name] = $export['value'];
+    }
+    else {
+      $this->settings[$name] = $export;
+    }
+  }
+
+  /**
+   * Exports a rule configuration.
+   *
+   * @param $prefix
+   *   An optional prefix for each line.
+   * @param $php
+   *   Optional. Set to TRUE to format the export using PHP arrays. By default
+   *   JSON is used.
+   * @return
+   *   The exported confiugration.
+   *
+   * @see rules_import()
+   */
+  public function export($prefix = '', $php = FALSE) {
+    $export = $this->exportToArray();
+    return $this->isRoot() ? $this->returnExport($export, $prefix, $php) : $export;
+  }
+
+  protected function exportToArray() {
+    $export[strtoupper($this->plugin())] = $this->exportSettings();
+    return $export;
+  }
+
+  protected function exportSettings() {
+    $export = array();
+    if (!$this->isRoot()) {
+      foreach ($this->pluginParameterInfo() as $name => $info) {
+        if (($return = $this->exportParameterSetting($name, $info)) !== NULL) {
+          $export['USING'][$name] = $return;
+        }
+      }
+      foreach ($this->providesVariables() as $name => $info) {
+        if (!empty($info['source name'])) {
+          $export['PROVIDE'][$info['source name']][$name] = $info['label'];
+        }
+      }
+    }
+    return $export;
+  }
+
+  protected function exportParameterSetting($name, $info) {
+    if (isset($this->settings[$name]) && (empty($info['optional']) || !isset($info['default value']) || $this->settings[$name] != $info['default value'])) {
+      // In case of an array-value wrap the value into another array, such that
+      // the value cannot be confused with an exported data selector.
+      return is_array($this->settings[$name]) ? array('value' => $this->settings[$name]) : $this->settings[$name];
+    }
+    elseif (isset($this->settings[$name . ':select'])) {
+      if (isset($this->settings[$name . ':process']) && $processor = $this->settings[$name . ':process']) {
+        $export['select'] = $this->settings[$name . ':select'];
+        $export += $processor instanceof RulesDataProcessor ? $processor->getChainSettings() : $processor;
+        return $export;
+      }
+      // If there is no processor use a simple array to abbreviate this usual
+      // case. In JSON this turns to a nice [selector] string.
+      return array($this->settings[$name . ':select']);
+    }
+  }
+
+  /**
+   * Finalizies the configuration export by adding general attributes regarding
+   * the configuration and returns it in the right format.
+   */
+  protected function returnExport($export, $prefix = '', $php = FALSE) {
+    $this->ensureNameExists();
+    if (!empty($this->label) && $this->label != t('unlabeled')) {
+      $export_cfg[$this->name]['LABEL'] = $this->label;
+    }
+    $export_cfg[$this->name]['PLUGIN'] = $this->plugin();
+    if (!empty($this->weight)) {
+      $export_cfg[$this->name]['WEIGHT'] = $this->weight;
+    }
+    if (isset($this->active) && !$this->active) {
+      $export_cfg[$this->name]['ACTIVE'] = FALSE;
+    }
+    if (!empty($this->tags)) {
+      $export_cfg[$this->name]['TAGS'] = $this->tags;
+    }
+    if ($modules = $this->dependencies()) {
+      $export_cfg[$this->name]['REQUIRES'] = $modules;
+    }
+    if (!empty($this->access_exposed)) {
+      $export_cfg[$this->name]['ACCESS_EXPOSED'] = $this->access_exposed;
+    };
+    $export_cfg[$this->name] += $export;
+    return $php ? entity_var_export($export_cfg, $prefix) : entity_var_json_export($export_cfg, $prefix);
+  }
+
+  /**
+   * Resets any internal static caches.
+   *
+   * This function does not reset regular caches as retrieved via
+   * rules_get_cache(). Usually, it's invoked automatically when a Rules
+   * configuration is modified.
+   *
+   * Static caches are reset for the element and any elements down the tree. To
+   * clear static caches of the whole configuration, invoke the function at the
+   * root.
+   *
+   * @see RulesPlugin::availableVariables()
+   */
+  public function resetInternalCache() {
+    $this->availableVariables = NULL;
+  }
+}
+
+/**
+ * Defines a common base class for so called "Abstract Plugins" like actions.
+ * Thus modules have to provide the concrete plugin implementation.
+ */
+abstract class RulesAbstractPlugin extends RulesPlugin {
+
+  protected $elementName;
+  protected $info = array('parameter' => array(), 'provides' => array());
+  protected $infoLoaded = FALSE;
+
+  /**
+   * @param $name
+   *   The plugin implementation's name.
+   * @param $info
+   *   Further information provided about the plugin. Optional.
+   * @throws RulesException
+   *   If validation of the passed settings fails RulesExceptions are thrown.
+   */
+  function __construct($name = NULL, $settings = array()) {
+    $this->elementName = $name;
+    $this->settings = (array) $settings + array('#_needs_processing' => TRUE);
+    $this->setUp();
+  }
+
+  protected function setUp() {
+    parent::setUp();
+    if (isset($this->cache[$this->itemName . '_info'][$this->elementName])) {
+      $this->info = $this->cache[$this->itemName . '_info'][$this->elementName];
+      // Remember that the info has been correctly setup.
+      // @see self::forceSetup().
+      $this->infoLoaded = TRUE;
+
+      // Register the defined class, if any.
+      if (isset($this->info['class'])) {
+        $this->faces['RulesPluginImplInterface'] = 'RulesPluginImplInterface';
+        $face_methods = get_class_methods('RulesPluginImplInterface');
+        $class_info = array(1 => $this->info['class']);
+        foreach ($face_methods as $method) {
+          $this->facesMethods[$method] = $class_info;
+        }
+      }
+      // Add in per-plugin implementation callbacks if any.
+      if (!empty($this->info['faces_cache'])) {
+        foreach ($this->info['faces_cache'] as $face => $data) {
+          list($methods, $file_names) = $data;
+          foreach ($methods as $method => $callback) {
+            $this->facesMethods[$method] = $callback;
+          }
+          foreach ((array) $file_names as $method => $name) {
+            $this->facesIncludes[$method] = array('module' => $this->info['module'], 'name' => $name);
+          }
+        }
+        // Invoke the info_alter callback, but only if it has been implemented.
+        if ($this->facesMethods['info_alter'] != $this->itemInfo['faces_cache'][0]['info_alter']) {
+          $this->__call('info_alter', array(&$this->info));
+        }
+      }
+    }
+    elseif (!empty($this->itemInfo['faces_cache']) && function_exists($this->elementName)) {
+      // We don't have any info, so just add the name as execution callback.
+      $this->override(array('execute' => $this->elementName));
+    }
+  }
+
+  public function forceSetUp() {
+    if (!isset($this->cache) || (!empty($this->itemInfo['faces_cache']) && !$this->faces)) {
+      $this->setUp();
+    }
+    // In case we have element specific information, which is not loaded yet,
+    // do so now. This might happen if the element has been initially loaded
+    // with an incomplete cache, i.e. during cache rebuilding.
+    elseif (!$this->infoLoaded && isset($this->cache[$this->itemName . '_info'][$this->elementName])) {
+      $this->setUp();
+    }
+  }
+
+  /**
+   * Returns the label of the element.
+   */
+  public function label() {
+    $info = $this->info();
+    return isset($info['label']) ? $info['label'] : t('@plugin "@name"', array('@name' => $this->elementName, '@plugin' => $this->plugin()));
+  }
+
+  public function access() {
+    $info = $this->info();
+    $this->loadBasicInclude();
+    if (!empty($info['access callback']) && !call_user_func($info['access callback'], $this->itemName, $this->getElementName())) {
+      return FALSE;
+    }
+    return parent::access() && $this->__call('access');
+  }
+
+  public function integrityCheck() {
+    // Do the usual integrity check first so the implementation's validation
+    // handler can rely on that already.
+    parent::integrityCheck();
+    // Make sure the element is known.
+    $this->forceSetUp();
+    if (!isset($this->cache[$this->itemName . '_info'][$this->elementName])) {
+      throw new RulesIntegrityException(t('Unknown @plugin %name.', array('@plugin' => $this->plugin(), '%name' => $this->elementName)));
+    }
+    $this->validate();
+    return $this;
+  }
+
+  public function processSettings($force = FALSE) {
+    // Process if not done yet.
+    if ($force || !empty($this->settings['#_needs_processing'])) {
+      $this->resetInternalCache();
+      // In case the element implements the info alteration callback, (re-)run
+      // the alteration so that any settings depending info alterations are
+      // applied.
+      if ($this->facesMethods && $this->facesMethods['info_alter'] != $this->itemInfo['faces_cache'][0]['info_alter']) {
+        $this->__call('info_alter', array(&$this->info));
+      }
+      // First let the plugin implementation do processing, so data types of the
+      // parameters are fixed when we process the settings.
+      $this->process();
+      parent::processSettings($force);
+    }
+  }
+
+  public function pluginParameterInfo() {
+    // Ensure the info alter callback has been executed.
+    $this->forceSetup();
+    return parent::pluginParameterInfo();
+  }
+
+  public function pluginProvidesVariables() {
+    // Ensure the info alter callback has been executed.
+    $this->forceSetup();
+    return parent::pluginProvidesVariables();
+  }
+
+  public function info() {
+    // Ensure the info alter callback has been executed.
+    $this->forceSetup();
+    return $this->info;
+  }
+
+  protected function variableInfoAssertions() {
+    // Get the implementation's assertions and map them to the variable names.
+    if ($assertions = $this->__call('assertions')) {
+      foreach ($assertions as $param_name => $data) {
+        $name = isset($this->settings[$param_name . ':select']) ? $this->settings[$param_name . ':select'] : $param_name;
+        $return[$name] = $data;
+      }
+      return $return;
+    }
+  }
+
+  public function import(array $export) {
+    // The key is the element name and the value the actual export.
+    $this->elementName = rules_array_key($export);
+    $export = reset($export);
+
+    // After setting the element name, setup the element again so the right
+    // element info is loaded.
+    $this->setUp();
+
+    if (!isset($export['USING']) && !isset($export['PROVIDES']) && !empty($export)) {
+      // The export has been abbreviated to skip "USING".
+      $export = array('USING' => $export);
+    }
+    $this->importSettings($export);
+  }
+
+  protected function exportToArray() {
+    $export = $this->exportSettings();
+    if (!$this->providesVariables()) {
+      // Abbreviate the export making "USING" implicit.
+      $export = isset($export['USING']) ? $export['USING'] : array();
+    }
+    return array($this->elementName => $export);
+  }
+
+  public function dependencies() {
+    $modules = array_flip(parent::dependencies());
+    $modules += array_flip((array) $this->__call('dependencies'));
+    return array_keys($modules + (isset($this->info['module']) ? array($this->info['module'] => 1) : array()));
+  }
+
+  public function executeByArgs($args = array()) {
+    $replacements = array('%label' => $this->label(), '@plugin' => $this->itemName);
+    rules_log('Executing @plugin %label.', $replacements, RulesLog::INFO, $this, TRUE);
+    $this->processSettings();
+    // If there is no element info, just pass through the passed arguments.
+    // That way we support executing actions without any info at all.
+    if ($this->info()) {
+      $state = $this->setUpState($args);
+      module_invoke_all('rules_config_execute', $this);
+
+      $result = $this->evaluate($state);
+      $return = $this->returnVariables($state, $result);
+    }
+    else {
+      rules_log('Unable to execute @plugin %label.', $replacements, RulesLog::ERROR, $this);
+    }
+    $state->cleanUp();
+    rules_log('Finished executing of @plugin %label.', $replacements, RulesLog::INFO, $this, FALSE);
+    return $return;
+  }
+
+  /**
+   * Execute the configured execution callback and log that.
+   */
+  abstract protected function executeCallback(array $args, RulesState $state = NULL);
+
+
+  public function evaluate(RulesState $state) {
+    $this->processSettings();
+    try {
+      // Get vars as needed for execute and call it.
+      return $this->executeCallback($this->getExecutionArguments($state), $state);
+    }
+    catch (RulesEvaluationException $e) {
+      rules_log($e->msg, $e->args, $e->severity);
+      rules_log('Unable to evaluate %name.', array('%name' => $this->getPluginName()), RulesLog::WARN, $this);
+    }
+    // Catch wrapper exceptions that might occur due to failures loading an
+    // entity or similar.
+    catch (EntityMetadataWrapperException $e) {
+      rules_log('Unable to get a data value. Error: !error', array('!error' => $e->getMessage()), RulesLog::WARN);
+      rules_log('Unable to evaluate %name.', array('%name' => $this->getPluginName()), RulesLog::WARN, $this);
+    }
+  }
+
+  public function __sleep() {
+    return parent::__sleep() + array('elementName' => 'elementName');
+  }
+
+  public function getPluginName() {
+    return $this->itemName ." ". $this->elementName;
+  }
+
+  /**
+   * Gets the name of the configured action or condition.
+   */
+  public function getElementName() {
+    return $this->elementName;
+  }
+
+  /**
+   * Add in the data provided by the info hooks to the cache.
+   */
+  public function rebuildCache(&$itemInfo, &$cache) {
+    parent::rebuildCache($itemInfo, $cache);
+
+    // Include all declared files so we can find all implementations.
+    self::includeFiles();
+
+    // Get the plugin's own info data.
+    $cache[$this->itemName .'_info'] = rules_fetch_data($this->itemName .'_info');
+    foreach ($cache[$this->itemName .'_info'] as $name => &$info) {
+      $info += array(
+        'parameter' => isset($info['arguments']) ? $info['arguments'] : array(),
+        'provides' => isset($info['new variables']) ? $info['new variables'] : array(),
+        'base' => $name,
+        'callbacks' => array(),
+      );
+      unset($info['arguments'], $info['new variables']);
+
+      if (function_exists($info['base'])) {
+        $info['callbacks'] += array('execute' => $info['base']);
+      }
+
+      // We do not need to build a faces cache for RulesPluginHandlerInterface,
+      // which gets added in automatically as its a parent of
+      // RulesPluginImplInterface.
+      unset($this->faces['RulesPluginHandlerInterface']);
+
+      // Build up the per plugin implementation faces cache.
+      foreach ($this->faces as $interface) {
+        $methods = $file_names = array();
+        $includes = self::getIncludeFiles($info['module']);
+
+        foreach (get_class_methods($interface) as $method) {
+          if (isset($info['callbacks'][$method]) && ($function = $info['callbacks'][$method])) {
+            $methods[$method][0] = $function;
+            $file_names[$method] = $this->getFileName($function, $includes);
+          }
+          // Note that this skips RulesPluginImplInterface, which is not
+          // implemented by plugin handlers.
+          elseif (isset($info['class']) && is_subclass_of($info['class'], $interface)) {
+            $methods[$method][1] = $info['class'];
+          }
+          elseif (function_exists($function = $info['base'] . '_' . $method)) {
+            $methods[$method][0] = $function;
+            $file_names[$method] = $this->getFileName($function, $includes);
+          }
+        }
+        // Cache only the plugin implementation specific callbacks.
+        $info['faces_cache'][$interface] = array($methods, array_filter($file_names));
+      }
+      // Filter out interfaces with no overriden methods.
+      $info['faces_cache'] = rules_filter_array($info['faces_cache'], 0, TRUE);
+      // We don't need that any more.
+      unset($info['callbacks'], $info['base']);
+    }
+  }
+
+  /**
+   * Makes sure the providing modules' .rules.inc file is included as diverse
+   * callbacks may reside in that file.
+   */
+  protected function loadBasicInclude() {
+    static $included = array();
+
+    if (isset($this->info['module']) && !isset($included[$this->info['module']])) {
+      $module = $this->info['module'];
+      module_load_include('inc', $module, $module . '.rules');
+      $included[$module] = TRUE;
+    }
+  }
+
+  /**
+   * Make sure all supported destinations are included.
+   */
+  public static function includeFiles() {
+    static $included;
+
+    if (!isset($included)) {
+      foreach (module_implements('rules_file_info') as $module) {
+        // rules.inc are already included thanks to the rules_hook_info() group.
+        foreach (self::getIncludeFiles($module, FALSE) as $name) {
+          module_load_include('inc', $module, $name);
+        }
+      }
+      $dirs = array();
+      foreach (module_implements('rules_directory') as $module) {
+        // Include all files once, so the discovery can find them.
+        $result = module_invoke($module, 'rules_directory');
+        if (!is_array($result)) {
+          $result = array($module => $result);
+        }
+        $dirs += $result;
+      }
+      foreach ($dirs as $module => $directory) {
+        foreach (glob(drupal_get_path('module', $module) . "/$directory/*.{inc,php}", GLOB_BRACE) as $filename) {
+          include_once $filename;
+        }
+      }
+      $included = TRUE;
+    }
+  }
+
+  /**
+   * Returns all include files for a module. If $all is set to FALSE the
+   * $module.rules.inc file isn't added.
+   */
+  protected static function getIncludeFiles($module, $all = TRUE) {
+    $files = (array)module_invoke($module, 'rules_file_info');
+    // Automatically add "$module.rules_forms.inc" and "$module.rules.inc".
+    $files[] = $module . '.rules_forms';
+    if ($all) {
+      $files[] = $module . '.rules';
+    }
+    return $files;
+  }
+
+  protected function getFileName($function, $includes) {
+    $reflector = new ReflectionFunction($function);
+    // On windows the path contains backslashes instead of slashes, fix that.
+    $file = str_replace('\\', '/', $reflector->getFileName());
+    foreach ($includes as $include) {
+      $pos = strpos($file, $include . '.inc');
+      // Test whether the file ends with the given filename.inc.
+      if ($pos !== FALSE && strlen($file) - $pos == strlen($include) + 4) {
+        return $include;
+      }
+    }
+  }
+}
+
+/**
+ * Interface for objects that can be used as action.
+ */
+interface RulesActionInterface {
+
+  /**
+   * @return As specified.
+   *
+   * @throws RulesEvaluationException
+   *   Throws an exception if not all necessary arguments have been provided.
+   */
+  public function execute();
+}
+
+/**
+ * Interface for objects that can be used as condition.
+ */
+interface RulesConditionInterface {
+
+  /**
+   * @return Boolean.
+   *
+   * @throws RulesEvaluationException
+   *   Throws an exception if not all necessary arguments have been provided.
+   */
+  public function execute();
+
+  /**
+   * Negate the result.
+   */
+  public function negate($negate = TRUE);
+
+  /**
+   * Returns whether the element is configured to negate the result.
+   */
+  public function isNegated();
+}
+
+interface RulesTriggerableInterface {
+
+  /**
+   * Returns the array of (configured) event names associated with this object.
+   */
+  public function events();
+
+  /**
+   * Removes an event from the rule configuration.
+   *
+   * @param $event
+   *   The name of the (configured) event to remove.
+   * @return RulesTriggerableInterface
+   *   The object instance itself, to allow chaining.
+   */
+  public function removeEvent($event_name);
+
+  /**
+   * Adds the specified event.
+   *
+   * @param string $event_name
+   *   The base name of the event to add.
+   * @param array $settings
+   *   (optional) The event settings. If there are no event settings, pass an
+   *   empty array (default).
+   *
+   * @return RulesTriggerableInterface
+   */
+  public function event($event_name, array $settings = array());
+
+  /**
+   * Gets the event settings associated with the given (configured) event.
+   *
+   * @param $event_name
+   *   The (configured) event's name.
+   *
+   * @return array|null
+   *   The array of event settings, or NULL if there are no settings.
+   */
+  public function getEventSettings($event_name);
+
+}
+
+/**
+ * Provides the base interface for implementing abstract plugins via classes.
+ */
+interface RulesPluginHandlerInterface {
+
+  /**
+   * Validates $settings independent from a form submission.
+   *
+   * @throws RulesIntegrityException
+   *   In case of validation errors, RulesIntegrityExceptions are thrown.
+   */
+  public function validate();
+
+  /**
+   * Processes settings independent from a form submission.
+   *
+   * Processing results may be stored and accessed on execution time in $settings.
+   */
+  public function process();
+
+  /**
+   * Allows altering of the element's action/condition info.
+   *
+   * Note that this method is also invoked on evaluation time, thus any costly
+   * operations should be avoided.
+   *
+   * @param $element_info
+   *   A reference on the element's info as returned by RulesPlugin::info().
+   */
+  public function info_alter(&$element_info);
+
+  /**
+   * Checks whether the user has access to configure this element.
+   *
+   * Note that this only covers access for already created elements. In order to
+   * control access for creating or using elements specify an 'access callback'
+   * in the element's info array.
+   *
+   * @see hook_rules_action_info()
+   */
+  public function access();
+
+  /**
+   * Returns an array of required modules.
+   */
+  public function dependencies();
+
+  /**
+   * Alter the generated configuration form of the element.
+   *
+   * Validation and processing of the settings should be untied from the form
+   * and implemented in validate() and process() wherever it makes sense.
+   * For the remaining cases where form tied validation and processing is needed
+   * make use of the form API #element_validate and #value_callback properties.
+   */
+  public function form_alter(&$form, $form_state, $options);
+
+
+  /**
+   * Optionally returns an array of info assertions for the specified
+   * parameters. This allows conditions to assert additional metadata, such as
+   * info about the fields of a bundle.
+   *
+   * @see RulesPlugin::variableInfoAssertions()
+   */
+  public function assertions();
+
+}
+
+/**
+ * Interface for implementing conditions via classes.
+ *
+ * In addition to the interface an execute() and a static getInfo() method must
+ * be implemented. The static getInfo() method has to return the info as
+ * returned by hook_rules_condition_info() but including an additional 'name'
+ * key, specifying the plugin name.
+ * The execute method is the equivalent to the usual execution callback and
+ * gets the parameters passed as specified in the info array.
+ *
+ * See RulesNodeConditionType for an example and rules_discover_plugins()
+ * for information about class discovery.
+ */
+interface RulesConditionHandlerInterface extends RulesPluginHandlerInterface {}
+
+/**
+ * Interface for implementing actions via classes.
+ *
+ * In addition to the interface an execute() and a static getInfo() method must
+ * be implemented. The static getInfo() method has to return the info as
+ * returned by hook_rules_action_info() but including an additional 'name' key,
+ * specifying the plugin name.
+ * The execute method is the equivalent to the usual execution callback and
+ * gets the parameters passed as specified in the info array.
+ *
+ * See RulesNodeConditionType for an example and rules_discover_plugins()
+ * for information about class discovery.
+ */
+interface RulesActionHandlerInterface extends RulesPluginHandlerInterface {}
+
+/**
+ *
+ * Provides the interface used for implementing an abstract plugin by using
+ * the Faces extension mechanism.
+ */
+interface RulesPluginImplInterface extends RulesPluginHandlerInterface {
+
+  /**
+   * Execute the action or condition making use of the parameters as specified.
+   */
+  public function execute();
+}
+
+/**
+ * Interface for optimizing evaluation.
+ *
+ * @see RulesContainerPlugin::optimize()
+ */
+interface RulesOptimizationInterface {
+  /**
+   * Optimizes a rule configuration in order to speed up evaluation.
+   */
+  public function optimize();
+}
+
+/**
+ * Base class for implementing abstract plugins via classes.
+ */
+abstract class RulesPluginHandlerBase extends FacesExtender implements RulesPluginHandlerInterface {
+
+  /**
+   * @var RulesAbstractPlugin
+   */
+  protected $element;
+
+  /**
+   * Overridden to provide $this->element to make the code more meaningful.
+   */
+  public function __construct(FacesExtendable $object) {
+    $this->object = $object;
+    $this->element = $object;
+  }
+
+  /**
+   * Implements RulesPluginImplInterface.
+   */
+  public function access() {
+    return TRUE;
+  }
+
+  public function validate() {}
+  public function process() {}
+  public function info_alter(&$element_info) {}
+  public function dependencies() {}
+  public function form_alter(&$form, $form_state, $options) {}
+  public function assertions() {}
+}
+
+/**
+ * Base class for implementing conditions via classes.
+ */
+abstract class RulesConditionHandlerBase extends RulesPluginHandlerBase implements RulesConditionHandlerInterface {}
+
+/**
+ * Base class for implementing actions via classes.
+ */
+abstract class RulesActionHandlerBase extends RulesPluginHandlerBase implements RulesActionHandlerInterface {}
+
+/**
+ * Class providing default implementations of the methods of the RulesPluginImplInterface.
+ *
+ * If a plugin implementation does not provide a function for a method, the
+ * default method of this class will be invoked.
+ *
+ * @see RulesPluginImplInterface
+ * @see RulesAbstractPlugin
+ */
+class RulesAbstractPluginDefaults extends RulesPluginHandlerBase implements RulesPluginImplInterface {
+
+  public function execute() {
+    throw new RulesEvaluationException($this->object->getPluginName() .": Execution implementation is missing.", array(), $this->object, RulesLog::ERROR);
+  }
+}
+
+/**
+ * A RecursiveIterator for rule elements.
+ */
+class RulesRecursiveElementIterator extends ArrayIterator implements RecursiveIterator {
+
+   public function getChildren() {
+     return $this->current()->getIterator();
+   }
+
+   public function hasChildren() {
+      return $this->current() instanceof IteratorAggregate;
+   }
+}
+
+/**
+ * Base class for ContainerPlugins like Rules, Logical Operations or Loops.
+ */
+abstract class RulesContainerPlugin extends RulesPlugin implements IteratorAggregate {
+
+  protected $children = array();
+
+  public function __construct($variables = array()) {
+    $this->setUp();
+    if (!empty($variables) && $this->isRoot()) {
+      $this->info['variables'] = $variables;
+    }
+  }
+
+  /**
+   * Returns the specified variables, in case the plugin is used as component.
+   */
+  public function &componentVariables() {
+    if ($this->isRoot()) {
+      $this->info += array('variables' => array());
+      return $this->info['variables'];
+    }
+    // We have to return a reference in any case.
+    $return = NULL;
+    return $return;
+  }
+
+  /**
+   * Allow access to the children through the iterator.
+   *
+   * @return RulesRecursiveElementIterator
+   */
+  public function getIterator() {
+    return new RulesRecursiveElementIterator($this->children);
+  }
+
+  /**
+   * @return RulesContainerPlugin
+   */
+  public function integrityCheck() {
+    if (!empty($this->info['variables']) && !$this->isRoot()) {
+      throw new RulesIntegrityException(t('%plugin: Specifying state variables is not possible for child elements.', array('%plugin' => $this->getPluginName())), $this);
+    }
+    parent::integrityCheck();
+    foreach ($this->children as $child) {
+      $child->integrityCheck();
+    }
+    return $this;
+  }
+
+  public function dependencies() {
+    $modules = array_flip(parent::dependencies());
+    foreach ($this->children as $child) {
+      $modules += array_flip($child->dependencies());
+    }
+    return array_keys($modules);
+  }
+
+  public function parameterInfo($optional = FALSE) {
+    $params = parent::parameterInfo($optional);
+    if (isset($this->info['variables'])) {
+      foreach ($this->info['variables'] as $name => $var_info) {
+        if (empty($var_info['handler']) && (!isset($var_info['parameter']) || $var_info['parameter'])) {
+          $params[$name] = $var_info;
+          // For lists allow empty variables by default.
+          if (entity_property_list_extract_type($var_info['type'])) {
+            $params[$name] += array('allow null' => TRUE);
+          }
+        }
+      }
+    }
+    return $params;
+  }
+
+  public function availableVariables() {
+    if (!isset($this->availableVariables)) {
+      if ($this->isRoot()) {
+        $this->availableVariables = RulesState::defaultVariables();
+        if (isset($this->info['variables'])) {
+          $this->availableVariables += $this->info['variables'];
+        }
+      }
+      else {
+        $this->availableVariables = $this->parent->stateVariables($this);
+      }
+    }
+    return $this->availableVariables;
+  }
+
+  /**
+   * Returns info about variables available in the evaluation state for any
+   * children elements or if given for a special child element.
+   *
+   * @param $element
+   *   The element for which the available state variables should be returned.
+   *   If NULL is given, the variables available before any children are invoked
+   *   are returned. If set to TRUE, the variables available after evaluating
+   *   all children will be returned.
+   */
+  protected function stateVariables($element = NULL) {
+    $vars = $this->availableVariables();
+    if (isset($element)) {
+      // Add in variables provided by siblings executed before the element.
+      foreach ($this->children as $child) {
+        if ($child === $element) {
+          break;
+        }
+        $vars += $child->providesVariables();
+        // Take variable info assertions into account.
+        if ($assertions = $child->variableInfoAssertions()) {
+          $vars = RulesData::addMetadataAssertions($vars, $assertions);
+        }
+      }
+    }
+    return $vars;
+  }
+
+  protected function variableInfoAssertions() {
+    $assertions = array();
+    foreach ($this->children as $child) {
+      if ($add = $child->variableInfoAssertions()) {
+        $assertions = rules_update_array($assertions, $add);
+      }
+    }
+    return $assertions;
+  }
+
+  protected function setUpVariables() {
+    return isset($this->info['variables']) ? parent::parameterInfo(TRUE) + $this->info['variables'] : $this->parameterInfo(TRUE);
+  }
+
+  /**
+   * Condition containers just return a boolean while action containers return
+   * the configured provided variables as an array of variables.
+   */
+  public function executeByArgs($args = array()) {
+    $replacements = array('%label' => $this->label(), '@plugin' => $this->itemName);
+    rules_log('Executing @plugin %label.', $replacements, RulesLog::INFO, $this, TRUE);
+    $this->processSettings();
+    $state = $this->setUpState($args);
+
+    // Handle recursion prevention.
+    if ($state->isBlocked($this)) {
+      return rules_log('Not evaluating @plugin %label to prevent recursion.', array('%label' => $this->label(), '@plugin' => $this->plugin()), RulesLog::INFO);
+    }
+    // Block the config to prevent any future recursion.
+    $state->block($this);
+
+    module_invoke_all('rules_config_execute', $this);
+    $result = $this->evaluate($state);
+    $return = $this->returnVariables($state, $result);
+
+    $state->unblock($this);
+    $state->cleanUp();
+    rules_log('Finished executing of @plugin %label.', $replacements, RulesLog::INFO, $this, FALSE);
+    return $return;
+  }
+
+  public function access() {
+    foreach ($this->children as $key => $child) {
+      if (!$child->access()) {
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  public function destroy() {
+    foreach ($this->children as $key => $child) {
+      $child->destroy();
+    }
+    parent::destroy();
+  }
+
+  /**
+   * By default we do a deep clone.
+   */
+  public function __clone() {
+    parent::__clone();
+    foreach ($this->children as $key => $child) {
+      $this->children[$key] = clone $child;
+      $this->children[$key]->parent = $this;
+    }
+  }
+
+  /**
+   * Override delete to keep the children alive, if possible.
+   */
+  public function delete($keep_children = TRUE) {
+    if (isset($this->parent) && $keep_children) {
+      foreach ($this->children as $child) {
+        $child->setParent($this->parent);
+      }
+    }
+    parent::delete();
+  }
+
+  public function __sleep() {
+    return parent::__sleep() + array('children' => 'children', 'info' => 'info');
+  }
+
+  /**
+   * Sorts all child elements by their weight.
+   *
+   * @param $deep
+   *   If enabled a deep sort is performed, thus the whole element tree below
+   *   this element is sorted.
+   */
+  public function sortChildren($deep = FALSE) {
+    // Make sure the array order is kept in case two children have the same
+    // weight by ensuring later childrens would have higher weights.
+    foreach (array_values($this->children) as $i => $child) {
+      $child->weight += $i / 1000;
+    }
+    usort($this->children, array('RulesPlugin', 'compare'));
+
+    // Fix up the weights afterwards to be unique integers.
+    foreach (array_values($this->children) as $i => $child) {
+      $child->weight = $i;
+    }
+
+    if ($deep) {
+      foreach (new ParentIterator($this->getIterator()) as $child) {
+        $child->sortChildren(TRUE);
+      }
+    }
+    $this->resetInternalCache();
+  }
+
+  protected function exportChildren($key = NULL) {
+    $key = isset($key) ? $key : strtoupper($this->plugin());
+    $export[$key] = array();
+    foreach ($this->children as $child) {
+      $export[$key][] = $child->export();
+    }
+    return $export;
+  }
+
+  /**
+   * Determines whether the element should be exported in flat style. Flat style
+   * means that the export keys are written directly into the export array,
+   * whereas else the export is written into a sub-array.
+   */
+  protected function exportFlat() {
+    // By default we always use flat style for plugins without any parameters
+    // or provided variables, as then only children have to be exported. E.g.
+    // this applies to the OR and AND plugins.
+    return $this->isRoot() || (!$this->pluginParameterInfo() && !$this->providesVariables());
+  }
+
+  protected function exportToArray() {
+    $export = array();
+    if (!empty($this->info['variables'])) {
+      $export['USES VARIABLES'] = $this->info['variables'];
+    }
+    if ($this->exportFlat()) {
+      $export += $this->exportSettings() + $this->exportChildren();
+    }
+    else {
+      $export[strtoupper($this->plugin())] = $this->exportSettings() + $this->exportChildren();
+    }
+    return $export;
+  }
+
+  public function import(array $export) {
+    if (!empty($export['USES VARIABLES'])) {
+      $this->info['variables'] = $export['USES VARIABLES'];
+    }
+    // Care for exports having the export array nested in a sub-array.
+    if (!$this->exportFlat()) {
+      $export = reset($export);
+    }
+    $this->importSettings($export);
+    $this->importChildren($export);
+  }
+
+  protected function importChildren($export, $key = NULL) {
+    $key = isset($key) ? $key : strtoupper($this->plugin());
+    foreach ($export[$key] as $child_export) {
+      $plugin = _rules_import_get_plugin(rules_array_key($child_export), $this instanceof RulesActionInterface ? 'action' : 'condition');
+      $child = rules_plugin_factory($plugin);
+      $child->setParent($this);
+      $child->import($child_export);
+    }
+  }
+
+  public function resetInternalCache() {
+    $this->availableVariables = NULL;
+    foreach ($this->children as $child) {
+      $child->resetInternalCache();
+    }
+  }
+
+  /**
+   * Overrides optimize().
+   */
+  public function optimize() {
+    parent::optimize();
+    // Now let the children optimize itself.
+    foreach ($this as $element) {
+      $element->optimize();
+    }
+  }
+}
+
+/**
+ * Base class for all action containers.
+ */
+abstract class RulesActionContainer extends RulesContainerPlugin implements RulesActionInterface {
+
+  public function __construct($variables = array(), $providesVars = array()) {
+    parent::__construct($variables);
+    // The provided vars of a component are the names of variables, which should
+    // be provided to the caller. See rule().
+    if ($providesVars) {
+      $this->info['provides'] = $providesVars;
+    }
+  }
+
+  /**
+   * Add an action. Pass either an instance of the RulesActionInterface
+   * or the arguments as needed by rules_action().
+   *
+   * @return RulesActionContainer
+   *   Returns $this to support chained usage.
+   */
+  public function action($name, $settings = array()) {
+    $action = (is_object($name) && $name instanceof RulesActionInterface) ? $name : rules_action($name, $settings);
+    $action->setParent($this);
+    return $this;
+  }
+
+  /**
+   * Evaluate, whereas by default new vars are visible in the parent's scope.
+   */
+  public function evaluate(RulesState $state) {
+    foreach ($this->children as $action) {
+      $action->evaluate($state);
+    }
+  }
+
+  public function pluginProvidesVariables() {
+    return array();
+  }
+
+  public function providesVariables() {
+    $provides = parent::providesVariables();
+    if (isset($this->info['provides']) && $vars = $this->componentVariables()) {
+      // Determine the full variable info for the provided variables. Note that
+      // we only support providing variables list in the component vars.
+      $provides += array_intersect_key($vars, array_flip($this->info['provides']));
+    }
+    return $provides;
+  }
+
+  /**
+   * Returns an array of variable names, which are provided by passing through
+   * the provided variables of the children.
+   */
+  public function &componentProvidesVariables() {
+    $this->info += array('provides' => array());
+    return $this->info['provides'];
+  }
+
+  protected function exportToArray() {
+    $export = parent::exportToArray();
+    if (!empty($this->info['provides'])) {
+      $export['PROVIDES VARIABLES'] = $this->info['provides'];
+    }
+    return $export;
+  }
+
+  public function import(array $export) {
+    parent::import($export);
+    if (!empty($export['PROVIDES VARIABLES'])) {
+      $this->info['provides'] = $export['PROVIDES VARIABLES'];
+    }
+  }
+}
+
+/**
+ * Base class for all condition containers.
+ */
+abstract class RulesConditionContainer extends RulesContainerPlugin implements RulesConditionInterface {
+
+  protected $negate = FALSE;
+
+  /**
+   * Add a condition. Pass either an instance of the RulesConditionInterface
+   * or the arguments as needed by rules_condition().
+   *
+   * @return RulesConditionContainer
+   *   Returns $this to support chained usage.
+   */
+  public function condition($name, $settings = array()) {
+    $condition = (is_object($name) && $name instanceof RulesConditionInterface) ? $name : rules_condition($name, $settings);
+    $condition->setParent($this);
+    return $this;
+  }
+
+  /**
+   * Negate this condition.
+   *
+   * @return RulesConditionContainer
+   */
+  public function negate($negate = TRUE) {
+    $this->negate = (bool) $negate;
+    return $this;
+  }
+
+  public function isNegated() {
+    return $this->negate;
+  }
+
+  public function __sleep() {
+    return parent::__sleep() + array('negate' => 'negate');
+  }
+
+  /**
+   * Just return the condition container's result.
+   */
+  protected function returnVariables(RulesState $state, $result = NULL) {
+    return $result;
+  }
+
+  protected function exportChildren($key = NULL) {
+    $key = isset($key) ? $key : strtoupper($this->plugin());
+    return parent::exportChildren($this->negate ? 'NOT ' . $key : $key);
+  }
+
+  protected function importChildren($export, $key = NULL) {
+    $key = isset($key) ? $key : strtoupper($this->plugin());
+    // Care for negated elements.
+    if (!isset($export[$key]) && isset($export['NOT ' . $key])) {
+      $this->negate = TRUE;
+      $key = 'NOT ' . $key;
+    }
+    parent::importChildren($export, $key);
+  }
+
+  /**
+   * Overridden to exclude variable assertions of negated conditions.
+   */
+  protected function stateVariables($element = NULL) {
+    $vars = $this->availableVariables();
+    if (isset($element)) {
+      // Add in variables provided by siblings executed before the element.
+      foreach ($this->children as $child) {
+        if ($child === $element) {
+          break;
+        }
+        $vars += $child->providesVariables();
+        // Take variable info assertions into account.
+        if (!$this->negate && !$child->isNegated() && ($assertions = $child->variableInfoAssertions())) {
+          $vars = RulesData::addMetadataAssertions($vars, $assertions);
+        }
+      }
+    }
+    return $vars;
+  }
+}
+
+/**
+ * The rules default logging class.
+ */
+class RulesLog {
+
+  const INFO  = 1;
+  const WARN  = 2;
+  const ERROR = 3;
+
+  static protected $logger;
+
+  /**
+   * @return RulesLog
+   *   Returns the rules logger instance.
+   */
+  static function logger() {
+    if (!isset(self::$logger)) {
+      $class = __CLASS__;
+      self::$logger = new $class(variable_get('rules_log_level', self::INFO));
+    }
+    return self::$logger;
+  }
+
+  protected $log = array();
+  protected $logLevel, $line = 0;
+
+  /**
+   * This is a singleton.
+   */
+  protected function __construct($logLevel = self::WARN) {
+    $this->logLevel = $logLevel;
+  }
+
+  public function __clone() {
+    throw new Exception("Cannot clone the logger.");
+  }
+
+  /**
+   * Logs a log message.
+   *
+   * @see rules_log()
+   */
+  public function log($msg, $args = array(), $logLevel = self::INFO, $scope = NULL, $path = NULL) {
+    if ($logLevel >= $this->logLevel) {
+      $this->log[] = array($msg, $args, $logLevel, microtime(TRUE), $scope, $path);
+    }
+  }
+
+  /**
+   * Checks the log and throws an exception if there were any problems.
+   */
+  function checkLog($logLevel = self::WARN) {
+    foreach ($this->log as $entry) {
+      if ($entry[2] >= $logLevel) {
+        throw new Exception($this->render());
+      }
+    }
+  }
+
+  /**
+   * Checks the log for (error) messages with a log level equal or higher than the given one.
+   *
+   * @return
+   *   Whether the an error has been logged.
+   */
+  public function hasErrors($logLevel = self::WARN) {
+    foreach ($this->log as $entry) {
+      if ($entry[2] >= $logLevel) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * Gets an array of logged messages.
+   */
+  public function get() {
+    return $this->log;
+  }
+
+  /**
+   * Renders the whole log.
+   */
+  public function render() {
+    $line = 0;
+    $output = array();
+    while (isset($this->log[$line])) {
+      $vars['head'] = t($this->log[$line][0], $this->log[$line][1]);
+      $vars['log'] = $this->renderHelper($line);
+      $output[] = theme('rules_debug_element', $vars);
+      $line++;
+    }
+    return implode('', $output);
+  }
+
+  /**
+   * Renders the log of one event invocation.
+   */
+  protected function renderHelper(&$line = 0) {
+    $startTime = isset($this->log[$line][3]) ? $this->log[$line][3] : 0;
+    $output = array();
+    while ($line < count($this->log)) {
+      if ($output && !empty($this->log[$line][4])) {
+        // The next entry stems from another evaluated set, add in its log
+        // messages here.
+        $vars['head'] = t($this->log[$line][0], $this->log[$line][1]);
+        if (isset($this->log[$line][5])) {
+          $vars['link'] = '[' . l('edit', $this->log[$line][5]) . ']';
+        }
+        $vars['log'] = $this->renderHelper($line);
+        $output[] = theme('rules_debug_element', $vars);
+      }
+      else {
+        $formatted_diff = round(($this->log[$line][3] - $startTime) * 1000, 3) .' ms';
+        $msg = $formatted_diff .' '. t($this->log[$line][0], $this->log[$line][1]);
+        if ($this->log[$line][2] >= RulesLog::WARN) {
+          $level = $this->log[$line][2] == RulesLog::WARN ? 'warn' : 'error';
+          $msg = '<span class="rules-debug-' . $level . '">'. $msg .'</span>';
+        }
+        if (isset($this->log[$line][5]) && !isset($this->log[$line][4])) {
+          $msg .= ' [' . l('edit', $this->log[$line][5]) . ']';
+        }
+        $output[] = $msg;
+
+        if (isset($this->log[$line][4]) && !$this->log[$line][4]) {
+          // This was the last log entry of this set.
+          return theme('item_list', array('items' => $output));
+        }
+      }
+      $line++;
+    }
+    return theme('item_list', array('items' => $output));
+  }
+
+  /**
+   * Clears the logged messages.
+   */
+  public function clear() {
+    $this->log = array();
+  }
+}
+
+/**
+ * A common exception for Rules.
+ *
+ * This class can be used to catch all exceptions thrown by Rules.
+ */
+abstract class RulesException extends Exception {}
+
+/**
+ * An exception that is thrown during evaluation.
+ *
+ * Messages are prepared to be logged to the watchdog, thus not yet translated.
+ *
+ * @see watchdog()
+ */
+class RulesEvaluationException extends RulesException {
+
+  public $msg, $args, $severity, $element, $keys = array();
+
+  /**
+   * @param $msg
+   *   The exception message containing placeholder as t().
+   * @param $args
+   *   Replacement arguments such as for t().
+   * @param $element
+   *   The element of a configuration causing the exception or an array
+   *   consisting of the element and keys specifying a setting value causing
+   *   the exception.
+   * @param $severity
+   *   The RulesLog severity. Defaults to RulesLog::WARN.
+   */
+  function __construct($msg, array $args = array(), $element = NULL, $severity = RulesLog::WARN) {
+    $this->element = is_array($element) ? array_shift($element) : $element;
+    $this->keys = is_array($element) ? $element : array();
+    $this->msg = $msg;
+    $this->args = $args;
+    $this->severity = $severity;
+    // If an error happened, run the integrity check on the rules configuration
+    // and mark it as dirty if it the check fails.
+    if ($severity == RulesLog::ERROR && isset($this->element)) {
+      $rules_config = $this->element->root();
+      rules_config_update_dirty_flag($rules_config);
+      // If we discovered a broken configuration, exclude it in future.
+      if ($rules_config->dirty) {
+        rules_clear_cache();
+      }
+    }
+    // @todo fix _drupal_decode_exception() to use __toString() and override it.
+    $this->message = t($this->msg, $this->args);
+  }
+}
+
+/**
+ * An exception that is thrown for Rules configurations that fail the integrity check.
+ *
+ * @see RulesPlugin::integrityCheck()
+ */
+class RulesIntegrityException extends RulesException {
+
+  public $msg, $element, $keys = array();
+
+  /**
+   * @param string $msg
+   *   The exception message, already translated.
+   * @param $element
+   *   The element of a configuration causing the exception or an array
+   *   consisting of the element and keys specifying a parameter or provided
+   *   variable causing the exception, e.g.
+   *   @code array($element, 'parameter', 'node') @endcode.
+   */
+  function __construct($msg, $element = NULL) {
+    $this->element = is_array($element) ? array_shift($element) : $element;
+    $this->keys = is_array($element) ? $element : array();
+    parent::__construct($msg);
+  }
+}
+
+/**
+ * An exception that is thrown for missing module dependencies.
+ */
+class RulesDependencyException extends RulesIntegrityException {}
+
+/**
+ * Determines the plugin to be used for importing a child element.
+ *
+ * @param $key
+ *   The key to look for, e.g. 'OR' or 'DO'.
+ * @param $default
+ *   The default to return if no special plugin can be found.
+ */
+function _rules_import_get_plugin($key, $default = 'action') {
+  $map = &drupal_static(__FUNCTION__);
+  if (!isset($map)) {
+    $cache = rules_get_cache();
+    foreach ($cache['plugin_info'] as $name => $info) {
+      if (!empty($info['embeddable'])) {
+        $info += array('import keys' => array(strtoupper($name)));
+        foreach ($info['import keys'] as $k) {
+          $map[$k] = $name;
+        }
+      }
+    }
+  }
+  // Cut of any leading NOT from the key.
+  if (strpos($key, 'NOT ') === 0) {
+    $key = substr($key, 4);
+  }
+  if (isset($map[$key])) {
+    return $map[$key];
+  }
+  return $default;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/includes/rules.event.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,411 @@
+<?php
+
+/**
+ * @file
+ * Contains event handler interface and base classes.
+ */
+
+/**
+ * Interface for handling rules events.
+ *
+ * Configurable events (i.e. events making use of settings) have a custom
+ * event suffix, which gets appended to the base event name. The configured
+ * event name of, e.g. the event for viewing an article node, would be
+ * node_view--article, whereas "node_view" is the base event name and "article"
+ * the event suffix as returned from
+ * RulesEventHandlerInterface::getEventNameSuffix(). The event suffix is
+ * generated based upon the event settings and must map to this settings, i.e.
+ * each set of event settings must always generate the same suffix.
+ * For a configurable event to be invoked, rules_invoke_event() has to be called
+ * with the configured event name, e.g.
+ * @code
+ * rules_invoke_event('node_view--' . $node->type, $node, $view_mode);
+ * @endcode
+ * If the event settings are optional, both events have to be invoked whereas
+ * usually the more general event is invoked last. E.g.:
+ * @code
+ * rules_invoke_event('node_view--' . $node->type, $node, $view_mode);
+ * rules_invoke_event('node_view', $node, $view_mode);
+ * @endcode
+ *
+ * Rules event handlers have to be declared using the 'class' key in
+ * hook_rules_event_info(), or may be discovered automatically, see
+ * rules_discover_plugins() for details.
+ *
+ * @see RulesEventHandlerBase
+ * @see RulesEventDefaultHandler
+ */
+interface RulesEventHandlerInterface {
+
+  /**
+   * Constructs the event handler.
+   *
+   * @param string $event_name
+   *   The base event string.
+   * @param array $info
+   *   The event info of the given event.
+   */
+  public function __construct($event_name, $info);
+
+  /**
+   * Sets the event settings.
+   *
+   * @param array $settings
+   *   An array of settings to set.
+   *
+   * @return RulesEventHandlerInterface
+   *   The handler itself for chaining.
+   */
+  public function setSettings(array $settings);
+
+  /**
+   * Gets the event settings.
+   *
+   * @return array
+   *   The array of settings.
+   */
+  public function getSettings();
+
+  /**
+   * Returns an array of default settings.
+   *
+   * @return array
+   */
+  public function getDefaults();
+
+  /**
+   * Returns a user-facing summary of the settings.
+   *
+   * @return string
+   *   The summary in HTML, i.e. properly escaped or filtered.
+   */
+  public function summary();
+
+  /**
+   * Builds the event settings form.
+   *
+   * @param array $form_state
+   *   An associative array containing the current state of the form.
+   *
+   * @return array
+   *   The form structure.
+   */
+  public function buildForm(array &$form_state);
+
+  /**
+   * Validate the event settings independent from a form submission.
+   *
+   * @throws RulesIntegrityException
+   *   In case of validation errors, RulesIntegrityExceptions are thrown.
+   */
+  public function validate();
+
+  /**
+   * Extract the form values and update the event settings.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param array $form_state
+   *   An associative array containing the current state of the form.
+   */
+  public function extractFormValues(array &$form, array &$form_state);
+
+  /**
+   * Returns the suffix to be added to the base event named based upon settings.
+   *
+   * If event settings are used, the event name Rules uses for the configured
+   * event is {EVENT_NAME}--{SUFFIX}.
+   *
+   * @return string
+   *   The suffix string. Return an empty string for not appending a suffix.
+   */
+  public function getEventNameSuffix();
+
+  /**
+   * Returns info about the variables provided by this event.
+   *
+   * @return array
+   *   An array of provided variables, keyed by variable names and with the
+   *   variable info array as value.
+   */
+  public function availableVariables();
+
+  /**
+   * Returns the base name of the event the event handler belongs to.
+   *
+   * @return string
+   *   The name of the event the event handler belongs to.
+   */
+  public function getEventName();
+
+  /**
+   * Returns the info array of the event the event handler belongs to.
+   *
+   * @return string
+   *   The info array of the event the event handler belongs to.
+   */
+  public function getEventInfo();
+}
+
+/**
+ * Interface for event dispatchers.
+ */
+interface RulesEventDispatcherInterface extends RulesEventHandlerInterface {
+
+  /**
+   * Starts the event watcher.
+   */
+  public function startWatching();
+
+  /**
+   * Stops the event watcher.
+   */
+  public function stopWatching();
+
+  /**
+   * Returns whether the event dispatcher is currently active.
+   *
+   * @return bool
+   *   TRUE if the event dispatcher is currently active, FALSE otherwise.
+   */
+  public function isWatching();
+}
+
+/**
+ * Base class for event handler.
+ */
+abstract class RulesEventHandlerBase implements RulesEventHandlerInterface {
+
+  /**
+   * The event name.
+   *
+   * @var string
+   */
+  protected $eventName;
+
+  /**
+   * The event info.
+   *
+   * @var array
+   */
+  protected $eventInfo;
+
+  /**
+   * The event settings.
+   *
+   * @var array
+   */
+  protected $settings = array();
+
+  /**
+   * Implements RulesEventHandlerInterface::__construct()
+   */
+  public function __construct($event_name, $info) {
+    $this->eventName = $event_name;
+    $this->eventInfo = $info;
+    $this->settings = $this->getDefaults();
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::getSettings()
+   */
+  public function getSettings() {
+    return $this->settings;
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::setSettings()
+   */
+  public function setSettings(array $settings) {
+    $this->settings = $settings + $this->getDefaults();
+    return $this;
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::validate()
+   */
+  public function validate() {
+    // Nothing to check by default.
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::extractFormValues()
+   */
+  public function extractFormValues(array &$form, array &$form_state) {
+    foreach ($this->getDefaults() as $key => $setting) {
+      $this->settings[$key] = isset($form_state['values'][$key]) ? $form_state['values'][$key] : $setting;
+    }
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::availableVariables()
+   */
+  public function availableVariables() {
+    return isset($this->eventInfo['variables']) ? $this->eventInfo['variables'] : array();
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::getEventName()
+   */
+  public function getEventName() {
+    return $this->eventName;
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::getEventInfo()
+   */
+  public function getEventInfo() {
+    return $this->eventInfo;
+  }
+}
+
+/**
+ * A handler for events having no settings. This is the default handler.
+ */
+class RulesEventDefaultHandler extends RulesEventHandlerBase  {
+
+  /**
+   * Implements RulesEventHandlerInterface::buildForm()
+   */
+  public function buildForm(array &$form_state) {
+    return array();
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::getConfiguredEventName()
+   */
+  public function getEventNameSuffix() {
+    return '';
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::summary()
+   */
+  public function summary() {
+    return check_plain($this->eventInfo['label']);
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::getDefaults()
+   */
+  public function getDefaults() {
+    return array();
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::getSettings()
+   */
+  public function getSettings() {
+    return NULL;
+  }
+}
+
+/**
+ * Exposes the bundle of an entity as event setting.
+ */
+class RulesEventHandlerEntityBundle extends RulesEventHandlerBase {
+
+  protected $entityType, $entityInfo, $bundleKey;
+
+  /**
+   * Implements RulesEventHandlerInterface::__construct()
+   */
+  public function __construct($event_name, $info) {
+    parent::__construct($event_name, $info);
+    // Cut off the suffix, e.g. remove 'view' from node_view.
+    $this->entityType = implode('_', explode('_', $event_name, -1));
+    $this->entityInfo = entity_get_info($this->entityType);
+    if (!$this->entityInfo) {
+      throw new InvalidArgumentException('Unsupported event name passed.');
+    }
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::summary()
+   */
+  public function summary() {
+    $bundle = &$this->settings['bundle'];
+    $bundle_label = isset($this->entityInfo['bundles'][$bundle]['label']) ? $this->entityInfo['bundles'][$bundle]['label'] : $bundle;
+    $suffix = isset($bundle) ? ' ' . t('of @bundle-key %name', array('@bundle-key' => $this->getBundlePropertyLabel(), '%name' => $bundle_label)) : '';
+    return check_plain($this->eventInfo['label']) . $suffix;
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::buildForm()
+   */
+  public function buildForm(array &$form_state) {
+    $form['bundle'] = array(
+      '#type' => 'select',
+      '#title' => t('Restrict by @bundle', array('@bundle' => $this->getBundlePropertyLabel())),
+      '#description' => t('If you need to filter for multiple values, either add multiple events or use the "Entity is of bundle" condition instead.'),
+      '#default_value' => $this->settings['bundle'],
+      '#empty_value' => '',
+    );
+    foreach ($this->entityInfo['bundles'] as $name => $bundle_info) {
+      $form['bundle']['#options'][$name] = $bundle_info['label'];
+    }
+    return $form;
+  }
+
+  /**
+   * Returns the label to use for the bundle property.
+   *
+   * @return string
+   */
+  protected function getBundlePropertyLabel() {
+    return $this->entityInfo['entity keys']['bundle'];
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::extractFormValues()
+   */
+  public function extractFormValues(array &$form, array &$form_state) {
+    $this->settings['bundle'] = !empty($form_state['values']['bundle']) ? $form_state['values']['bundle'] : NULL;
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::validate()
+   */
+  public function validate() {
+    if ($this->settings['bundle'] && empty($this->entityInfo['bundles'][$this->settings['bundle']])) {
+      throw new RulesIntegrityException(t('The @bundle %bundle of %entity_type is not known.',
+        array(
+          '%bundle' => $this->settings['bundle'],
+          '%entity_type' => $this->entityInfo['label'],
+          '@bundle' => $this->getBundlePropertyLabel(),
+      )), array(NULL, 'bundle'));
+    }
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::getConfiguredEventName()
+   */
+  public function getEventNameSuffix() {
+    return $this->settings['bundle'];
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::getDefaults()
+   */
+  public function getDefaults() {
+    return array(
+      'bundle' => NULL,
+    );
+  }
+
+  /**
+   * Implements RulesEventHandlerInterface::availableVariables()
+   */
+  public function availableVariables() {
+    $variables = $this->eventInfo['variables'];
+    if ($this->settings['bundle']) {
+      // Add the bundle to all variables of the entity type.
+      foreach ($variables as $name => $variable_info) {
+        if ($variable_info['type'] == $this->entityType) {
+          $variables[$name]['bundle'] = $this->settings['bundle'];
+        }
+      }
+    }
+    return $variables;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/includes/rules.plugins.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,827 @@
+<?php
+
+/**
+ * @file Contains plugin info and implementations not needed for rule evaluation.
+ */
+
+
+/**
+ * Implements a rules action.
+ */
+class RulesAction extends RulesAbstractPlugin implements RulesActionInterface {
+
+  protected $itemName = 'action';
+
+  /**
+   * Execute the callback and update/save data as specified by the action.
+   */
+  protected function executeCallback(array $args, RulesState $state = NULL) {
+    rules_log('Evaluating the action %name.', array('%name' => $this->elementName), RulesLog::INFO, $this);
+    $return = $this->__call('execute', empty($this->info['named parameter']) ? $args : array($args));
+    // Get the (partially) wrapped arguments.
+    $args = $state->currentArguments;
+
+    if (is_array($return)) {
+      foreach ($return as $name => $data) {
+        // Add provided variables.
+        if (isset($this->info['provides'][$name])) {
+          $var_name = isset($this->settings[$name . ':var']) ? $this->settings[$name . ':var'] : $name;
+          if (!$state->varInfo($var_name)) {
+            $state->addVariable($var_name, $data, $this->info['provides'][$name]);
+            rules_log('Added the provided variable %name of type %type', array('%name' => $var_name, '%type' => $this->info['provides'][$name]['type']), RulesLog::INFO, $this);
+            if (!empty($this->info['provides'][$name]['save']) && $state->variables[$var_name] instanceof EntityMetadataWrapper) {
+              $state->saveChanges($var_name, $state->variables[$var_name]);
+            }
+          }
+        }
+        // Support updating variables by returning the values.
+        elseif (!isset($this->info['provides'][$name])) {
+          // Update the data value using the wrapper.
+          if (isset($args[$name]) && $args[$name] instanceof EntityMetadataWrapper) {
+            try {
+              $args[$name]->set($data);
+            }
+            catch (EntityMetadataWrapperException $e) {
+              throw new RulesEvaluationException('Unable to update the argument for parameter %name: %error', array('%name' => $name, '%error' => $e->getMessage()), $this);
+            }
+          }
+          elseif (array_key_exists($name, $args)) {
+            // Map back to the source variable name and update it.
+            $var_name = !empty($this->settings[$name . ':select']) ? str_replace('-', '_', $this->settings[$name . ':select']) : $name;
+            $state->variables[$var_name] = $data;
+          }
+        }
+      }
+    }
+    // Save parameters as defined in the parameter info.
+    if ($return !== FALSE) {
+      foreach ($this->info['parameter'] as $name => $info) {
+        if (!empty($info['save']) && $args[$name] instanceof EntityMetadataWrapper) {
+          if (isset($this->settings[$name . ':select'])) {
+            $state->saveChanges($this->settings[$name . ':select'], $args[$name]);
+          }
+          else {
+            // Wrapper has been configured via direct input, so just save.
+            rules_log('Saved argument of type %type for parameter %name.', array('%name' => $name, '%type' => $args[$name]->type()));
+            $args[$name]->save();
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements a rules condition.
+ */
+class RulesCondition extends RulesAbstractPlugin implements RulesConditionInterface {
+
+  protected $itemName = 'condition';
+  protected $negate = FALSE;
+
+  public function providesVariables() {
+    return array();
+  }
+
+  public function negate($negate = TRUE) {
+    $this->negate = (bool) $negate;
+    return $this;
+  }
+
+  public function isNegated() {
+    return $this->negate;
+  }
+
+  protected function executeCallback(array $args, RulesState $state = NULL) {
+    $return = (bool) $this->__call('execute', empty($this->info['named parameter']) ? $args : array($args));
+    rules_log('The condition %name evaluated to %bool', array('%name' => $this->elementName, '%bool' => $return ? 'TRUE' : 'FALSE'), RulesLog::INFO, $this);
+    return $this->negate ? !$return : $return;
+  }
+
+  public function __sleep() {
+    return parent::__sleep() + array('negate' => 'negate');
+  }
+
+  /**
+   * Just return the boolean result.
+   */
+  protected function returnVariables(RulesState $state, $result = NULL) {
+    return $result;
+  }
+
+  protected function exportToArray() {
+    $not = $this->negate ? 'NOT ' : '';
+    $export = $this->exportSettings();
+    // Abbreviate the export making "USING" implicit.
+    return array($not . $this->elementName => isset($export['USING']) ? $export['USING'] : array());
+  }
+
+  public function import(array $export) {
+    $this->elementName = rules_array_key($export);
+    if (strpos($this->elementName, 'NOT ') === 0) {
+      $this->elementName = substr($this->elementName, 4);
+      $this->negate = TRUE;
+    }
+    // After setting the element name, setup the element again so the right
+    // element info is loaded.
+    $this->setUp();
+
+    // Re-add 'USING' which has been removed for abbreviation.
+    $this->importSettings(array('USING' => reset($export)));
+  }
+
+  public function label() {
+    $label = parent::label();
+    return $this->negate ? t('NOT @condition', array('@condition' => $label)) : $label;
+  }
+}
+
+/**
+ * An actual rule.
+ * Note: A rule also implements the RulesActionInterface (inherited).
+ */
+class Rule extends RulesActionContainer {
+
+  protected $conditions = NULL;
+  protected $itemName = 'rule';
+
+  public $label = 'unlabeled';
+
+  public function __construct($variables = array(), $providesVars = array()) {
+    parent::__construct($variables, $providesVars);
+
+    // Initialize the conditions container.
+    if (!isset($this->conditions)) {
+      $this->conditions = rules_and();
+      // Don't use setParent() to avoid having it added to the children.
+      $this->conditions->parent = $this;
+    }
+  }
+
+  /**
+   * Get an iterator over all contained conditions. Note that this iterator also
+   * implements the ArrayAcces interface.
+   *
+   * @return RulesRecursiveElementIterator
+   */
+  public function conditions() {
+    return $this->conditions->getIterator();
+  }
+
+  /**
+   * Returns the "And" condition container, which contains all conditions of
+   * this rule.
+   *
+   * @return RulesAnd
+   */
+  public function conditionContainer() {
+    return $this->conditions;
+  }
+
+  public function __sleep() {
+    return parent::__sleep() + drupal_map_assoc(array('conditions', 'label'));
+  }
+
+  /**
+   * Get an iterator over all contained actions. Note that this iterator also
+   * implements the ArrayAccess interface.
+   *
+   * @return RulesRecursiveElementIterator
+   */
+  public function actions() {
+    return parent::getIterator();
+  }
+
+  /**
+   * Add a condition. Pass either an instance of the RulesConditionInterface
+   * or the arguments as needed by rules_condition().
+   *
+   * @return Rule
+   *   Returns $this to support chained usage.
+   */
+  public function condition($name, $settings = array()) {
+    $this->conditions->condition($name, $settings);
+    return $this;
+  }
+
+  public function sortChildren($deep = FALSE) {
+    $this->conditions->sortChildren($deep);
+    parent::sortChildren($deep);
+  }
+
+  public function evaluate(RulesState $state) {
+    rules_log('Evaluating conditions of rule %label.', array('%label' => $this->label), RulesLog::INFO, $this);
+    if ($this->conditions->evaluate($state)) {
+      rules_log('Rule %label fires.', array('%label' => $this->label), RulesLog::INFO, $this, TRUE);
+      parent::evaluate($state);
+      rules_log('Rule %label has fired.', array('%label' => $this->label), RulesLog::INFO, $this, FALSE);
+    }
+  }
+
+  /**
+   * Fires the rule, i.e. evaluates the rule without checking its conditions.
+   *
+   * @see RulesPlugin::evaluate()
+   */
+  public function fire(RulesState $state) {
+    rules_log('Firing rule %label.', array('%label' => $this->label), RulesLog::INFO, $this);
+    parent::evaluate($state);
+  }
+
+  public function integrityCheck() {
+    parent::integrityCheck();
+    $this->conditions->integrityCheck();
+    return $this;
+  }
+
+  public function access() {
+    return (!isset($this->conditions) || $this->conditions->access()) && parent::access();
+  }
+
+  public function dependencies() {
+    return array_keys(array_flip($this->conditions->dependencies()) + array_flip(parent::dependencies()));
+  }
+
+  public function destroy() {
+    $this->conditions->destroy();
+    parent::destroy();
+  }
+
+  /**
+   * @return RulesRecursiveElementIterator
+   */
+  public function getIterator() {
+    $array = array_merge(array($this->conditions), $this->children);
+    return new RulesRecursiveElementIterator($array);
+  }
+
+  protected function stateVariables($element = NULL) {
+    // Don't add in provided action variables for the conditions.
+    if (isset($element) && $element === $this->conditions) {
+      return $this->availableVariables();
+    }
+    $vars = parent::stateVariables($element);
+    // Take variable info assertions of conditions into account.
+    if ($assertions = $this->conditions->variableInfoAssertions()) {
+      $vars = RulesData::addMetadataAssertions($vars, $assertions);
+    }
+    return $vars;
+  }
+
+  protected function exportFlat() {
+    return $this->isRoot();
+  }
+
+  protected function exportToArray() {
+    $export = parent::exportToArray();
+    if (!$this->isRoot()) {
+      $export[strtoupper($this->plugin())]['LABEL'] = $this->label;
+    }
+    return $export;
+  }
+
+  protected function exportChildren($key = NULL) {
+    $export = array();
+    if ($this->conditions->children) {
+      $export = $this->conditions->exportChildren('IF');
+    }
+    return $export + parent::exportChildren('DO');
+  }
+
+  public function import(array $export) {
+    if (!$this->isRoot() && isset($export[strtoupper($this->plugin())]['LABEL'])) {
+      $this->label = $export[strtoupper($this->plugin())]['LABEL'];
+    }
+    parent::import($export);
+  }
+
+  protected function importChildren($export, $key = NULL) {
+    if (!empty($export['IF'])) {
+      $this->conditions->importChildren($export, 'IF');
+    }
+    parent::importChildren($export, 'DO');
+  }
+
+  public function __clone() {
+    parent::__clone();
+    $this->conditions = clone $this->conditions;
+    $this->conditions->parent = $this;
+  }
+
+  /**
+   * Rules may not provided any variable info assertions, as Rules are only
+   * conditionally executed.
+   */
+  protected function variableInfoAssertions() {
+    return array();
+  }
+
+  /**
+   * Overridden to ensure the whole Rule is deleted at once.
+   */
+  public function delete($keep_children = FALSE) {
+    parent::delete($keep_children);
+  }
+
+  /**
+   * Overriden to expose the variables of all actions for embedded rules.
+   */
+  public function providesVariables() {
+    $provides = parent::providesVariables();
+    if (!$this->isRoot()) {
+      foreach ($this->actions() as $action) {
+        $provides += $action->providesVariables();
+      }
+    }
+    return $provides;
+  }
+
+  public function resetInternalCache() {
+    parent::resetInternalCache();
+    $this->conditions->resetInternalCache();
+  }
+}
+
+/**
+ * Represents rules getting triggered by events.
+ */
+class RulesReactionRule extends Rule implements RulesTriggerableInterface {
+
+  protected $itemName = 'reaction rule';
+  protected $events = array(), $eventSettings = array();
+
+  /**
+   * Implements RulesTriggerableInterface::events().
+   */
+  public function events() {
+    return $this->events;
+  }
+
+  /**
+   * Implements RulesTriggerableInterface::removeEvent().
+   */
+  public function removeEvent($event) {
+    if (($id = array_search($event, $this->events)) !== FALSE) {
+      unset($this->events[$id]);
+    }
+    return $this;
+  }
+
+  /**
+   * Implements RulesTriggerableInterface::event().
+   */
+  public function event($event_name, array $settings = NULL) {
+    // Process any settings and determine the configured event's name.
+    if ($settings) {
+      $handler = rules_get_event_handler($event_name, $settings);
+      if ($suffix = $handler->getEventNameSuffix()) {
+        $event_name .= '--' . $suffix;
+        $this->eventSettings[$event_name] = $settings;
+      }
+      else {
+        // Do not store settings if there is no suffix.
+        unset($this->eventSettings[$event_name]);
+      }
+    }
+    if (array_search($event_name, $this->events) === FALSE) {
+      $this->events[] = $event_name;
+    }
+    return $this;
+  }
+
+  /**
+   * Implements RulesTriggerableInterface::getEventSettings().
+   */
+  public function getEventSettings($event_name) {
+    if (isset($this->eventSettings[$event_name])) {
+      return $this->eventSettings[$event_name];
+    }
+  }
+
+  public function integrityCheck() {
+    parent::integrityCheck();
+    // Check integrity of the configured events.
+    foreach ($this->events as $event_name) {
+      $handler = rules_get_event_handler($event_name, $this->getEventSettings($event_name));
+      $handler->validate();
+    }
+    return $this;
+  }
+
+  /**
+   * Reaction rules can't add variables to the parent scope, so clone $state.
+   */
+  public function evaluate(RulesState $state) {
+    // Implement recursion prevention for reaction rules.
+    if ($state->isBlocked($this)) {
+      return rules_log('Not evaluating @plugin %label to prevent recursion.', array('%label' => $this->label(), '@plugin' => $this->plugin()), RulesLog::INFO, $this);
+    }
+    $state->block($this);
+    $copy = clone $state;
+    parent::evaluate($copy);
+    $state->unblock($this);
+  }
+
+  public function access() {
+    foreach ($this->events as $event_name) {
+      $event_info = rules_get_event_info($event_name);
+      if (!empty($event_info['access callback']) && !call_user_func($event_info['access callback'], 'event', $event_info['name'])) {
+        return FALSE;
+      }
+    }
+    return parent::access();
+  }
+
+  public function dependencies() {
+    $modules = array_flip(parent::dependencies());
+    foreach ($this->events as $event_name) {
+      $event_info = rules_get_event_info($event_name);
+      if (isset($event_info['module'])) {
+        $modules[$event_info['module']] = TRUE;
+      }
+    }
+    return array_keys($modules);
+  }
+
+  public function providesVariables() {
+    return array();
+  }
+
+  public function parameterInfo($optional = FALSE) {
+    // If executed directly, all variables as defined by the event need to
+    // be passed.
+    return rules_filter_array($this->availableVariables(), 'handler', FALSE);
+  }
+
+  public function availableVariables() {
+    if (!isset($this->availableVariables)) {
+      if (isset($this->parent)) {
+        // Return the event variables provided by the event set, once cached.
+        $this->availableVariables = $this->parent->stateVariables();
+      }
+      else {
+        // The intersection of the variables provided by the events are
+        // available.
+        foreach ($this->events as $event_name) {
+          $handler = rules_get_event_handler($event_name, $this->getEventSettings($event_name));
+
+          if (isset($this->availableVariables)) {
+            $event_vars = $handler->availableVariables();
+            // Merge variable info by intersecting the variable-info keys also,
+            // so we have only metadata available that is valid for all of the
+            // provided variables.
+            foreach (array_intersect_key($this->availableVariables, $event_vars) as $name => $variable_info) {
+              $this->availableVariables[$name] = array_intersect_key($variable_info, $event_vars[$name]);
+            }
+          }
+          else {
+            $this->availableVariables = $handler->availableVariables();
+          }
+        }
+        $this->availableVariables = isset($this->availableVariables) ? RulesState::defaultVariables() + $this->availableVariables : RulesState::defaultVariables();
+      }
+    }
+    return $this->availableVariables;
+  }
+
+  public function __sleep() {
+    return parent::__sleep() + drupal_map_assoc(array('events', 'eventSettings'));
+  }
+
+  protected function exportChildren($key = 'ON') {
+    foreach ($this->events as $event_name) {
+      $export[$key][$event_name] = (array) $this->getEventSettings($event_name);
+    }
+    return $export + parent::exportChildren();
+  }
+
+  protected function importChildren($export, $key = 'ON') {
+    // Detect and support old-style exports: a numerically indexed array of
+    // event names.
+    if (is_string(reset($export[$key])) && is_numeric(key($export[$key]))) {
+      $this->events = $export[$key];
+    }
+    else {
+      $this->events = array_keys($export[$key]);
+      $this->eventSettings = array_filter($export[$key]);
+    }
+    parent::importChildren($export);
+  }
+
+  /**
+   * Overrides optimize().
+   */
+  public function optimize() {
+    parent::optimize();
+    // No need to keep event settings for evaluation.
+    $this->eventSettings = array();
+  }
+}
+
+/**
+ * A logical AND.
+ */
+class RulesAnd extends RulesConditionContainer {
+
+  protected $itemName = 'and';
+
+  public function evaluate(RulesState $state) {
+    foreach ($this->children as $condition) {
+      if (!$condition->evaluate($state)) {
+        rules_log('AND evaluated to FALSE.');
+        return $this->negate;
+      }
+    }
+    rules_log('AND evaluated to TRUE.');
+    return !$this->negate;
+  }
+
+  public function label() {
+    return !empty($this->label) ? $this->label : ($this->negate ? t('NOT AND') : t('AND'));
+  }
+}
+
+/**
+ * A logical OR.
+ */
+class RulesOr extends RulesConditionContainer {
+
+  protected $itemName = 'or';
+
+  public function evaluate(RulesState $state) {
+    foreach ($this->children as $condition) {
+      if ($condition->evaluate($state)) {
+        rules_log('OR evaluated to TRUE.');
+        return !$this->negate;
+      }
+    }
+    rules_log('OR evaluated to FALSE.');
+    return $this->negate;
+  }
+
+  public function label() {
+    return !empty($this->label) ? $this->label : ($this->negate ? t('NOT OR') : t('OR'));
+  }
+
+  /**
+   * Overridden to exclude all variable assertions as in an OR we cannot assert
+   * the children are successfully evaluated.
+   */
+  protected function stateVariables($element = NULL) {
+    $vars = $this->availableVariables();
+    if (isset($element)) {
+      // Add in variables provided by siblings executed before the element.
+      foreach ($this->children as $child) {
+        if ($child === $element) {
+          break;
+        }
+        $vars += $child->providesVariables();
+      }
+    }
+    return $vars;
+  }
+}
+
+/**
+ * A loop element.
+ */
+class RulesLoop extends RulesActionContainer {
+
+  protected $itemName = 'loop';
+  protected $listItemInfo;
+
+  public function __construct($settings = array(), $variables = NULL) {
+    $this->setUp();
+    $this->settings = (array) $settings + array(
+      'item:var' => 'list_item',
+      'item:label' => t('Current list item'),
+    );
+    if (!empty($variables)) {
+      $this->info['variables'] = $variables;
+    }
+  }
+
+  public function pluginParameterInfo() {
+    $info['list'] = array(
+      'type' => 'list',
+      'restriction' => 'selector',
+      'label' => t('List'),
+      'description' => t('The list to loop over. The loop will step through each item in the list, allowing further actions on them. See <a href="@url"> the online handbook</a> for more information on how to use loops.',
+        array('@url' => rules_external_help('loops'))),
+    );
+    return $info;
+  }
+
+  public function integrityCheck() {
+    parent::integrityCheck();
+    $this->checkVarName($this->settings['item:var']);
+  }
+
+  public function listItemInfo() {
+    if (!isset($this->listItemInfo)) {
+      if ($info = $this->getArgumentInfo('list')) {
+        // Pass through the variable info keys like property info.
+        $this->listItemInfo = array_intersect_key($info, array_flip(array('type', 'property info', 'bundle')));
+        $this->listItemInfo['type'] = isset($info['type']) ? entity_property_list_extract_type($info['type']) : 'unknown';
+      }
+      else {
+        $this->listItemInfo = array('type' => 'unknown');
+      }
+      $this->listItemInfo['label'] = $this->settings['item:label'];
+    }
+    return $this->listItemInfo;
+  }
+
+  public function evaluate(RulesState $state) {
+    try {
+      $param_info = $this->pluginParameterInfo();
+      $list = $this->getArgument('list', $param_info['list'], $state);
+      $item_var_info = $this->listItemInfo();
+      $item_var_name = $this->settings['item:var'];
+
+      if (isset($this->settings['list:select'])) {
+        rules_log('Looping over the list items of %selector', array('%selector' => $this->settings['list:select']), RulesLog::INFO, $this);
+      }
+
+      // Loop over the list and evaluate the children for each list item.
+      foreach ($list as $key => $item) {
+        // Use a separate state so variables are available in the loop only.
+        $state2 = clone $state;
+        $state2->addVariable($item_var_name, $list[$key], $item_var_info);
+        parent::evaluate($state2);
+
+        // Update variables from parent scope.
+        foreach ($state->variables as $var_key => &$var_value) {
+          if (array_key_exists($var_key, $state2->variables)) {
+            $var_value = $state2->variables[$var_key];
+          }
+        }
+      }
+    }
+    catch (RulesEvaluationException $e) {
+      rules_log($e->msg, $e->args, $e->severity);
+      rules_log('Unable to evaluate %name.', array('%name' => $this->getPluginName()), RulesLog::WARN, $this);
+    }
+  }
+
+  protected function stateVariables($element = NULL) {
+    return array($this->settings['item:var'] => $this->listItemInfo()) + parent::stateVariables($element);
+  }
+
+  public function label() {
+    return !empty($this->label) ? $this->label : t('Loop');
+  }
+
+  protected function exportChildren($key = 'DO') {
+    return parent::exportChildren($key);
+  }
+
+  protected function importChildren($export, $key = 'DO') {
+    parent::importChildren($export, $key);
+  }
+
+  protected function exportSettings() {
+    $export = parent::exportSettings();
+    $export['ITEM'][$this->settings['item:var']] = $this->settings['item:label'];
+    return $export;
+  }
+
+  protected function importSettings($export) {
+    parent::importSettings($export);
+    if (isset($export['ITEM'])) {
+      $this->settings['item:var'] = rules_array_key($export['ITEM']);
+      $this->settings['item:label'] = reset($export['ITEM']);
+    }
+  }
+}
+
+/**
+ * An action set component.
+ */
+class RulesActionSet extends RulesActionContainer {
+
+  protected $itemName = 'action set';
+
+}
+
+/**
+ * A set of rules to execute upon defined variables.
+ */
+class RulesRuleSet extends RulesActionContainer {
+
+  protected $itemName = 'rule set';
+
+  /**
+   * @return RulesRuleSet
+   */
+  public function rule($rule) {
+    return $this->action($rule);
+  }
+
+  protected function exportChildren($key = 'RULES') {
+    return parent::exportChildren($key);
+  }
+
+  protected function importChildren($export, $key = 'RULES') {
+    parent::importChildren($export, $key);
+  }
+}
+
+/**
+ * This class is used for caching the rules to be evaluated per event.
+ */
+class RulesEventSet extends RulesRuleSet {
+
+  protected $itemName = 'event set';
+  // Event sets may recurse as we block recursions on rule-level.
+  public $recursion = TRUE;
+
+  public function __construct($info = array()) {
+    $this->setup();
+    $this->info = $info;
+  }
+
+  public function executeByArgs($args = array()) {
+    rules_log('Reacting on event %label.', array('%label' => $this->info['label']), RulesLog::INFO, NULL, TRUE);
+    $state = $this->setUpState($args);
+    module_invoke_all('rules_config_execute', $this);
+    $this->evaluate($state);
+    $state->cleanUp($this);
+    rules_log('Finished reacting on event %label.', array('%label' => $this->info['label']), RulesLog::INFO, NULL, FALSE);
+  }
+
+  /**
+   * Cache event-sets per event to allow efficient usage via rules_invoke_event().
+   *
+   * @see rules_get_cache()
+   * @see rules_invoke_event()
+   */
+  public static function rebuildEventCache() {
+    // Set up the per-event cache.
+    $events = rules_fetch_data('event_info');
+    $sets = array();
+    // Add all rules associated with this event to an EventSet for caching.
+    $rules = rules_config_load_multiple(FALSE, array('plugin' => 'reaction rule', 'active' => TRUE));
+
+    foreach ($rules as $name => $rule) {
+      foreach ($rule->events() as $event_name) {
+        $event_base_name = rules_get_event_base_name($event_name);
+        // Skip not defined events.
+        if (empty($events[$event_base_name])) {
+          continue;
+        }
+        // Create an event set if not yet done.
+        if (!isset($sets[$event_name])) {
+          $handler = rules_get_event_handler($event_name, $rule->getEventSettings($event_name));
+
+          // Start the event dispatcher for this event, if any.
+          if ($handler instanceof RulesEventDispatcherInterface && !$handler->isWatching()) {
+            $handler->startWatching();
+          }
+
+          // Update the event info with the variables available based on the
+          // event settings.
+          $event_info = $events[$event_base_name];
+          $event_info['variables'] = $handler->availableVariables();
+          $sets[$event_name] = new RulesEventSet($event_info);
+          $sets[$event_name]->name = $event_name;
+        }
+
+        // If a rule is marked as dirty, check if this still applies.
+        if ($rule->dirty) {
+          rules_config_update_dirty_flag($rule);
+        }
+        if (!$rule->dirty) {
+          // Clone the rule to avoid modules getting the changed version from
+          // the static cache.
+          $sets[$event_name]->rule(clone $rule);
+        }
+      }
+    }
+
+    // Create cache items for all created sets.
+    foreach ($sets as $event_name => $set) {
+      $set->sortChildren();
+      $set->optimize();
+      // Allow modules to alter the cached event set.
+      drupal_alter('rules_event_set', $event_name, $set);
+      rules_set_cache('event_' . $event_name, $set);
+    }
+    // Cache a whitelist of configured events so we can use it to speed up later
+    // calls. See rules_invoke_event().
+    variable_set('rules_event_whitelist', array_flip(array_keys($sets)));
+  }
+
+  protected function stateVariables($element = NULL) {
+    return $this->availableVariables();
+  }
+
+  /**
+   * Do not save since this class is for caching purposes only.
+   *
+   * @see RulesPlugin::save()
+   */
+  public function save($name = NULL, $module = 'rules') {
+    return FALSE;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/includes/rules.processor.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,364 @@
+<?php
+
+/**
+ * @file Contains classes for data processing.
+ *
+ * Data processors can be used to process element arguments on evaluation time,
+ * e.g. to apply input evaluators or to apply simple calculations to number
+ * arguments.
+ */
+
+/**
+ * Common base class for Rules data processors.
+ */
+abstract class RulesDataProcessor {
+
+  /**
+   * The processors' setting value.
+   */
+  protected $setting = NULL;
+
+  /**
+   * Allows chaining processors. If set, the next processor to invoke.
+   */
+  protected $processor = NULL;
+
+  /**
+   * Constructor.
+   */
+  protected function __construct($setting, $param_info, $var_info = array(), $processor = NULL) {
+    $this->setting = $setting;
+    $this->processor = $processor;
+  }
+
+  /**
+   * Return $this or skip this processor by returning the next processor.
+   */
+  protected function getPreparedValue() {
+    return isset($this->setting) && array_filter($this->setting) ? $this : $this->processor;
+  }
+
+  /**
+   * Returns whether the current user has permission to edit this chain of data
+   * processors.
+   */
+  public function editAccess() {
+    return $this->access() && (!isset($this->processor) || $this->processor->editAccess());
+  }
+
+
+  /**
+   * Prepares the processor for parameters.
+   *
+   * It turns the settings into a suiting processor object, which gets invoked
+   * on evaluation time.
+   *
+   * @param $setting
+   *   The processor settings which are to be prepared.
+   * @param $param_info
+   *   The info about the parameter to prepare the processor for.
+   * @param $var_info
+   *   An array of info about the available variables.
+   */
+  public static function prepareSetting(&$setting, $param_info, $var_info = array()) {
+    $processor = NULL;
+    foreach (self::processors($param_info, FALSE) as $name => $info) {
+      if (!empty($setting[$name])) {
+        $object = new $info['class']($setting[$name], $param_info, $var_info, $processor);
+        $processor = $object->getPreparedValue();
+      }
+    }
+    $setting = $processor;
+  }
+
+  /**
+   * Attaches the form of applicable data processors.
+   */
+  public static function attachForm(&$form, $settings, $param_info, $var_info, $access_check = TRUE) {
+    // If $settings is already prepared get the settings from the processors.
+    if ($settings instanceof RulesDataProcessor) {
+      $settings = $settings->getChainSettings();
+    }
+    foreach (self::processors($param_info, $access_check) as $name => $info) {
+      $settings += array($name => array());
+      $form[$name] = call_user_func(array($info['class'], 'form'), $settings[$name], $var_info);
+      $form[$name]['#weight'] = $info['weight'];
+    }
+  }
+
+  /**
+   * Returns defined data processors applicable for the given parameter.
+   * Optionally also access to the processors is checked.
+   *
+   * @param $param_info
+   *   If given, only processors valid for this parameter are returned.
+   */
+  public static function processors($param_info = NULL, $access_check = TRUE, $hook = 'data_processor_info') {
+    static $items = array();
+
+    if (!isset($items[$hook]['all'])) {
+      $items[$hook]['all'] = rules_fetch_data($hook);
+      uasort($items[$hook]['all'], array(__CLASS__, '_item_sort'));
+    }
+    // Data processing isn't supported for multiple types.
+    if (isset($param_info) && is_array($param_info['type'])) {
+      return array();
+    }
+    // Filter the items by type.
+    if (isset($param_info['type']) && !isset($items[$hook][$param_info['type']])) {
+      $items[$hook][$param_info['type']] = array();
+      foreach ($items[$hook]['all'] as $name => $info) {
+        // Check whether the parameter type matches the supported types.
+        $info += array('type' => 'text');
+        if (RulesData::typesMatch($param_info, $info, FALSE)) {
+          $items[$hook][$param_info['type']][$name] = $info;
+        }
+      }
+    }
+    // Apply the access check.
+    $return = isset($param_info['type']) ? $items[$hook][$param_info['type']] : $items[$hook]['all'];
+    if ($access_check) {
+      foreach ($return as $base => $info) {
+        if (!call_user_func(array($info['class'], 'access'))) {
+          unset($return[$base]);
+        }
+      }
+    }
+    return $return;
+  }
+
+  public static function _item_sort($a, $b) {
+    return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : 0);
+  }
+
+  /**
+   * Gets the settings array for this and all contained chained processors.
+   */
+  public function getChainSettings() {
+    foreach ($this->unchain() as $name => $processor) {
+      $settings[$name] = $processor->getSetting();
+    }
+    return isset($settings) ? $settings : array();
+  }
+
+  /**
+   * Returns an array of modules which we depend on.
+   */
+  public function dependencies() {
+    $used_processor_info = array_intersect_key($this->processors(), $this->unchain());
+    $modules = array();
+    foreach ($used_processor_info as $name => $info) {
+      $modules[] = $info['module'];
+    }
+    return array_filter($modules);
+  }
+
+  /**
+   * @return
+   *   An array of processors keyed by processor name.
+   */
+  protected function unchain() {
+    $processor = $this;
+    while ($processor instanceof RulesDataProcessor) {
+      $processors[get_class($processor)] = $processor;
+      $processor = $processor->processor;
+    }
+    // Note: Don't use the static context to call processors() here as we need a
+    // late binding to invoke the input evaluators version, if needed.
+    $return = array();
+    foreach ($this->processors() as $name => $info) {
+      if (isset($processors[$info['class']])) {
+        $return[$name] = $processors[$info['class']];
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Gets the settings of this processor.
+   */
+  public function getSetting() {
+    return $this->setting;
+  }
+
+  /**
+   * Processes the value. If $this->processor is set, invoke this processor
+   * first so chaining multiple processors is working.
+   *
+   * @param $value
+   *   The value to process.
+   * @param $info
+   *   Info about the parameter for which we process the value.
+   * @param $state RulesState
+   *   The rules evaluation state.
+   * @param $element RulesPlugin
+   *   The element for which we process the value.
+   * @return
+   *   The processed value.
+   */
+  abstract public function process($value, $info, RulesState $state, RulesPlugin $element);
+
+  /**
+   * Return whether the current user has permission to use the processor.
+   */
+  public static function access() {
+    return TRUE;
+  }
+
+  /**
+   * Defines the processor form element.
+   *
+   * @param $settings
+   *   The settings of the processor.
+   * @param $var_info
+   *   An array of info about the available variables.
+   *
+   * @return
+   *   A form element structure.
+   */
+  protected static function form($settings, $var_info) {
+    return array();
+  }
+}
+
+
+/**
+ * A base processor for use as input evaluators. Input evaluators are not listed
+ * in hook_rules_data_processor_info(). Instead they use
+ * hook_rules_evaluator_info() and get attached to input forms.
+ */
+abstract class RulesDataInputEvaluator extends RulesDataProcessor {
+
+  /**
+   * Overridden to invoke prepare().
+   */
+  protected function __construct($setting, $param_info, $var_info = array(), $processor = NULL) {
+    $this->setting = TRUE;
+    $this->processor = $processor;
+    $this->prepare($setting, $var_info, $param_info);
+  }
+
+  /**
+   * Overridden to generate evaluator $options and invoke evaluate().
+   */
+  public function process($value, $info, RulesState $state, RulesPlugin $element, $options = NULL) {
+    $options = isset($options) ? $options : $this->getEvaluatorOptions($info, $state, $element);
+    $value = isset($this->processor) ? $this->processor->process($value, $info, $state, $element, $options) : $value;
+    return $this->evaluate($value, $options, $state);
+  }
+
+  /**
+   * Generates the evaluator $options.
+   */
+  protected function getEvaluatorOptions($info, $state, $element) {
+    $cache = rules_get_cache();
+    $languages = language_list();
+    $info += array(
+      'cleaning callback' => isset($cache['data info'][$info['type']]['cleaning callback']) ? $cache['data info'][$info['type']]['cleaning callback'] : FALSE,
+      'sanitize' => FALSE,
+    );
+    $options = array_filter(array(
+      'language' => $info['#langcode'] != LANGUAGE_NONE && isset($languages[$info['#langcode']]) ? $languages[$info['#langcode']] : NULL,
+      'callback' => $info['cleaning callback'],
+      'sanitize' => $info['sanitize'],
+    ));
+    return $options;
+  }
+
+  /**
+   * Overriden to prepare input evaluator processors. The setting is expected
+   * to be the input value to be evaluated later on and is replaced by the
+   * suiting processor.
+   */
+  public static function prepareSetting(&$setting, $param_info, $var_info = array()) {
+    $processor = NULL;
+    foreach (self::evaluators($param_info, FALSE) as $name => $info) {
+      $object = new $info['class']($setting, $param_info, $var_info, $processor);
+      $processor = $object->getPreparedValue();
+    }
+    $setting = $processor;
+  }
+
+  protected function getPreparedValue() {
+    return isset($this->setting) ? $this : $this->processor;
+  }
+
+  /**
+   * Overriden to just attach the help() of evaluators.
+   */
+  public static function attachForm(&$form, $settings, $param_info, $var_info, $access_check = TRUE) {
+    foreach (self::evaluators($param_info, $access_check) as $name => $info) {
+      $form['help'][$name] = call_user_func(array($info['class'], 'help'), $var_info, $param_info);
+      $form['help'][$name]['#weight'] = $info['weight'];
+    }
+  }
+
+  /**
+   * Returns all input evaluators that can be applied to the parameters needed
+   * type.
+   */
+  public static function evaluators($param_info = NULL, $access_check = TRUE) {
+    return parent::processors($param_info, $access_check, 'evaluator_info');
+  }
+
+  /**
+   * Overridden to default to our hook, thus being equivalent to
+   * self::evaluators().
+   */
+  public static function processors($param_info = NULL, $access_check = TRUE, $hook = 'evaluator_info') {
+    return parent::processors($param_info, $access_check, $hook);
+  }
+
+  /**
+   * Prepares the evalution, e.g. to determine whether the input evaluator has
+   * been used. If this evaluator should be skipped just unset $this->setting.
+   *
+   * @param $text
+   *   The text to evaluate later on.
+   * @param $variables
+   *   An array of info about available variables.
+   * @param $param_info
+   *   (optional) An array of information about the handled parameter value.
+   *   For backward compatibility, this parameter is not required.
+   */
+  abstract public function prepare($text, $variables);
+
+  /**
+   * Apply the input evaluator.
+   *
+   * @param $text
+   *   The text to evaluate.
+   * @param $options
+   *   A keyed array of settings and flags to control the processing.
+   *   Supported options are:
+   *   - language: A language object to be used when processing.
+   *   - callback: A callback function that will be used to post-process
+   *     replacements that might be incorporated, so they can be cleaned in a
+   *     certain way.
+   *   - sanitize: A boolean flag indicating whether incorporated replacements
+   *     should be sanitized.
+   * @param RulesState
+   *   The rules evaluation state.
+   *
+   * @return
+   *   The evaluated text.
+   */
+  abstract public function evaluate($text, $options, RulesState $state);
+
+  /**
+   * Provide some usage help for the evaluator.
+   *
+   * @param $variables
+   *   An array of info about available variables.
+   * @param $param_info
+   *   (optional) An array of information about the handled parameter value.
+   *   For backward compatibility, this parameter is not required.
+   *
+   * @return
+   *   A renderable array.
+   */
+  public static function help($variables) {
+    return array();
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/includes/rules.state.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,770 @@
+<?php
+
+/**
+ * @file Contains the state and data related stuff.
+ */
+
+/**
+ * The rules evaluation state.
+ *
+ * A rule element may clone the state, so any added variables are only visible
+ * for elements in the current PHP-variable-scope.
+ */
+class RulesState {
+
+  /**
+   * Globally keeps the ids of rules blocked due to recursion prevention.
+   */
+  static protected $blocked = array();
+
+  /**
+   * The known variables.
+   */
+  public $variables = array();
+
+  /**
+   * Holds info about the variables.
+   */
+  protected $info = array();
+
+  /**
+   * Keeps wrappers to be saved later on.
+   */
+  protected $save;
+
+  /**
+   * Holds the arguments while an element is executed. May be used by the
+   * element to easily access the wrapped arguments.
+   */
+  public $currentArguments;
+
+  /**
+   * Variable for saving currently blocked configs for serialization.
+   */
+  protected $currentlyBlocked;
+
+
+  public function __construct() {
+    // Use an object in order to ensure any cloned states reference the same
+    // save information.
+    $this->save = new ArrayObject();
+    $this->addVariable('site', FALSE, self::defaultVariables('site'));
+  }
+
+  /**
+   * Adds the given variable to the given execution state.
+   */
+  public function addVariable($name, $data, $info) {
+    $this->info[$name] = $info + array(
+      'skip save' => FALSE,
+      'type' => 'unknown',
+      'handler' => FALSE,
+    );
+    if (empty($this->info[$name]['handler'])) {
+      $this->variables[$name] = rules_wrap_data($data, $this->info[$name]);
+    }
+  }
+
+  /**
+   * Runs post-evaluation tasks, such as saving variables.
+   */
+  public function cleanUp() {
+    // Make changes permanent.
+    foreach ($this->save->getArrayCopy() as $selector => $wrapper) {
+      $this->saveNow($selector);
+    }
+    unset($this->currentArguments);
+  }
+
+  /**
+   * Block a rules configuration from execution.
+   */
+  public function block($rules_config) {
+    if (empty($rules_config->recursion) && $rules_config->id) {
+      self::$blocked[$rules_config->id] = TRUE;
+    }
+  }
+
+  /**
+   * Unblock a rules configuration from execution.
+   */
+  public function unblock($rules_config) {
+    if (empty($rules_config->recursion) && $rules_config->id) {
+      unset(self::$blocked[$rules_config->id]);
+    }
+  }
+
+  /**
+   * Returns whether a rules configuration should be blocked from execution.
+   */
+  public function isBlocked($rule_config) {
+    return !empty($rule_config->id) && isset(self::$blocked[$rule_config->id]);
+  }
+
+  /**
+   * Get the info about the state variables or a single variable.
+   */
+  public function varInfo($name = NULL) {
+    if (isset($name)) {
+      return isset($this->info[$name]) ? $this->info[$name] : FALSE;
+    }
+    return $this->info;
+  }
+
+  /**
+   * Returns whether the given wrapper is savable.
+   */
+  public function isSavable($wrapper) {
+    return ($wrapper instanceof EntityDrupalWrapper && entity_type_supports($wrapper->type(), 'save')) || $wrapper instanceof RulesDataWrapperSavableInterface;
+  }
+
+  /**
+   * Returns whether the variable with the given name is an entity.
+   */
+  public function isEntity($name) {
+    $entity_info = entity_get_info();
+    return isset($this->info[$name]['type']) && isset($entity_info[$this->info[$name]['type']]);
+  }
+
+  /**
+   * Gets a variable.
+   *
+   * If necessary, the specified handler is invoked to fetch the variable.
+   *
+   * @param $name
+   *   The name of the variable to return.
+   *
+   * @return
+   *   The variable or a EntityMetadataWrapper containing the variable.
+   *
+   * @throws RulesEvaluationException
+   *   Throws a RulesEvaluationException in case we have info about the
+   *   requested variable, but it is not defined.
+   */
+  public function &get($name) {
+    if (!array_key_exists($name, $this->variables)) {
+      // If there is handler to load the variable, do it now.
+      if (!empty($this->info[$name]['handler'])) {
+        $data = call_user_func($this->info[$name]['handler'], rules_unwrap_data($this->variables), $name, $this->info[$name]);
+        $this->variables[$name] = rules_wrap_data($data, $this->info[$name]);
+        $this->info[$name]['handler'] = FALSE;
+        if (!isset($data)) {
+          throw new RulesEvaluationException('Unable to load variable %name, aborting.', array('%name' => $name), NULL, RulesLog::INFO);
+        }
+      }
+      else {
+        throw new RulesEvaluationException('Unable to get variable %name, it is not defined.', array('%name' => $name), NULL, RulesLog::ERROR);
+      }
+    }
+    return $this->variables[$name];
+  }
+
+  /**
+   * Apply permanent changes provided the wrapper's data type is savable.
+   *
+   * @param $selector
+   *   The data selector of the wrapper to save or just a variable name.
+   * @param $immediate
+   *   Pass FALSE to postpone saving to later on. Else it's immediately saved.
+   */
+  public function saveChanges($selector, $wrapper, $immediate = FALSE) {
+    $info = $wrapper->info();
+    if (empty($info['skip save']) && $this->isSavable($wrapper)) {
+      $this->save($selector, $wrapper, $immediate);
+    }
+    // No entity, so try saving the parent.
+    elseif (empty($info['skip save']) && isset($info['parent']) && !($wrapper instanceof EntityDrupalWrapper)) {
+      // Cut of the last part of the selector.
+      $selector = implode(':', explode(':', $selector, -1));
+      $this->saveChanges($selector, $info['parent'], $immediate);
+    }
+    return $this;
+  }
+
+  /**
+   * Remembers to save the wrapper on cleanup or does it now.
+   */
+  protected function save($selector, EntityMetadataWrapper $wrapper, $immediate) {
+    // Convert variable names and selectors to both use underscores.
+    $selector = strtr($selector, '-', '_');
+    if (isset($this->save[$selector])) {
+      if ($this->save[$selector][0]->getIdentifier() == $wrapper->getIdentifier()) {
+        // The entity is already remembered. So do a combined save.
+        $this->save[$selector][1] += self::$blocked;
+      }
+      else {
+        // The wrapper is already in there, but wraps another entity. So first
+        // save the old one, then care about the new one.
+        $this->saveNow($selector);
+      }
+    }
+    if (!isset($this->save[$selector])) {
+      // In case of immediate saving don't clone the wrapper, so saving a new
+      // entity immediately makes the identifier available afterwards.
+      $this->save[$selector] = array($immediate ? $wrapper : clone $wrapper, self::$blocked);
+    }
+    if ($immediate) {
+      $this->saveNow($selector);
+    }
+  }
+
+  /**
+   * Saves the wrapper for the given selector.
+   */
+  protected function saveNow($selector) {
+    // Add the set of blocked elements for the recursion prevention.
+    $previously_blocked = self::$blocked;
+    self::$blocked += $this->save[$selector][1];
+
+    // Actually save!
+    $wrapper = $this->save[$selector][0];
+    $entity = $wrapper->value();
+    // When operating in hook_entity_insert() $entity->is_new might be still
+    // set. In that case remove the flag to avoid causing another insert instead
+    // of an update.
+    if (!empty($entity->is_new) && $wrapper->getIdentifier()) {
+      $entity->is_new = FALSE;
+    }
+    rules_log('Saved %selector of type %type.', array('%selector' => $selector, '%type' => $wrapper->type()));
+    $wrapper->save();
+
+    // Restore the state's set of blocked elements.
+    self::$blocked = $previously_blocked;
+    unset($this->save[$selector]);
+  }
+
+  /**
+   * Merges the info about to be saved variables form the given state into the
+   * existing state. Therefor we can aggregate saves from invoked components.
+   * Merged in saves are removed from the given state, but not mergable saves
+   * remain there.
+   *
+   * @param $state
+   *   The state for which to merge the to be saved variables in.
+   * @param $component
+   *   The component which has been invoked, thus needs to be blocked for the
+   *   merged in saves.
+   * @param $settings
+   *   The settings of the element that invoked the component. Contains
+   *   information about variable/selector mappings between the states.
+   */
+  public function mergeSaveVariables(RulesState $state, RulesPlugin $component, $settings) {
+    // For any saves that we take over, also block the component.
+    $this->block($component);
+
+    foreach ($state->save->getArrayCopy() as $selector => $data) {
+      $parts = explode(':', $selector, 2);
+      // Adapt the selector to fit for the parent state and move the wrapper.
+      if (isset($settings[$parts[0] . ':select'])) {
+        $parts[0] = $settings[$parts[0] . ':select'];
+        $this->save(implode(':', $parts), $data[0], FALSE);
+        unset($state->save[$selector]);
+      }
+    }
+    $this->unblock($component);
+  }
+
+  /**
+   * Returns an entity metadata wrapper as specified in the selector.
+   *
+   * @param $selector
+   *   The selector string, e.g. "node:author:mail".
+   * @param $langcode
+   *   (optional) The language code used to get the argument value if the
+   *   argument value should be translated. Defaults to LANGUAGE_NONE.
+   *
+   * @return EntityMetadataWrapper
+   *   The wrapper for the given selector.
+   *
+   * @throws RulesEvaluationException
+   *   Throws a RulesEvaluationException in case the selector cannot be applied.
+   */
+  public function applyDataSelector($selector, $langcode = LANGUAGE_NONE) {
+    $parts = explode(':', str_replace('-', '_', $selector), 2);
+    $wrapper = $this->get($parts[0]);
+    if (count($parts) == 1) {
+      return $wrapper;
+    }
+    elseif (!$wrapper instanceof EntityMetadataWrapper) {
+      throw new RulesEvaluationException('Unable to apply data selector %selector. The specified variable is not wrapped correctly.', array('%selector' => $selector));
+    }
+    try {
+      foreach (explode(':', $parts[1]) as $name) {
+        if ($wrapper instanceof EntityListWrapper || $wrapper instanceof EntityStructureWrapper) {
+          // Make sure we are usign the right language. Wrappers might be cached
+          // and have previous langcodes set, so always set the right language.
+          if ($wrapper instanceof EntityStructureWrapper) {
+            $wrapper->language($langcode);
+          }
+          $wrapper = $wrapper->get($name);
+        }
+        else {
+          throw new RulesEvaluationException('Unable to apply data selector %selector. The specified variable is not a list or a structure: %wrapper.', array('%selector' => $selector, '%wrapper' => $wrapper));
+        }
+      }
+    }
+    catch (EntityMetadataWrapperException $e) {
+      // In case of an exception, re-throw it.
+      throw new RulesEvaluationException('Unable to apply data selector %selector: %error', array('%selector' => $selector, '%error' => $e->getMessage()));
+    }
+    return $wrapper;
+  }
+
+  /**
+   * Magic method. Only serialize variables and their info.
+   * Additionally we remember currently blocked configs, so we can restore them
+   * upon deserialization using restoreBlocks().
+   */
+  public function __sleep () {
+    $this->currentlyBlocked = self::$blocked;
+    return array('info', 'variables', 'currentlyBlocked');
+  }
+
+  public function __wakeup() {
+    $this->save = new ArrayObject();
+  }
+
+  /**
+   * Restore the before serialization blocked configurations.
+   *
+   * Warning: This overwrites any possible currently blocked configs. Thus
+   * do not invoke this method, if there might be evaluations active.
+   */
+  public function restoreBlocks() {
+    self::$blocked = $this->currentlyBlocked;
+  }
+
+  /**
+   * Defines always available variables.
+   */
+  public static function defaultVariables($key = NULL) {
+    // Add a variable for accessing site-wide data properties.
+    $vars['site'] = array(
+      'type' => 'site',
+      'label' => t('Site information'),
+      'description' => t("Site-wide settings and other global information."),
+      // Add the property info via a callback making use of the cached info.
+      'property info alter' => array('RulesData', 'addSiteMetadata'),
+      'property info' => array(),
+      'optional' => TRUE,
+    );
+    return isset($key) ? $vars[$key] : $vars;
+  }
+}
+
+/**
+ * A class holding static methods related to data.
+ */
+class RulesData  {
+
+  /**
+   * Returns whether the type match. They match if type1 is compatible to type2.
+   *
+   * @param $var_info
+   *   The name of the type to check for whether it is compatible to type2.
+   * @param $param_info
+   *   The type expression to check for.
+   * @param $ancestors
+   *   Whether sub-type relationships for checking type compatibility should be
+   *   taken into account. Defaults to TRUE.
+   *
+   * @return
+   *   Whether the types match.
+   */
+  public static function typesMatch($var_info, $param_info, $ancestors = TRUE) {
+    $var_type = $var_info['type'];
+    $param_type = $param_info['type'];
+
+    if ($param_type == '*' || $param_type == 'unknown') {
+      return TRUE;
+    }
+
+    if ($var_type == $param_type) {
+      // Make sure the bundle matches, if specified by the parameter.
+      return !isset($param_info['bundles']) || isset($var_info['bundle']) && in_array($var_info['bundle'], $param_info['bundles']);
+    }
+
+    // Parameters may specify multiple types using an array.
+    $valid_types = is_array($param_type) ? $param_type : array($param_type);
+    if (in_array($var_type, $valid_types)) {
+      return TRUE;
+    }
+
+    // Check for sub-type relationships.
+    if ($ancestors && !isset($param_info['bundles'])) {
+      $cache = &rules_get_cache();
+      self::typeCalcAncestors($cache, $var_type);
+      // If one of the types is an ancestor return TRUE.
+      return (bool)array_intersect_key($cache['data_info'][$var_type]['ancestors'], array_flip($valid_types));
+    }
+    return FALSE;
+  }
+
+  protected static function typeCalcAncestors(&$cache, $type) {
+    if (!isset($cache['data_info'][$type]['ancestors'])) {
+      $cache['data_info'][$type]['ancestors'] = array();
+      if (isset($cache['data_info'][$type]['parent']) && $parent = $cache['data_info'][$type]['parent']) {
+        $cache['data_info'][$type]['ancestors'][$parent] = TRUE;
+        self::typeCalcAncestors($cache, $parent);
+        // Add all parent ancestors to our own ancestors.
+        $cache['data_info'][$type]['ancestors'] += $cache['data_info'][$parent]['ancestors'];
+      }
+      // For special lists like list<node> add in "list" as valid parent.
+      if (entity_property_list_extract_type($type)) {
+        $cache['data_info'][$type]['ancestors']['list'] = TRUE;
+      }
+    }
+  }
+
+  /**
+   * Returns matching data variables or properties for the given info and the to
+   * be configured parameter.
+   *
+   * @param $source
+   *   Either an array of info about available variables or a entity metadata
+   *   wrapper.
+   * @param $param_info
+   *   The information array about the to be configured parameter.
+   * @param $prefix
+   *   An optional prefix for the data selectors.
+   * @param $recursions
+   *   The number of recursions used to go down the tree. Defaults to 2.
+   * @param $suggestions
+   *   Whether possibilities to recurse are suggested as soon as the deepest
+   *   level of recursions is reached. Defaults to TRUE.
+   *
+   * @return
+   *  An array of info about matching variables or properties that match, keyed
+   *  with the data selector.
+   */
+  public static function matchingDataSelector($source, $param_info, $prefix = '', $recursions = 2, $suggestions = TRUE) {
+    // If an array of info is given, get entity metadata wrappers first.
+    $data = NULL;
+    if (is_array($source)) {
+      foreach ($source as $name => $info) {
+        $source[$name] = rules_wrap_data($data, $info, TRUE);
+      }
+    }
+
+    $matches = array();
+    foreach ($source as $name => $wrapper) {
+      $info = $wrapper->info();
+      $name = str_replace('_', '-', $name);
+
+      if (self::typesMatch($info, $param_info)) {
+        $matches[$prefix . $name] = $info;
+        if (!is_array($source) && $source instanceof EntityListWrapper) {
+          // Add some more possible list items.
+          for ($i = 1; $i < 4; $i++) {
+            $matches[$prefix . $i] = $info;
+          }
+        }
+      }
+      // Recurse later on to get an improved ordering of the results.
+      if ($wrapper instanceof EntityStructureWrapper || $wrapper instanceof EntityListWrapper) {
+        $recurse[$prefix . $name] = $wrapper;
+        if ($recursions > 0) {
+          $matches += self::matchingDataSelector($wrapper, $param_info, $prefix . $name . ':', $recursions - 1, $suggestions);
+        }
+        elseif ($suggestions) {
+          // We may not recurse any more, but indicate the possibility to recurse.
+          $matches[$prefix . $name . ':'] = $wrapper->info();
+          if (!is_array($source) && $source instanceof EntityListWrapper) {
+            // Add some more possible list items.
+            for ($i = 1; $i < 4; $i++) {
+              $matches[$prefix . $i . ':'] = $wrapper->info();
+            }
+          }
+        }
+      }
+    }
+    return $matches;
+  }
+
+  /**
+   * Adds asserted metadata to the variable info. In case there are already
+   * assertions for a variable, the assertions are merged such that both apply.
+   *
+   * @see RulesData::applyMetadataAssertions()
+   */
+  public static function addMetadataAssertions($var_info, $assertions) {
+    foreach ($assertions as $selector => $assertion) {
+      // Convert the selector back to underscores, such it matches the varname.
+      $selector = str_replace('-', '_', $selector);
+
+      $parts = explode(':', $selector);
+      if (isset($var_info[$parts[0]])) {
+        // Apply the selector to determine the right target array. We build an
+        // array like
+        // $var_info['rules assertion']['property1']['property2']['#info'] = ..
+        $target = &$var_info[$parts[0]]['rules assertion'];
+        foreach (array_slice($parts, 1) as $part) {
+          $target = &$target[$part];
+        }
+
+        // In case the assertion is directly for a variable, we have to modify
+        // the variable info directly. In case the asserted property is nested
+        // the info-has to be altered by RulesData::applyMetadataAssertions()
+        // before the child-wrapper is created.
+        if (count($parts) == 1) {
+          // Support asserting a type in case of generic entity references only.
+          if (isset($assertion['type']) && $var_info[$parts[0]]['type'] == 'entity') {
+            if (entity_get_info($assertion['type'])) {
+              $var_info[$parts[0]]['type'] = $assertion['type'];
+            }
+            unset($assertion['type']);
+          }
+          // Add any single bundle directly to the variable info, so the
+          // variable fits as argument for parameters requiring the bundle.
+          if (isset($assertion['bundle']) && count($bundles = (array) $assertion['bundle']) == 1) {
+            $var_info[$parts[0]]['bundle'] = reset($bundles);
+          }
+        }
+
+        // Add the assertions, but merge them with any previously added
+        // assertions if necessary.
+        $target['#info'] = isset($target['#info']) ? rules_update_array($target['#info'], $assertion) : $assertion;
+
+        // Add in a callback that the entity metadata wrapper pick up for
+        // altering the property info, such that we can add in the assertions.
+        $var_info[$parts[0]] += array('property info alter' => array('RulesData', 'applyMetadataAssertions'));
+
+        // In case there is a VARNAME_unchanged variable as it is used in update
+        // hooks, assume the assertions are valid for the unchanged variable
+        // too.
+        if (isset($var_info[$parts[0] . '_unchanged'])) {
+          $name = $parts[0] . '_unchanged';
+          $var_info[$name]['rules assertion'] = $var_info[$parts[0]]['rules assertion'];
+          $var_info[$name]['property info alter'] = array('RulesData', 'applyMetadataAssertions');
+
+          if (isset($var_info[$parts[0]]['bundle']) && !isset($var_info[$name]['bundle'])) {
+            $var_info[$name]['bundle'] = $var_info[$parts[0]]['bundle'];
+          }
+        }
+      }
+    }
+    return $var_info;
+  }
+
+  /**
+   * Property info alter callback for the entity metadata wrapper for applying
+   * the rules metadata assertions.
+   *
+   * @see RulesData::addMetadataAssertions()
+   */
+  public static function applyMetadataAssertions(EntityMetadataWrapper $wrapper, $property_info) {
+    $info = $wrapper->info();
+
+    if (!empty($info['rules assertion'])) {
+      $assertion = $info['rules assertion'];
+
+      // In case there are list-wrappers pass through the assertions of the item
+      // but make sure we only apply the assertions for the list items for
+      // which the conditions are executed.
+      if (isset($info['parent']) && $info['parent'] instanceof EntityListWrapper) {
+        $assertion = isset($assertion[$info['name']]) ? $assertion[$info['name']] : array();
+      }
+
+      // Support specifying multiple bundles, whereas the added properties are
+      // the intersection of the bundle properties.
+      if (isset($assertion['#info']['bundle'])) {
+        $bundles = (array) $assertion['#info']['bundle'];
+        foreach ($bundles as $bundle) {
+          $properties[] = isset($property_info['bundles'][$bundle]['properties']) ? $property_info['bundles'][$bundle]['properties'] : array();
+        }
+        // Add the intersection.
+        $property_info['properties'] += count($properties) > 1 ? call_user_func_array('array_intersect_key', $properties) : reset($properties);
+      }
+      // Support adding directly asserted property info.
+      if (isset($assertion['#info']['property info'])) {
+        $property_info['properties'] += $assertion['#info']['property info'];
+      }
+
+      // Pass through any rules assertion of properties to their info, so any
+      // derived wrappers apply it.
+      foreach (element_children($assertion) as $key) {
+        $property_info['properties'][$key]['rules assertion'] = $assertion[$key];
+        $property_info['properties'][$key]['property info alter'] = array('RulesData', 'applyMetadataAssertions');
+
+        // Apply any 'type' and 'bundle' assertion directly to the propertyinfo.
+        if (isset($assertion[$key]['#info']['type'])) {
+          $type = $assertion[$key]['#info']['type'];
+          // Support asserting a type in case of generic entity references only.
+          if ($property_info['properties'][$key]['type'] == 'entity' && entity_get_info($type)) {
+            $property_info['properties'][$key]['type'] = $type;
+          }
+        }
+        if (isset($assertion[$key]['#info']['bundle'])) {
+          $bundle = (array) $assertion[$key]['#info']['bundle'];
+          // Add any single bundle directly to the variable info, so the
+          // property fits as argument for parameters requiring the bundle.
+          if (count($bundle) == 1) {
+            $property_info['properties'][$key]['bundle'] = reset($bundle);
+          }
+        }
+      }
+    }
+    return $property_info;
+  }
+
+  /**
+   * Property info alter callback for the entity metadata wrapper to inject
+   * metadata for the 'site' variable. In contrast to doing this via
+   * hook_rules_data_info() this callback makes use of the already existing
+   * property info cache for site information of entity metadata.
+   *
+   * @see RulesPlugin::availableVariables()
+   */
+  public static function addSiteMetadata(EntityMetadataWrapper $wrapper, $property_info) {
+    $site_info = entity_get_property_info('site');
+    $property_info['properties'] += $site_info['properties'];
+    // Also invoke the usual callback for altering metadata, in case actions
+    // have specified further metadata.
+    return RulesData::applyMetadataAssertions($wrapper, $property_info);
+  }
+}
+
+/**
+ * A wrapper class similar to the EntityDrupalWrapper, but for non-entities.
+ *
+ * This class is intended to serve as base for a custom wrapper classes of
+ * identifiable data types, which are non-entities. By extending this class only
+ * the extractIdentifier() and load() methods have to be defined.
+ * In order to make the data type savable implement the
+ * RulesDataWrapperSavableInterface.
+ *
+ * That way it is possible for non-entity data types to be work with Rules, i.e.
+ * one can implement a 'ui class' with a direct input form returning the
+ * identifier of the data. However, instead of that it is suggested to implement
+ * an entity type, such that the same is achieved via general API functions like
+ * entity_load().
+ */
+abstract class RulesIdentifiableDataWrapper extends EntityStructureWrapper {
+
+  /**
+   * Contains the id.
+   */
+  protected $id = FALSE;
+
+  /**
+   * Construct a new wrapper object.
+   *
+   * @param $type
+   *   The type of the passed data.
+   * @param $data
+   *   Optional. The data to wrap or its identifier.
+   * @param $info
+   *   Optional. Used internally to pass info about properties down the tree.
+   */
+  public function __construct($type, $data = NULL, $info = array()) {
+    parent::__construct($type, $data, $info);
+    $this->setData($data);
+  }
+
+  /**
+   * Sets the data internally accepting both the data id and object.
+   */
+  protected function setData($data) {
+    if (isset($data) && $data !== FALSE && !is_object($data)) {
+      $this->id = $data;
+      $this->data = FALSE;
+    }
+    elseif (is_object($data)) {
+      // We got the data object passed.
+      $this->data = $data;
+      $id = $this->extractIdentifier($data);
+      $this->id = isset($id) ? $id : FALSE;
+    }
+  }
+
+  /**
+   * Returns the identifier of the wrapped data.
+   */
+  public function getIdentifier() {
+    return $this->dataAvailable() && $this->value() ? $this->id : NULL;
+  }
+
+  /**
+   * Overridden.
+   */
+  public function value(array $options = array()) {
+    $this->setData(parent::value());
+    if (!$this->data && !empty($this->id)) {
+      // Lazy load the data if necessary.
+      $this->data = $this->load($this->id);
+      if (!$this->data) {
+        throw new EntityMetadataWrapperException('Unable to load the ' . check_plain($this->type) . ' with the id ' . check_plain($this->id) . '.');
+      }
+    }
+    return $this->data;
+  }
+
+  /**
+   * Overridden to support setting the data by either the object or the id.
+   */
+  public function set($value) {
+    if (!$this->validate($value)) {
+      throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.');
+    }
+    // As custom wrapper classes can only appear for Rules variables, but not
+    // as properties we don't have to care about updating the parent.
+    $this->clear();
+    $this->setData($value);
+    return $this;
+  }
+
+  /**
+   * Overridden.
+   */
+  public function clear() {
+    $this->id = NULL;
+    parent::clear();
+  }
+
+  /**
+   * Prepare for serializiation.
+   */
+  public function __sleep() {
+    $vars = parent::__sleep();
+    // Don't serialize the loaded data, except for the case the data is not
+    // saved yet.
+    if (!empty($this->id)) {
+      unset($vars['data']);
+    }
+    return $vars;
+  }
+
+  public function __wakeup() {
+    if ($this->id !== FALSE) {
+      // Make sure data is set, so the data will be loaded when needed.
+      $this->data = FALSE;
+    }
+  }
+
+  /**
+   * Extract the identifier of the given data object.
+   *
+   * @return
+   *   The extracted identifier.
+   */
+  abstract protected function extractIdentifier($data);
+
+  /**
+   * Load a data object given an identifier.
+   *
+   * @return
+   *   The loaded data object, or FALSE if loading failed.
+   */
+  abstract protected function load($id);
+}
+
+/**
+ * Interface that allows custom wrapper classes to declare that they are savable.
+ */
+interface RulesDataWrapperSavableInterface {
+
+  /**
+   * Save the currently wrapped data.
+   */
+  public function save();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/includes/rules.upgrade.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,664 @@
+<?php
+
+/**
+ * @file
+ * Contains code for upgrading rule configurations from 6.x-1.x to 7.x-2.x.
+ */
+
+/**
+ * Form builder for the upgrade page.
+ */
+function rules_upgrade_form($form, &$form_state) {
+
+  if (!empty($form_state['export'])) {
+    foreach ($form_state['export'] as $key => $export) {
+      // Rules have been already converted and exported, so show the export.
+      $form['export'][$key] = array(
+        '#type' => 'textarea',
+        '#title' => t('Export %name', array('%name' => $key)),
+        '#description' => t('For importing copy the content of the text area and paste it into the import page of the Rules admin UI. In case the export does not pass the integrity check during import, try using the save to database method instead and manually fix your configuration after conversion.'),
+        '#rows' => 10,
+        '#default_value' => $export,
+      );
+    }
+    return $form;
+  }
+
+  $form['help'] = array(
+    '#prefix' => '<p>',
+    '#suffix' => '</p>',
+    '#markup' => t('This form allows you to convert rules or rule sets from Rules 1.x to Rules 2.x.') . ' ' .
+      t('In order to convert a rule or rule set make sure you have all dependend modules installed and upgraded, i.e. modules which provide Rules integration that has been used in your rules or rule sets. In addition those modules may need to implement some Rules specific update hooks for the conversion to properly work.') . ' ' .
+      t('After conversion, the old rules and rule sets will stay in the database until you manually delete them. That way you can make sure the conversion has gone right before you delete the old rules and rule sets.')
+  );
+
+  $option_rules = $option_sets = array();
+  if (!db_table_exists('rules_rules')) {
+    drupal_set_message('There are no Rules 1.x rules or rule sets left to convert.', 'error');
+  }
+  else {
+    foreach (_rules_upgrade_fetch_all_rules() as $name => $rule) {
+      if (!empty($rule['#set']) && strpos($rule['#set'], 'event_') === 0) {
+        $option_rules[$name] = $name . ': ' . $rule['#label'];
+      }
+    }
+    $query = db_select('rules_sets', 'r')->fields('r');
+    foreach ($query->execute() as $row) {
+      $set = unserialize($row->data);
+      $option_sets[$row->name] = $row->name . ': ' . $set['label'];
+    }
+
+    $form['clear'] = array(
+      '#prefix' => '<p>',
+      '#suffix' => '</p>',
+      '#markup' => t('Once you have successfully converted your configuration, you can clean up your database and <a href="!url">delete</a> all Rules 1.x configurations.', array('!url' => url('admin/config/workflow/rules/upgrade/clear')))
+    );
+  }
+
+  $form['rules'] = array(
+    '#type' => 'select',
+    '#title' => t('Rules'),
+    '#options' => $option_rules,
+    '#multiple' => TRUE,
+  );
+
+  $form['sets'] = array(
+    '#type' => 'select',
+    '#title' => t('Rule sets'),
+    '#options' => $option_sets,
+    '#multiple' => TRUE,
+  );
+  $form['method'] = array(
+    '#type' => 'radios',
+    '#title' => t('Method'),
+    '#options' => array(
+       'export' => t('Convert configuration and export it.'),
+       'save' => t('Convert configuration and save it.'),
+    ),
+    '#default_value' => 'export',
+  );
+
+  $form['actions']['convert'] = array(
+    '#type' => 'submit',
+    '#value' => t('Convert'),
+    '#disabled' => !db_table_exists('rules_rules')
+  );
+  return $form;
+}
+
+/**
+ * Submit handler for the form.
+ */
+function rules_upgrade_form_submit($form, &$form_state) {
+  // Load all rules includes and install files so modules may put there upgrade
+  // information in both locations.
+  module_load_all_includes('rules.inc');
+  module_load_all_includes('install');
+
+  $configs = array();
+
+  try {
+    foreach ($form_state['values']['rules'] as $name) {
+      drupal_set_message(t('Converting %plugin %name...', array('%plugin' => t('rule'), '%name' => $name)));
+      $configs[$name] = rules_upgrade_convert_rule($name, _rules_upgrade_fetch_item($name, 'rules_rules'));
+    }
+    foreach ($form_state['values']['sets'] as $name) {
+      drupal_set_message(t('Converting %plugin %name...', array('%plugin' => t('rule set'), '%name' => $name)));
+      $configs[$name] = rules_upgrade_convert_rule_set($name, _rules_upgrade_fetch_item($name, 'rules_sets'));
+    }
+    drupal_set_message(t('Completed.'));
+
+    if ($form_state['values']['method'] == 'save') {
+      foreach ($configs as $config) {
+        $config->save();
+      }
+      drupal_set_message(t('Converted configurations have been saved to the database and will appear in the Rules administration interface.'));
+    }
+    elseif ($form_state['values']['method'] == 'export') {
+      $export = array();
+      foreach ($configs as $name => $config) {
+        $export[$name] = $config->export();
+      }
+      $form_state['export'] = $export;
+      $form_state['rebuild'] = TRUE;
+    }
+  }
+  catch (RulesException $e) {
+    drupal_set_message($e->getMessage(), 'error');
+  }
+}
+
+/**
+ * Confirm form for deleting data.
+ */
+function rules_upgrade_confirm_clear_form($form, $form_state) {
+  $confirm_question = t('Are you sure you want to drop the Rules 1.x tables from the database?');
+  $confirm_question_long = t('Are you sure you want to drop the Rules 1.x tables from the database? All Rules 1.x configurations will be deleted regardless whether they have been already converted.') . ' ' . t('This action cannot be undone.');
+  return confirm_form($form, $confirm_question, 'admin/config/workflow/rules/upgrade', $confirm_question_long, t('Delete data'), t('Cancel'));
+}
+
+function rules_upgrade_confirm_clear_form_submit($form, &$form_state) {
+  db_drop_table('rules_rules');
+  db_drop_table('rules_sets');
+  db_drop_table('rules_scheduler_d6');
+  drupal_set_message(t('Rules 1.x configurations have been deleted.'));
+  $form_state['redirect'] = 'admin';
+}
+
+/**
+ * Fetches a single item (rule | rule set).
+ */
+function _rules_upgrade_fetch_item($name, $table) {
+  $query = db_select($table, 'r')->fields('r')->condition('name', $name);
+  $row = $query->execute()->fetchAssoc();
+  return unserialize($row['data']);
+}
+
+/**
+ * Fetches all rules.
+ */
+function _rules_upgrade_fetch_all_rules() {
+  $static = drupal_static(__FUNCTION__);
+
+  if (!isset($static)) {
+    $query = db_select('rules_rules', 'r')->fields('r');
+    $static['rules'] = array();
+    foreach ($query->execute() as $row) {
+      $static['rules'][$row->name] = unserialize($row->data);
+    }
+  }
+  return $static['rules'];
+}
+
+/**
+ * Converts a single reaction rule.
+ */
+function rules_upgrade_convert_rule($name, $cfg_old) {
+  $config = rules_upgrade_plugin_factory($cfg_old);
+  $config->name = $name;
+
+  if ($config instanceof RulesReactionRule) {
+    rules_upgrade_convert_element($cfg_old, $config);
+  }
+  return $config;
+}
+
+/**
+ * Converts a single rule set, including all of its rules.
+ */
+function rules_upgrade_convert_rule_set($name, $cfg_old) {
+  $config = rules_plugin_factory('rule set');
+  $config->name = $name;
+  foreach (array('label', 'weight') as $key) {
+    if (isset($cfg_old[$key])) {
+      $config->$key = $cfg_old[$key];
+    }
+  }
+  if (isset($cfg_old['arguments'])) {
+    $vars = &$config->componentVariables();
+    foreach ($cfg_old['arguments'] as $var_name => $info) {
+      // Map data types as required.
+      if ($info['type'] == 'string') {
+        $info['type'] = 'text';
+      }
+      $vars[$var_name] = $info;
+    }
+  }
+
+  // Add in all rules of the set.
+  foreach(_rules_upgrade_fetch_all_rules() as $rule_name => $rule) {
+    if ($rule['#set'] == $name) {
+      drupal_set_message(' >> ' . t('Converting %plugin %name...', array('%plugin' => t('rule'), '%name' => $rule_name . ': ' . $rule['#label'])));
+      $new_rule = rules_upgrade_plugin_factory($rule);
+      rules_upgrade_convert_element($rule, $new_rule);
+      $new_rule->setParent($config);
+    }
+  }
+  return $config;
+}
+
+/**
+ * Convert a single element.
+ *
+ * @param $element
+ *   The element to convert.
+ * @param $target
+ *   The converted element to write to.
+ */
+function rules_upgrade_convert_element(array $element, RulesPlugin $target) {
+  foreach (array('active', 'label', 'weight') as $key) {
+    if (isset($element['#' . $key])) {
+      $target->$key = $element['#' . $key];
+    }
+  }
+  // Go through the parameters and take over its configuration if possible.
+  foreach ($target->pluginParameterInfo() as $name => $info) {
+    rules_upgrade_element_parameter_settings($element, $target, $name);
+  }
+  // @todo: Care about php input evaluator for non-text parameters.
+
+  // Take care of variable names and labels.
+  foreach ($target->pluginProvidesVariables() as $name => $info) {
+    rules_upgrade_element_variable_settings($element, $target, $name);
+  }
+
+  if ($target instanceof RulesConditionInterface && !empty($element['#negate'])) {
+    $target->negate(TRUE);
+  }
+  if ($target instanceof RulesReactionRule) {
+    // Cut of the 'event_' prefix.
+    $target->event(substr($element['#set'], 6));
+  }
+  if ($element['#type'] == 'rule') {
+    if (!empty($element['#conditions'])) {
+      foreach (element_children($element['#conditions']) as $key) {
+        $child = rules_upgrade_plugin_factory($element['#conditions'][$key]);
+        rules_upgrade_convert_element($element['#conditions'][$key], $child);
+        $target->condition($child);
+      }
+    }
+    if (!empty($element['#actions'])) {
+      foreach (element_children($element['#actions']) as $key) {
+        $child = rules_upgrade_plugin_factory($element['#actions'][$key]);
+        rules_upgrade_convert_element($element['#actions'][$key], $child);
+        $target->action($child);
+      }
+    }
+  }
+
+  // Invoke action/condition specific hooks and a general one.
+  if (($element['#type'] == 'action' || $element['#type'] == 'condition')) {
+    if (function_exists($function = $element['#name'] .'_upgrade')) {
+      $element_name = $function($element, $target);
+    }
+    elseif (isset($element['#info']['base']) && function_exists($function = $element['#info']['base'] .'_upgrade')) {
+      $element_name = $function($element, $target);
+    }
+  }
+
+  drupal_alter('rules_element_upgrade', $element, $target);
+  // Recurse down, if necessary.
+  foreach (element_children($element) as $key) {
+    $child = rules_upgrade_plugin_factory($element[$key]);
+    rules_upgrade_convert_element($element[$key], $child);
+    $child->setParent($target);
+  }
+  if ($target instanceof RulesContainerPlugin) {
+    $target->sortChildren();
+  }
+}
+
+/**
+ * Creates the right element.
+ */
+function rules_upgrade_plugin_factory($element) {
+  if ($element['#type'] == 'rule' && !empty($element['#set']) && strpos($element['#set'], 'event_') === 0) {
+    return rules_plugin_factory('reaction rule');
+  }
+
+  switch ($element['#type']) {
+    case 'OR':
+      return rules_plugin_factory('or');
+    case 'AND':
+      return rules_plugin_factory('and');
+    default:
+      return rules_plugin_factory($element['#type']);
+
+    case 'action':
+    case 'condition':
+      if (isset($element['#name'])) {
+        // Try to come up with the right action/condition name ourself, then
+        // invoke a hook.
+        $cache = rules_get_cache();
+        $items = $cache[$element['#type'] == 'action' ? 'action_info' : 'condition_info'];
+
+        if (isset($items[$element['#name']])) {
+          $element_name = $element['#name'];
+        }
+        elseif (($name = str_replace('rules_', '', $element['#name'])) && isset($items[$name])) {
+          $element_name = $name;
+        }
+        elseif (($name = str_replace($element['#type'] . '_', '', $element['#name'])) && isset($items[$name])) {
+          $element_name = $name;
+        }
+        elseif (($name = str_replace('rules_' . $element['#type'] . '_', '', $element['#name'])) && isset($items[$name])) {
+          $element_name = $name;
+        }
+        elseif (isset($element['#info']['base']) && isset($items[$element['#info']['base']])) {
+          $element_name = $name;
+        }
+
+        // Call the upgrade callback if one has been defined.
+        if (function_exists($function = $element['#name'] .'_upgrade_map_name') || (isset($element['#info']['base']) && function_exists($function = $element['#info']['base'] .'_upgrade_map_name'))) {
+          $element_name = $function($element);
+        }
+        if (!isset($element_name)) {
+          throw new RulesIntegrityException(t("Cannot find @plugin %name. Maybe a required is missing or the module has not implemented the upgrade functionality.", array('@plugin' => $element['#type'], '%name' => $element['#name'])));
+        }
+        return rules_plugin_factory($element['#type'], $element_name);
+      }
+      break;
+  }
+}
+
+/**
+ * Converts the settings for a given parameter.
+ */
+function rules_upgrade_element_parameter_settings($element, $target, $name, $new_name = NULL) {
+  if (!isset($new_name)) {
+    $new_name = $name;
+  }
+  if (isset($element['#settings'][$name])) {
+    // In case a single token has been used, just convert it to a data
+    // selector.
+    if (is_string($element['#settings'][$name]) && preg_match("/\[(.*)\]$/", $element['#settings'][$name], $matches)) {
+      $target->settings[$new_name . ':select'] = $matches[1];
+    }
+    else {
+      $target->settings[$new_name] = $element['#settings'][$name];
+    }
+  }
+  elseif (isset($element['#settings']['#argument map'][$name])) {
+    $target->settings[$new_name . ':select'] = $element['#settings']['#argument map'][$name];
+  }
+}
+
+/**
+ * Converts the settings for a given variable.
+ */
+function rules_upgrade_element_variable_settings($element, $target, $name, $new_name = NULL) {
+  if (!isset($new_name)) {
+    $new_name = $name;
+  }
+  if (isset($element['#settings']['#argument map'][$name])) {
+    $target->settings[$new_name . ':var'] = $element['#settings']['#argument map'][$name];
+    $target->settings[$new_name . ':label'] = $element['#info']['new variables'][$target->settings[$new_name . ':var']]['label'];
+  }
+}
+
+/**
+ * Upgrade callbacks for upgrading the provided Rules 1.x integration.
+ */
+
+// Comment.module integration.
+function rules_action_load_comment_upgrade_map_name($element) {
+  return 'entity_fetch';
+}
+function rules_action_load_comment_upgrade($element, $target) {
+  $target->settings['type'] = 'comment';
+  rules_upgrade_element_parameter_settings($element, $target, 'cid', 'id');
+  rules_upgrade_element_variable_settings($element, $target, 'comment_loaded', 'entity_fetched');
+}
+
+// Node.module integration.
+function rules_condition_content_is_type_upgrade_map_name($element) {
+  return 'node_is_of_type';
+}
+function rules_condition_content_is_published_upgrade_map_name($element) {
+  return 'node_is_published';
+}
+function rules_condition_content_is_sticky_upgrade_map_name($element) {
+  return 'node_is_sticky';
+}
+function rules_condition_content_is_promoted_upgrade_map_name($element) {
+  return 'node_is_promoted';
+}
+function rules_condition_content_is_new_upgrade_map_name($element) {
+  return 'entity_is_new';
+}
+function rules_condition_content_is_new_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'node', 'entity');
+}
+function rules_action_node_set_author_upgrade_map_name($element) {
+  return 'data_set';
+}
+function rules_action_node_set_author_upgrade($element, $target) {
+  $target->settings['data:select'] = $element['#settings']['#argument map']['node'] . ':author';
+  $target->settings['value:select'] = $element['#settings']['#argument map']['author'];
+}
+function rules_action_node_load_author_upgrade_map_name($element) {
+  return 'entity_fetch';
+}
+function rules_action_node_load_author_upgrade($element, $target) {
+  $target->settings['type'] = 'user';
+  $target->settings['id'] = $element['#settings']['#argument map']['node'] . ':author:uid';
+}
+function rules_action_set_node_title_upgrade_map_name($element) {
+  return 'data_set';
+}
+function rules_action_set_node_title_upgrade($element, $target) {
+  $target->settings['data:select'] = $element['#settings']['#argument map']['node'] . ':title';
+  $target->settings['value'] = $element['#settings']['title'];
+}
+function rules_action_add_node_upgrade_map_name($element) {
+  return 'entity_create';
+}
+function rules_action_add_node_upgrade($element, $target) {
+  $target->settings['type'] = 'node';
+  rules_upgrade_element_parameter_settings($element, $target, 'title', 'param_title');
+  rules_upgrade_element_parameter_settings($element, $target, 'author', 'param_author');
+  rules_upgrade_element_parameter_settings($element, $target, 'type', 'param_type');
+  rules_upgrade_element_variable_settings($element, $target, 'node_added', 'entity_created');
+  if (!empty($element['#settings']['node_access'])) {
+    drupal_set_message(t('Warning: The node-access check option for the node creation action is not supported any more.'));
+  }
+}
+function rules_action_load_node_upgrade_map_name($element) {
+  return 'entity_fetch';
+}
+function rules_action_load_node_upgrade($element, $target) {
+  $target->settings['type'] = 'node';
+  rules_upgrade_element_parameter_settings($element, $target, 'nid', 'id');
+  rules_upgrade_element_parameter_settings($element, $target, 'vid', 'revision_id');
+  rules_upgrade_element_variable_settings($element, $target, 'node_loaded', 'entity_fetched');
+}
+function rules_action_delete_node_upgrade_map_name($element) {
+  return 'entity_delete';
+}
+function rules_action_delete_node_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'node', 'entity');
+}
+function rules_core_node_publish_action_upgrade_map_name($element) {
+  return 'node_publish';
+}
+function rules_core_node_unpublish_action_upgrade_map_name($element) {
+  return 'node_unpublish';
+}
+function rules_core_node_make_sticky_action_upgrade_map_name($element) {
+  return 'node_make_sticky_action';
+}
+function rules_core_node_make_unsticky_action_upgrade_map_name($element) {
+  return 'node_make_unsticky_action';
+}
+function rules_core_node_promote_action_upgrade_map_name($element) {
+  return 'node_promote_action';
+}
+function rules_core_node_unpromote_action_upgrade_map_name($element) {
+  return 'node_unpromote_action';
+}
+
+
+// Path.module integration.
+function rules_condition_url_has_alias_upgrade_map_name($element) {
+  return 'path_has_alias';
+}
+function rules_condition_url_has_alias_upgrade($element, $target) {
+  $target->settings['source'] = $element['#settings']['src'];
+  $target->settings['alias'] = $element['#settings']['dst'];
+}
+function rules_condition_alias_exists_upgrade_map_name($element) {
+  return 'path_alias_exists';
+}
+function rules_condition_alias_exists_upgrade($element, $target) {
+  $target->settings['alias'] = $element['#settings']['dst'];
+}
+function rules_action_path_alias_upgrade($element, $target) {
+  $target->settings['source'] = $element['#settings']['src'];
+  $target->settings['alias'] = $element['#settings']['dst'];
+}
+function rules_action_node_path_alias_upgrade($element, $target) {
+  $target->settings['alias'] = $element['#settings']['dst'];
+}
+
+// PHP.module integration.
+function rules_condition_custom_php_upgrade_map_name($element) {
+  return 'php_eval';
+}
+function rules_action_custom_php_upgrade_map_name($element) {
+  return 'php_eval';
+}
+
+// General Rules integration.
+function rules_condition_text_compare_upgrade_map_name($element) {
+  // @todo: Support regex.
+  return 'data_is';
+}
+function rules_condition_text_compare_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'text1', 'data');
+  rules_upgrade_element_parameter_settings($element, $target, 'text2', 'value');
+}
+function rules_condition_number_compare_upgrade_map_name($element) {
+  return 'data_is';
+}
+function rules_condition_number_compare_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'number1', 'data');
+  rules_upgrade_element_parameter_settings($element, $target, 'number2', 'value');
+}
+function rules_condition_check_boolean_upgrade_map_name($element) {
+  return 'data_is';
+}
+function rules_condition_check_boolean_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'boolean', 'data');
+  $target->settings['value'] = TRUE;
+}
+function rules_action_invoke_set_upgrade_map_name($element) {
+  return 'component_' . $element['#info']['set'];
+}
+function rules_action_invoke_set_upgrade($element, $target) {
+  foreach ($element['#info']['arguments'] as $name => $info) {
+    rules_upgrade_element_parameter_settings($element, $target, $name);
+  }
+}
+function rules_action_save_variable_upgrade_map_name($element) {
+  return isset($element['#info']['new variables']) ? 'variable_add' : 'entity_save';
+}
+function rules_action_save_variable_upgrade($element, $target) {
+  $type = $element['#info']['arguments']['var_name']['default value'];
+  if (isset($element['#info']['new variables'])) {
+    $target->settings['type'] = $type;
+    rules_upgrade_element_parameter_settings($element, $target, $type, 'value');
+    rules_upgrade_element_variable_settings($element, $target, $type, 'variable_added');
+  }
+  else {
+    rules_upgrade_element_parameter_settings($element, $target, $type, 'entity');
+  }
+}
+
+
+// System.module integration.
+function rules_action_set_breadcrumb_upgrade_map_name($element) {
+  return 'breadcumb_set';
+}
+function rules_action_mail_to_user_upgrade_map_name($element) {
+  return 'mail';
+}
+function rules_action_mail_to_user_upgrade($element, $target) {
+  $target->settings['to:select'] = $element['#settings']['#argument map']['user'] . ':mail';
+}
+function rules_action_drupal_goto_upgrade_map_name($element) {
+  return 'redirect';
+}
+function rules_action_drupal_goto_upgrade($element, $target) {
+  $settings = $element['#settings'];
+  $target->settings['url'] = $settings['path'];
+  $target->settings['url'] .= $settings['query'] ? '?' . $settings['query'] : '';
+  $target->settings['url'] .= $settings['fragment'] ? '#' . $settings['fragment'] : '';
+  if ($settings['immediate']) {
+    drupal_set_message(t("Warning: The 'immediate' option for the page redirect action has been dropped in Rules 2.x."));
+  }
+}
+
+function rules_action_watchdog_upgrade_map_name($element) {
+  // @todo: Support action in Rules 2.x!
+  return NULL;
+}
+
+// Taxonomy.module integration.
+// @todo: Finish.
+function rules_action_taxonomy_load_term_upgrade_map_name($element) {
+  return 'entity_fetch';
+}
+function rules_action_taxonomy_add_term_upgrade_map_name($element) {
+  return 'entity_create';
+}
+function rules_action_taxonomy_delete_term_upgrade_map_name($element) {
+  return 'entity_delete';
+}
+function rules_action_taxonomy_term_assign_to_content_upgrade_map_name($element) {
+  // @todo : list.
+  return NULL;
+}
+function rules_action_taxonomy_term_remove_from_content_upgrade_map_name($element) {
+  // @todo : list.
+  return NULL;
+}
+function rules_action_taxonomy_load_vocab_upgrade_map_name($element) {
+  return 'entity_fetch';
+}
+function rules_action_taxonomy_add_vocab_upgrade_map_name($element) {
+  return 'data_set';
+}
+
+// User.module integration.
+function rules_condition_user_hasrole_upgrade_map_name($element) {
+  return 'user_has_role';
+}
+function rules_condition_user_hasrole_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'user', 'account');
+}
+function rules_condition_user_comparison_upgrade_map_name($element) {
+  return 'data_is';
+}
+function rules_condition_user_comparison_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'user1', 'data');
+  rules_upgrade_element_parameter_settings($element, $target, 'user2', 'value');
+}
+function rules_action_user_addrole_upgrade_map_name($element) {
+  return 'user_add_role';
+}
+function rules_action_user_addrole_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'user', 'account');
+}
+function rules_action_user_removerole_upgrade_map_name($element) {
+  return 'user_remove_role';
+}
+function rules_action_user_removerole_upgrade($element, $target) {
+  rules_upgrade_element_parameter_settings($element, $target, 'user', 'account');
+}
+function rules_action_load_user_upgrade_map_name($element) {
+  if (!empty($element['#settings']['username'])) {
+    drupal_set_message(t('Warning: Directly upgrading the load user by name action is not supported.'));
+  }
+  return 'entity_fetch';
+}
+function rules_action_load_user_upgrade($element, $target) {
+  $target->settings['type'] = 'user';
+  rules_upgrade_element_parameter_settings($element, $target, 'userid', 'id');
+  rules_upgrade_element_variable_settings($element, $target, 'user_loaded', 'entity_fetched');
+}
+function rules_action_user_create_upgrade_map_name($element) {
+  return 'entity_create';
+}
+function rules_action_user_create_upgrade($element, $target) {
+  $target->settings['type'] = 'user';
+  rules_upgrade_element_parameter_settings($element, $target, 'username', 'param_name');
+  rules_upgrade_element_parameter_settings($element, $target, 'email', 'param_mail');
+  rules_upgrade_element_variable_settings($element, $target, 'user_added', 'entity_created');
+
+}
+function rules_core_user_block_user_action_upgrade_map_name($element) {
+  return 'user_block';
+}
+function rules_core_user_block_user_action_upgrade($element, $target) {
+  $target->settings['account:select'] = $element['#settings']['#argument map']['user'];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/comment.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file rules integration for the comment module
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implementation of hook_rules_event_info().
+ */
+function rules_comment_event_info() {
+  $defaults = array(
+    'group' => t('comment'),
+    'module' => 'comment',
+    'access callback' => 'rules_comment_integration_access',
+    'class' => 'RulesCommentEventHandler',
+  );
+  return array(
+    'comment_insert' => $defaults + array(
+      'label' => t('After saving a new comment'),
+      'variables' => array(
+        'comment' => array('type' => 'comment', 'label' => t('created comment')),
+      ),
+    ),
+    'comment_update' => $defaults + array(
+      'label' => t('After updating an existing comment'),
+      'variables' => array(
+        'comment' => array('type' => 'comment', 'label' => t('updated comment')),
+        'comment_unchanged' => array('type' => 'comment', 'label' => t('unchanged comment'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+    ),
+    'comment_presave' => $defaults + array(
+      'label' => t('Before saving a comment'),
+      'variables' => array(
+        'comment' => array('type' => 'comment', 'label' => t('saved comment'), 'skip save' => TRUE),
+        'comment_unchanged' => array('type' => 'comment', 'label' => t('unchanged comment'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+    ),
+    'comment_view' => $defaults + array(
+      'label' => t('A comment is viewed'),
+      'variables' => array(
+        'comment' => array('type' => 'comment', 'label' => t('viewed comment')),
+      ),
+      'help' => t("Note that if drupal's page cache is enabled, this event won't be generated for pages served from cache."),
+    ),
+    'comment_delete' => $defaults + array(
+      'label' => t('After deleting a comment'),
+      'variables' => array(
+        'comment' => array('type' => 'comment', 'label' => t('deleted comment')),
+      ),
+    ),
+  );
+}
+
+/**
+ * Comment integration access callback.
+ */
+function rules_comment_integration_access($type, $name) {
+  if ($type == 'event' || $type == 'condition') {
+    return entity_access('view', 'comment');
+  }
+}
+
+/**
+ * Event handler support comment bundle event settings.
+ */
+class RulesCommentEventHandler extends RulesEventHandlerEntityBundle {
+
+  /**
+   * Returns the label to use for the bundle property.
+   *
+   * @return string
+   */
+  protected function getBundlePropertyLabel() {
+    return t('type');
+  }
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/data.eval.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,404 @@
+<?php
+
+/**
+ * @file
+ * Contains rules integration for the data module needed during evaluation.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Action: Modify data.
+ */
+function rules_action_data_set($wrapper, $value, $settings, $state, $element) {
+  if ($wrapper instanceof EntityMetadataWrapper) {
+    try {
+      // Update the value first then save changes, if possible.
+      $wrapper->set($value);
+    }
+    catch (EntityMetadataWrapperException $e) {
+      throw new RulesEvaluationException('Unable to modify data "@selector": ' . $e->getMessage(), array('@selector' => $settings['data:select']));
+    }
+    // Save changes if a property of a variable has been changed.
+    if (strpos($element->settings['data:select'], ':') !== FALSE) {
+      $info = $wrapper->info();
+      // We always have to save the changes in the parent entity. E.g. when the
+      // node author is changed, we don't want to save the author but the node.
+      $state->saveChanges(implode(':', explode(':', $settings['data:select'], -1)), $info['parent']);
+    }
+  }
+  else {
+    // A not wrapped variable (e.g. a number) is being updated. Just overwrite
+    // the variable with the new value.
+    return array('data' => $value);
+  }
+}
+
+/**
+ * Info alter callback for the data_set action.
+ */
+function rules_action_data_set_info_alter(&$element_info, $element) {
+  $element->settings += array('data:select' => NULL);
+  if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) {
+    $info = $wrapper->info();
+    $element_info['parameter']['value']['type'] = $wrapper->type();
+    $element_info['parameter']['value']['options list']  = !empty($info['options list']) ? 'rules_data_selector_options_list' : FALSE;
+  }
+}
+
+/**
+ * Action: Calculate a value.
+ */
+function rules_action_data_calc($input1, $op, $input2, $settings, $state, $element) {
+  $info = $element->pluginParameterInfo();
+  // Make sure to apply date offsets intelligently.
+  if ($info['input_1']['type'] == 'date' && $info['input_2']['type'] == 'duration') {
+    $input2 = ($op == '-') ? $input2 * -1 : $input2;
+    return array('result' => (int) RulesDateOffsetProcessor::applyOffset($input1, $input2));
+  }
+
+  switch ($op) {
+    case '+':
+      $result = $input1 + $input2;
+      break;
+    case '-':
+      $result = $input1 - $input2;
+      break;
+    case '*':
+      $result = $input1 * $input2;
+      break;
+    case '/':
+      $result = $input1 / $input2;
+      break;
+    case 'min':
+      $result = min($input1, $input2);
+      break;
+    case 'max':
+      $result = max($input1, $input2);
+      break;
+  }
+  if (isset($result)) {
+    // Ensure results are valid integer values if necessary.
+    $variables = $element->providesVariables();
+    $var_info = reset($variables);
+    if ($var_info['type'] == 'integer') {
+      $result = (int) $result;
+    }
+    return array('result' => $result);
+  }
+}
+
+/**
+ * Info alter callback for the data_calc action.
+ */
+function rules_action_data_calc_info_alter(&$element_info, RulesPlugin $element) {
+  if ($info = $element->getArgumentInfo('input_1')) {
+    // Only allow durations as offset for date values.
+    if ($info['type'] == 'date') {
+      $element_info['parameter']['input_2']['type'] = 'duration';
+    }
+    // Specify the data type of the result.
+    $element_info['provides']['result']['type'] = $info['type'];
+
+    if ($info['type'] == 'integer' && ($info2 = $element->getArgumentInfo('input_2')) && $info2['type'] == 'decimal') {
+      $element_info['provides']['result']['type'] = 'decimal';
+    }
+    // A division with two integers results in a decimal.
+    elseif (isset($element->settings['op']) && $element->settings['op'] == '/') {
+      $element_info['provides']['result']['type'] = 'decimal';
+    }
+  }
+}
+
+/**
+ * Action: Add a list item.
+ */
+function rules_action_data_list_add($list, $item, $unique = FALSE, $pos = 'end', $settings, $state) {
+  // Optionally, only add the list item if it is not yet contained.
+  if ($unique && rules_condition_data_list_contains($list, $item, $settings, $state)) {
+    return;
+  }
+
+  switch ($pos) {
+    case 'start':
+      array_unshift($list, $item);
+      break;
+
+    default:
+      $list[] = $item;
+      break;
+  }
+  return array('list' => $list);
+}
+
+/**
+ * Info alteration callback for the "Add and Remove a list item" actions.
+ */
+function rules_data_list_info_alter(&$element_info, RulesAbstractPlugin $element) {
+  // Update the required type for the list item if it is known.
+  $element->settings += array('list:select' => NULL);
+  if ($wrapper = $element->applyDataSelector($element->settings['list:select'])) {
+    if ($type = entity_property_list_extract_type($wrapper->type())) {
+      $info = $wrapper->info();
+      $element_info['parameter']['item']['type'] = $type;
+      $element_info['parameter']['item']['options list']  = !empty($info['options list']) ? 'rules_data_selector_options_list' : FALSE;
+    }
+  }
+}
+
+/**
+ * Action: Remove a list item.
+ */
+function rules_action_data_list_remove($list, $item) {
+  foreach (array_keys($list, $item) as $key) {
+    unset($list[$key]);
+  }
+  return array('list' => $list);
+}
+
+/**
+ * Action: Add variable.
+ */
+function rules_action_variable_add($args, $element) {
+  return array('variable_added' => $args['value']);
+}
+
+/**
+ * Info alteration callback for variable add action.
+ */
+function rules_action_variable_add_info_alter(&$element_info, RulesAbstractPlugin $element) {
+  if (isset($element->settings['type']) && $type = $element->settings['type']) {
+    $cache = rules_get_cache();
+    $type_info = $cache['data_info'][$type];
+    $element_info['parameter']['value']['type'] = $type;
+    $element_info['provides']['variable_added']['type'] = $type;
+
+    // For lists, we default to an empty list so subsequent actions can add
+    // items.
+    if (entity_property_list_extract_type($type)) {
+      $element_info['parameter']['value']['default value'] = array();
+    }
+  }
+}
+
+/**
+ * Action: Convert a value.
+ */
+function rules_action_data_convert($arguments, RulesPlugin $element, $state) {
+
+  $value_info = $element->getArgumentInfo('value');
+  $from_type = $value_info['type'];
+  $target_type = $arguments['type'];
+
+  // First apply the rounding behavior if given.
+  if (isset($arguments['rounding_behavior'])) {
+    switch ($arguments['rounding_behavior']) {
+      case 'up':
+        $arguments['value'] = ceil($arguments['value']);
+        break;
+      case 'down':
+        $arguments['value'] = floor($arguments['value']);
+        break;
+      default:
+      case 'round':
+        $arguments['value'] = round($arguments['value']);
+        break;
+    }
+  }
+
+  switch ($target_type) {
+    case 'decimal':
+      $result = floatval($arguments['value']);
+      break;
+    case 'integer':
+      $result = intval($arguments['value']);
+      break;
+    case 'text':
+      $result = strval($arguments['value']);
+      break;
+  }
+
+  return array('conversion_result' => $result);
+}
+
+/**
+ * Info alteration callback for variable add action.
+ */
+function rules_action_data_convert_info_alter(&$element_info, RulesAbstractPlugin $element) {
+
+  if (isset($element->settings['type']) && $type = $element->settings['type']) {
+    $element_info['provides']['conversion_result']['type'] = $type;
+
+    if ($type != 'integer') {
+      // Only support the rounding behavior option for integers.
+      unset($element_info['parameter']['rounding_behavior']);
+    }
+
+    // Configure compatible source-types:
+    switch ($type) {
+      case 'integer':
+        $sources = array('decimal', 'text', 'token', 'uri', 'date', 'duration', 'boolean');
+        break;
+      case 'decimal':
+        $sources = array('integer', 'text', 'token', 'uri', 'date', 'duration', 'boolean');
+        break;
+      case 'text':
+        $sources = array('integer', 'decimal', 'token', 'uri', 'date', 'duration', 'boolean');
+        break;
+    }
+    $element_info['parameter']['value']['type'] = $sources;
+  }
+}
+
+/**
+ * Action: Create data.
+ */
+function rules_action_data_create($args, $element) {
+  $type = $args['type'];
+  $values = array();
+  foreach ($element->pluginParameterInfo() as $name => $info) {
+    if ($name != 'type') {
+      // Remove the parameter name prefix 'param_'.
+      $values[substr($name, 6)] = $args[$name];
+    }
+  }
+  $cache = rules_get_cache();
+  $type_info = $cache['data_info'][$type];
+  if (isset($type_info['creation callback'])) {
+    try {
+      $data = $type_info['creation callback']($values, $type);
+      return array('data_created' => $data);
+    }
+    catch (EntityMetadataWrapperException $e) {
+      throw new RulesEvaluationException('Unable to create @data": ' . $e->getMessage(), array('@data' => $type), $element);
+    }
+  }
+  else {
+    throw new RulesEvaluationException('Unable to create @data, no creation callback found.', array('@data' => $type), $element, RulesLog::ERROR);
+  }
+}
+
+/**
+ * Info alteration callback for data create action.
+ */
+function rules_action_data_create_info_alter(&$element_info, RulesAbstractPlugin $element) {
+  if (!empty($element->settings['type'])) {
+    $type = $element->settings['type'];
+    $cache = rules_get_cache();
+    $type_info = $cache['data_info'][$type];
+    if (isset($type_info['property info'])) {
+      // Add the data type's properties as parameters.
+      foreach ($type_info['property info'] as $property => $property_info) {
+        // Prefix parameter names to avoid name clashes with existing parameters.
+        $element_info['parameter']['param_' . $property] = array_intersect_key($property_info, array_flip(array('type', 'label', 'allow null')));
+        if (empty($property_info['required'])) {
+          $element_info['parameter']['param_' . $property]['optional'] = TRUE;
+        }
+      }
+    }
+    $element_info['provides']['data_created']['type'] = $type;
+  }
+}
+
+/**
+ * Creation callback for array structured data.
+ */
+function rules_action_data_create_array($values = array(), $type) {
+  // $values is an array already, so we can just pass it to the wrapper.
+  return rules_wrap_data($values, array('type' => $type));
+}
+
+/**
+ * Condition: Compare data.
+ */
+function rules_condition_data_is($data, $op, $value) {
+  switch ($op) {
+    default:
+    case '==':
+      // In case both values evaluate to FALSE, further differentiate between
+      // NULL values and values evaluating to FALSE.
+      if (!$data && !$value) {
+        return (isset($data) && isset($value)) || (!isset($data) && !isset($value));
+      }
+      return $data == $value;
+    case '<':
+      return $data < $value;
+    case '>':
+      return $data > $value;
+      // Note: This is deprecated by the text comparison condition and IN below.
+    case 'contains':
+      return is_string($data) && strpos($data, $value) !== FALSE || is_array($data) && in_array($value, $data);
+    case 'IN':
+      return is_array($value) && in_array($data, $value);
+  }
+}
+
+/**
+ * Info alteration callback for the data_is condition.
+ *
+ * If we check the bundle property of a variable, add an assertion so that later
+ * evaluated elements can make use of this information.
+ */
+function rules_condition_data_is_info_alter(&$element_info, RulesAbstractPlugin $element) {
+  $element->settings += array('data:select' => NULL, 'op' => '==');
+  if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) {
+    $info = $wrapper->info();
+    $element_info['parameter']['value']['type'] = $element->settings['op'] == 'IN' ? 'list<' . $wrapper->type() . '>' : $wrapper->type();
+    $element_info['parameter']['value']['options list']  = !empty($info['options list']) ? 'rules_data_selector_options_list' : FALSE;
+  }
+}
+
+/**
+ * Condition: List contains.
+ */
+function rules_condition_data_list_contains($list, $item, $settings, $state) {
+  $wrapper = $state->currentArguments['item'];
+  if ($wrapper instanceof EntityStructureWrapper && $id = $wrapper->getIdentifier()) {
+    // Check for equal items using the identifier if there is one.
+    foreach ($state->currentArguments['list'] as $i) {
+      if ($i->getIdentifier() == $id) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+  return in_array($item, $list);
+}
+
+/**
+ * Condition: Data value is empty.
+ */
+function rules_condition_data_is_empty($data) {
+  // Note that some primitive variables might not be wrapped at all.
+  if ($data instanceof EntityMetadataWrapper) {
+    try {
+      // We cannot use the dataAvailable() method from the wrapper because it
+      // is protected, so we catch possible exceptions with the value() method.
+      $value = $data->value();
+      return empty($value);
+    }
+    catch (EntityMetadataWrapperException $e) {
+      // An exception means that the wrapper is somehow broken and we treat
+      // that as empty.
+      return TRUE;
+    }
+  }
+  return empty($data);
+}
+
+/**
+ * Condition: Textual comparison.
+ */
+function rules_data_text_comparison($text, $text2, $op = 'contains') {
+  switch ($op) {
+    case 'contains':
+      return strpos($text, $text2) !== FALSE;
+    case 'starts':
+      return strpos($text, $text2) === 0;
+    case 'ends':
+     return strrpos($text, $text2) === (strlen($text) - strlen($text2));
+    case 'regex':
+     return (bool) preg_match('/'. str_replace('/', '\\/', $text2) .'/', $text);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/data.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,724 @@
+<?php
+
+/**
+ * @file General data related rules integration
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_category_info() on behalf of the pseudo data module.
+ */
+function rules_data_category_info() {
+  return array(
+    'rules_data' => array(
+      'label' => t('Data'),
+      'equals group' => t('Data'),
+      'weight' => -50,
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_file_info() on behalf of the pseudo data module.
+ * @see rules_core_modules()
+ */
+function rules_data_file_info() {
+  return array('modules/data.eval');
+}
+
+/**
+ * Implements hook_rules_action_info() on behalf of the pseudo data module.
+ * @see rules_core_modules()
+ */
+function rules_data_action_info() {
+  $return['data_set'] = array(
+    'label' => t('Set a data value'),
+    'parameter' => array(
+      'data' => array(
+        'type' => '*',
+        'label' => t('Data'),
+        'description' => t('Specifies the data to be modified using a data selector, e.g. "node:author:name".'),
+        'restriction' => 'selector',
+        'wrapped' => TRUE,
+        'allow null' => TRUE,
+      ),
+      'value' => array(
+        'type' => '*',
+        'label' => t('Value'),
+        'description' => t('The new value to set for the specified data.'),
+        'allow null' => TRUE,
+        'optional' => TRUE,
+      ),
+    ),
+    'group' => t('Data'),
+    'base' => 'rules_action_data_set',
+  );
+  $return['data_calc'] = array(
+    'label' => t('Calculate a value'),
+    'parameter' => array(
+      'input_1' => array(
+        'type' => array('decimal', 'date'),
+        'label' => t('Input value 1'),
+        'description' => t('The first input value for the calculation.'),
+      ),
+      'op' => array(
+        'type' => 'text',
+        'label' => t('Operator'),
+        'description' => t('The calculation operator.'),
+        'options list' => 'rules_action_data_calc_operator_options',
+        'restriction' => 'input',
+        'default value' => '+',
+      ),
+      'input_2' => array(
+        'type' => 'decimal',
+        'label' => t('Input value 2'),
+        'description' => t('The second input value.'),
+      ),
+    ),
+    'group' => t('Data'),
+    'base' => 'rules_action_data_calc',
+    'provides' => array(
+      'result' => array(
+        'type' => 'unknown',
+        'label' => t('Calculation result'),
+      ),
+    ),
+  );
+  $return['list_add'] = array(
+    'label' => t('Add an item to a list'),
+    'parameter' => array(
+      'list' => array(
+        'type' => 'list',
+        'label' => t('List', array(), array('context' => 'data_types')),
+        'description' => t('The data list, to which an item is to be added.'),
+        'restriction' => 'selector',
+        'allow null' => TRUE,
+        'save' => TRUE,
+      ),
+      'item' => array(
+        'type' => 'unknown',
+        'label' => t('Item to add'),
+      ),
+      'unique' => array(
+        'type' => 'boolean',
+        'label' => t('Enforce uniqueness'),
+        'description' => t('Only add the item to the list if it is not yet contained.'),
+        'optional' => TRUE,
+        'default value' => FALSE,
+      ),
+      'pos' => array(
+        'type' => 'text',
+        'label' => t('Insert position'),
+        'optional' => TRUE,
+        'default value' => 'end',
+        'options list' => 'rules_action_data_list_add_positions',
+      ),
+    ),
+    'group' => t('Data'),
+    'base' => 'rules_action_data_list_add',
+    'callbacks' => array(
+      'info_alter' => 'rules_data_list_info_alter',
+      'form_alter' => 'rules_data_list_form_alter',
+    ),
+  );
+  $return['list_remove'] = array(
+    'label' => t('Remove an item from a list'),
+    'parameter' => array(
+      'list' => array(
+        'type' => 'list',
+        'label' => t('List', array(), array('context' => 'data_types')),
+        'description' => t('The data list for which an item is to be removed.'),
+        'restriction' => 'selector',
+        'save' => TRUE,
+      ),
+      'item' => array(
+        'type' => 'unknown',
+        'label' => t('Item to remove'),
+      ),
+    ),
+    'group' => t('Data'),
+    'base' => 'rules_action_data_list_remove',
+    'callbacks' => array(
+      'info_alter' => 'rules_data_list_info_alter',
+      'form_alter' => 'rules_data_list_form_alter',
+    ),
+  );
+  $return['variable_add'] = array(
+    'label' => t('Add a variable'),
+    'named parameter' => TRUE,
+    'parameter' => array(
+      'type' => array(
+        'type' => 'text',
+        'label' => t('Type'),
+        'options list' => 'rules_data_action_variable_add_options',
+        'description' => t('Specifies the type of the variable that should be added.'),
+        'restriction' => 'input',
+      ),
+      'value' => array(
+        'type' => 'unknown',
+        'label' => t('Value'),
+        'optional' => TRUE,
+        'description' => t('Optionally, specify the initial value of the variable.')
+      ),
+    ),
+    'provides' => array(
+      'variable_added' => array(
+        'type' => 'unknown',
+        'label' => t('Added variable'),
+      ),
+    ),
+    'group' => t('Data'),
+    'base' => 'rules_action_variable_add',
+    'callbacks' => array(
+      'form_alter' => 'rules_action_type_form_alter',
+      'validate' => 'rules_action_create_type_validate',
+    ),
+  );
+
+  if (rules_data_action_data_create_options()) {
+    $return['data_create'] = array(
+      'label' => t('Create a data structure'),
+      'named parameter' => TRUE,
+      'parameter' => array(
+        'type' => array(
+          'type' => 'text',
+          'label' => t('Type'),
+          'options list' => 'rules_data_action_data_create_options',
+          'description' => t('Specifies the type of the data structure that should be created.'),
+          'restriction' => 'input',
+        ),
+        // Further needed parameters depend on the type.
+      ),
+      'provides' => array(
+        'data_created' => array(
+          'type' => 'unknown',
+          'label' => t('Created data'),
+        ),
+      ),
+      'group' => t('Data'),
+      'base' => 'rules_action_data_create',
+      'callbacks' => array(
+        'form_alter' => 'rules_action_type_form_alter',
+        'validate' => 'rules_action_create_type_validate',
+      ),
+    );
+  }
+  $return['data_convert'] = array(
+    'label' => t('Convert data type'),
+    'parameter' => array(
+      'type' => array(
+        'type' => 'token',
+        'label' => t('Target type'),
+        'description' => t('The data type to convert a value to.'),
+        'options list' => 'rules_action_data_convert_types_options',
+        'restriction' => 'input',
+      ),
+      'value' => array(
+        'type' => array('decimal', 'integer', 'text'),
+        'label' => t('Value to convert'),
+        'default mode' => 'selector',
+      ),
+      // For to-integer conversion only.
+      'rounding_behavior' => array(
+        'type' => 'token',
+        'label' => t('Rounding behavior'),
+        'description' => t('The rounding behavior the conversion should use.'),
+        'options list' => 'rules_action_data_convert_rounding_behavior_options',
+        'restriction' => 'input',
+        'default value' => 'round',
+        'optional' => TRUE,
+      ),
+    ),
+    'provides' => array(
+      'conversion_result' => array(
+        'type' => 'unknown',
+        'label' => t('Conversion result'),
+      ),
+    ),
+    'group' => t('Data'),
+    'base' => 'rules_action_data_convert',
+    'named parameter' => TRUE,
+    'callbacks' => array(
+      'form_alter' => 'rules_action_type_form_alter',
+    ),
+  );
+  return $return;
+}
+
+/**
+ * Data conversation action: Options list callback for the target type.
+ */
+function rules_action_data_convert_types_options(RulesPlugin $element, $param_name) {
+  return array(
+    'decimal' => t('Decimal'),
+    'integer' => t('Integer'),
+    'text' => t('Text'),
+  );
+}
+
+/**
+ * Data conversation action: Options list callback for rounding behavior.
+ */
+function rules_action_data_convert_rounding_behavior_options(RulesPlugin $element, $param_name) {
+  return array(
+    'down' => t('Always down (9.5 -> 9)'),
+    'round' => t('Round, half up (9.5 -> 10)'),
+    'up' => t('Always up (9.5 -> 10)'),
+  );
+}
+
+/**
+ * Customize access check for data set action.
+ */
+function rules_action_data_set_access(RulesAbstractPlugin $element) {
+  if (isset($element->settings['data:select']) && $wrapper = $element->applyDataSelector($element->settings['data:select'])) {
+    return $wrapper instanceof EntityMetadataWrapper && $wrapper->access('edit');
+  }
+}
+
+/**
+ * Custom validation callback for the data set action.
+ */
+function rules_action_data_set_validate(RulesAbstractPlugin $element) {
+  $element->settings += array('data:select' => NULL);
+  $info = $element->applyDataSelector($element->settings['data:select'])->info();
+  if (strpos($element->settings['data:select'], ':') !== FALSE && empty($info['setter callback'])) {
+    throw new RulesIntegrityException(t("The selected data property doesn't support writing."), array($element, 'parameter', 'data'));
+  }
+}
+
+/**
+ * Form alter callback for the data_set action.
+ */
+function rules_action_data_set_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+  if (!empty($options['init']) && !isset($form_state['rules_element_step'])) {
+    $form['negate']['#access'] = FALSE;
+    unset($form['parameter']['value']);
+    unset($form['parameter']['language']);
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Continue'),
+      '#limit_validation_errors' => array(array('parameter', 'data')),
+      '#submit' => array('rules_form_submit_rebuild'),
+    );
+    $form_state['rules_element_step'] = 'data_value';
+    // Clear the parameter mode for the value parameter, so its gets the proper
+    // default value based upon the type of the the selected data on rebuild.
+    unset($form_state['parameter_mode']['value']);
+  }
+  else {
+    // Change the data parameter to be not editable.
+    $form['parameter']['data']['settings']['#access'] = FALSE;
+    // TODO: improve display
+    $form['parameter']['data']['info'] = array(
+      '#prefix' => '<p>',
+      '#markup' => t('<strong>Selected data:</strong> %selector', array('%selector' => $element->settings['data:select'])),
+      '#suffix' => '</p>',
+    );
+  }
+}
+
+/**
+ * Form alter callback for the data calculation action.
+ */
+function rules_action_data_calc_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+
+  $form['reload'] = array(
+    '#weight' => 5,
+    '#type' => 'submit',
+    '#name' => 'reload',
+    '#value' => t('Reload form'),
+    '#limit_validation_errors' => array(array('parameter', 'input_1')),
+    '#submit' => array('rules_form_submit_rebuild'),
+    '#ajax' => rules_ui_form_default_ajax(),
+  );
+}
+
+/**
+ * Custom validate callback for entity create, add variable and data create
+ * action.
+ */
+function rules_action_create_type_validate($element) {
+  if (!isset($element->settings['type'])) {
+    throw new RulesIntegrityException(t('Invalid type specified.'), array($element, 'parameter', 'type'));
+  }
+}
+
+/**
+ * Form alter callback for the list add and remove actions.
+ *
+ * Use multiple steps to configure the action to update the item configuration
+ * form once we know the data type.
+ *
+ * @see rules_data_list_info_alter()
+ */
+function rules_data_list_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+  if (!empty($options['init']) && !isset($form_state['rules_element_step'])) {
+    unset($form['parameter']['item'], $form['parameter']['pos']);
+    $form_state['rules_element_step'] = 1;
+    $form['negate']['#access'] = FALSE;
+    $form['parameter']['unique']['#access'] = FALSE;
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Continue'),
+      '#limit_validation_errors' => array(array('parameter', 'list')),
+      '#submit' => array('rules_form_submit_rebuild'),
+    );
+  }
+  else {
+    // Change the list parameter to be not editable any more.
+    $form['parameter']['list']['settings']['#access'] = FALSE;
+    $form['parameter']['list']['info'] = array(
+      '#prefix' => '<p>',
+      '#markup' => t('<strong>Selected list:</strong> %selector', array('%selector' => $element->settings['list:select'])),
+      '#suffix' => '</p>',
+    );
+  }
+}
+
+
+/**
+ * Form alter callback for actions relying on the entity type or the data type.
+ */
+function rules_action_type_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+  $first_step = empty($element->settings['type']);
+  $form['reload'] = array(
+    '#weight' => 5,
+    '#type' => 'submit',
+    '#name' => 'reload',
+    '#value' => $first_step ? t('Continue') : t('Reload form'),
+    '#limit_validation_errors' => array(array('parameter', 'type')),
+    '#submit' => array('rules_action_type_form_submit_rebuild'),
+    '#ajax' => rules_ui_form_default_ajax(),
+  );
+  // Use ajax and trigger as the reload button.
+  $form['parameter']['type']['settings']['type']['#ajax'] = $form['reload']['#ajax'] + array(
+    'event' => 'change',
+    'trigger_as' => array('name' => 'reload'),
+  );
+
+  if ($first_step) {
+    // In the first step show only the type select.
+    foreach (element_children($form['parameter']) as $key) {
+      if ($key != 'type') {
+        unset($form['parameter'][$key]);
+      }
+    }
+    unset($form['submit']);
+    unset($form['provides']);
+    // Disable #ajax for the first step as it has troubles with lazy-loaded JS.
+    // @todo: Re-enable once JS lazy-loading is fixed in core.
+    unset($form['parameter']['type']['settings']['type']['#ajax']);
+    unset($form['reload']['#ajax']);
+  }
+  else {
+    // Hide the reload button in case js is enabled and it's not the first step.
+    $form['reload']['#attributes'] = array('class' => array('rules-hide-js'));
+  }
+}
+
+/**
+ * FAPI submit callback for reloading the type form for entities or data types.
+ */
+function rules_action_type_form_submit_rebuild($form, &$form_state) {
+  rules_form_submit_rebuild($form, $form_state);
+  // Clear the parameter modes for the parameters, so they get the proper
+  // default values based upon the data types on rebuild.
+  $form_state['parameter_mode'] = array();
+}
+
+/**
+ * Options list callback for possible insertion positions.
+ */
+function rules_action_data_list_add_positions() {
+  return array(
+    'end' => t('Append the item to the end.'),
+    'start' => t('Prepend the item to the front.'),
+  );
+}
+
+/**
+ * Options list callback for variable add action.
+ */
+function rules_data_action_variable_add_options() {
+  return RulesPluginUI::getOptions('data');
+}
+
+/**
+ * Options list callback for the data calculation action.
+ */
+function rules_action_data_calc_operator_options(RulesPlugin $element, $param_name) {
+  $options = array(
+    '+' => '( + )',
+    '-' => '( - )',
+    '*' => '( * )',
+    '/' => '( / )',
+    'min' => 'min',
+    'max' => 'max',
+  );
+  // Only show +/- in case a date has been selected.
+  if (($info = $element->getArgumentInfo('input_1')) && $info['type'] == 'date') {
+    unset($options['*']);
+    unset($options['/']);
+  }
+  return $options;
+}
+
+/**
+ * Options list callback for data create action.
+ */
+function rules_data_action_data_create_options() {
+  $cache = rules_get_cache();
+  $data_info = $cache['data_info'];
+  $entity_info = entity_get_info();
+  // Remove entities.
+  $data_info = array_diff_key($data_info, $entity_info);
+  $options = array();
+  foreach ($data_info as $type => $properties) {
+    if (isset($properties['creation callback'])) {
+      // Add data types with creation callback only.
+      $options[$type] = $properties['label'];
+    }
+  }
+  natcasesort($options);
+  return $options;
+}
+
+/**
+ * Implements hook_rules_condition_info() on behalf of the pseudo data module.
+ * @see rules_core_modules()
+ */
+function rules_data_condition_info() {
+  return array(
+    'data_is' => array(
+      'label' => t('Data comparison'),
+      'parameter' => array(
+        'data' => array(
+          'type' => '*',
+          'label' => t('Data to compare'),
+          'description' => t('The data to be compared, specified by using a data selector, e.g. "node:author:name".'),
+          'allow null' => TRUE,
+        ),
+        'op' => array(
+          'type' => 'text',
+          'label' => t('Operator'),
+          'description' => t('The comparison operator.'),
+          'optional' => TRUE,
+          'default value' => '==',
+          'options list' => 'rules_condition_data_is_operator_options',
+          'restriction' => 'input',
+        ),
+        'value' => array(
+          'type' => '*',
+          'label' => t('Data value'),
+          'description' => t('The value to compare the data with.'),
+          'allow null' => TRUE,
+        ),
+      ),
+      'group' => t('Data'),
+      'base' => 'rules_condition_data_is',
+    ),
+    'data_is_empty' => array(
+      'label' => t('Data value is empty'),
+      'parameter' => array(
+        'data' => array(
+          'type' => '*',
+          'label' => t('Data to check'),
+          'description' => t('The data to be checked to be empty, specified by using a data selector, e.g. "node:author:name".'),
+          'allow null' => TRUE,
+          'wrapped' => TRUE,
+        ),
+      ),
+      'group' => t('Data'),
+      'base' => 'rules_condition_data_is_empty',
+    ),
+    'list_contains'  => array(
+      'label' => t('List contains item'),
+      'parameter' => array(
+        'list' => array(
+          'type' => 'list',
+          'label' => t('List', array(), array('context' => 'data_types')),
+          'restriction' => 'selector',
+        ),
+        'item' => array(
+          'type' => 'unknown',
+          'label' => t('Item'),
+          'description' => t('The item to check for.'),
+        ),
+      ),
+      'group' => t('Data'),
+      'base' => 'rules_condition_data_list_contains',
+      'callbacks' => array(
+        'info_alter' => 'rules_data_list_info_alter',
+        'form_alter' => 'rules_data_list_form_alter',
+      ),
+    ),
+    'text_matches'  => array(
+      'label' => t('Text comparison'),
+      'parameter' => array(
+        'text' => array(
+          'type' => 'text',
+          'label' => t('Text'),
+          'restriction' => 'selector',
+        ),
+        'match' => array(
+          'type' => 'text',
+          'label' => t('Matching text'),
+        ),
+        'operation' => array(
+          'type' => 'text',
+          'label' => t('Comparison operation'),
+          'options list' => 'rules_data_text_comparison_operation_list',
+          'restriction' => 'input',
+          'default value' => 'contains',
+          'optional' => TRUE,
+          'description' => t('In case the comparison operation @regex is selected, the matching pattern will be interpreted as a <a href="@regex-wikipedia">regular expression</a>.  Tip: <a href="@RegExr">RegExr: Online Regular Expression Testing Tool</a> is helpful for learning, writing, and testing Regular Expressions.', array('@regex-wikipedia' => 'http://en.wikipedia.org/wiki/Regular_expression', '@RegExr' => 'http://gskinner.com/RegExr/', '@regex' => t('regular expression'))),
+        ),
+      ),
+      'group' => t('Data'),
+      'base' => 'rules_data_text_comparison',
+    ),
+  );
+}
+
+/**
+ * If the bundle is compared, add the metadata assertion so other elements
+ * can make use of properties specific to the bundle.
+ */
+function rules_condition_data_is_assertions($element) {
+  // Assert the bundle of entities, if its compared.
+  if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) {
+    $info = $wrapper->info();
+    if (isset($info['parent']) && $info['parent'] instanceof EntityDrupalWrapper) {
+      $entity_info = $info['parent']->entityInfo();
+      if (isset($entity_info['entity keys']['bundle']) && $entity_info['entity keys']['bundle'] == $info['name']) {
+        // Assert that the entity is of bundle $value.
+        $value = is_array($element->settings['value']) ? $element->settings['value'] : array($element->settings['value']);
+        // Chop of the last part of the selector.
+        $parts = explode(':', $element->settings['data:select'], -1);
+        return array(implode(':', $parts) => array('bundle' => $value));
+      }
+    }
+  }
+}
+
+/**
+ * Form alter callback for the condition data_is.
+ *
+ * Use multiple steps to configure the condition as the needed type of the value
+ * depends on the selected data.
+ */
+function rules_condition_data_is_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+  if (!empty($options['init']) && !isset($form_state['rules_element_step'])) {
+    unset($form['parameter']['op'], $form['parameter']['value']);
+    $form['negate']['#access'] = FALSE;
+    $form_state['rules_element_step'] = 'data_value';
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Continue'),
+      '#limit_validation_errors' => array(array('parameter', 'data'), array('parameter', 'op')),
+      '#submit' => array('rules_form_submit_rebuild'),
+    );
+    // Clear the parameter mode for the value parameter, so its gets the proper
+    // default value based upon the type of the the selected data on rebuild.
+    unset($form_state['parameter_mode']['value']);
+  }
+  else {
+    // Change the data parameter to be not editable.
+    $form['parameter']['data']['settings']['#access'] = FALSE;
+    // TODO: improve display
+    $form['parameter']['data']['info'] = array(
+      '#prefix' => '<p>',
+      '#markup' => t('<strong>Selected data:</strong> %selector', array('%selector' => $element->settings['data:select'])),
+      '#suffix' => '</p>',
+    );
+
+    // Limit the operations to what makes sense for the selected data type.
+    $info = $element->pluginParameterInfo();
+    $data_info = $info['value'];
+    if ($element->settings['op'] == 'IN') {
+      $data_info['type'] = entity_property_list_extract_type($data_info['type']);
+    }
+
+    if (!RulesData::typesMatch($data_info, array('type' => array('decimal', 'date')))) {
+      $options =& $form['parameter']['op']['settings']['op']['#options'];
+      unset($options['<'], $options['>']);
+    }
+    // Remove 'contains' if it is not selected, as it is deprecated by the
+    // text comparison condition.
+    if ($element->settings['op'] != 'contains') {
+      unset($form['parameter']['op']['settings']['op']['#options']['contains']);
+    }
+
+    // Auto-refresh the form if the operation is changed, so the input form
+    // changes in case "is one of" requires a list value.
+    $form['parameter']['op']['settings']['op']['#ajax'] = rules_ui_form_default_ajax() + array(
+      'trigger_as' => array('name' => 'reload'),
+    );
+    // Provide a reload button for non-JS users.
+    $form['reload'] = array(
+      '#type' => 'submit',
+      '#value' => t('Reload form'),
+      '#limit_validation_errors' => array(array('parameter', 'data'), array('parameter', 'op')),
+      '#submit' => array('rules_form_submit_rebuild'),
+      '#ajax' => rules_ui_form_default_ajax(),
+      '#weight' => 5,
+    );
+    // Hide the reload button in case JS is enabled.
+    $form['reload']['#attributes'] = array('class' => array('rules-hide-js'));
+  }
+}
+
+/**
+ * Provides configuration help for the data_is condition.
+ */
+function rules_condition_data_is_help() {
+  return array('#markup' => t('Compare two data values of the same type with each other.'));
+}
+
+/**
+ * Options list callback for condition data_is.
+ */
+function rules_condition_data_is_operator_options() {
+  return array(
+    '==' => t('equals'),
+    'IN' => t('is one of'),
+    '<' => t('is lower than'),
+    '>' => t('is greater than'),
+    // Note: This is deprecated by the text comparison condition.
+    'contains' => t('contains'),
+  );
+}
+
+/**
+ * Options list callback for condition text_matches.
+ */
+function rules_data_text_comparison_operation_list() {
+  return array(
+    'contains' => t('contains'),
+    'starts' => t('starts with'),
+    'ends' => t('ends with'),
+    'regex' => t('regular expression'),
+  );
+}
+
+/**
+ * Returns the options list as specified by the selected property of the first parameter.
+ *
+ * @see rules_data_list_info_alter()
+ * @see rules_action_data_set_info_alter()
+ * @see rules_condition_data_is_info_alter()
+ */
+function rules_data_selector_options_list(RulesAbstractPlugin $element) {
+  $name = rules_array_key($element->pluginParameterInfo());
+  // If the selected data property has an option list, make use of it.
+  if (isset($element->settings[$name . ':select']) && $wrapper = $element->applyDataSelector($element->settings[$name . ':select'])) {
+    return $wrapper->optionsList($element instanceof RulesActionInterface ? 'edit' : 'view');
+  }
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/entity.eval.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,174 @@
+<?php
+
+/**
+ * @file
+ * Contains rules integration for entities needed during evaluation.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Action: Fetch data.
+ */
+function rules_action_entity_fetch($type, $id, $revision) {
+  $info = entity_get_info($type);
+
+  // Support the revision parameter, if applicable.
+  if (!empty($info['entity keys']['revision']) && isset($revision)) {
+    $conditions = array($info['entity keys']['revision'] => $revision);
+  }
+
+  $return = entity_load($type, array($id), isset($conditions) ? $conditions : array());
+  $entity = reset($return);
+  if (!$entity) {
+    throw new RulesEvaluationException('Unable to load @entity with id "@id"', array('@id' => $id, '@entity' => $type));
+  }
+  return array('entity_fetched' => $entity);
+}
+
+/**
+ * Info alteration callback for the entity fetch action.
+ */
+function rules_action_entity_fetch_info_alter(&$element_info, RulesAbstractPlugin $element) {
+  $element->settings += array('type' => NULL);
+  $info = entity_get_info($element->settings['type']);
+
+  // Fix the type of the identifier.
+  $element_info['parameter']['id']['type'] = isset($info['entity keys']['name']) ? 'text' : 'integer';
+
+  // Add an optional revision parameter, if supported.
+  if (!empty($info['entity keys']['revision'])) {
+    $element_info['parameter']['revision_id'] = array(
+      'type' => 'integer',
+      'label' => t('Revision identifier'),
+      'optional' => TRUE,
+    );
+  }
+  $element_info['provides']['entity_fetched']['type'] = $element->settings['type'];
+}
+
+/**
+ * Action: Query entities.
+ */
+function rules_action_entity_query($type, $property, $value, $limit) {
+  $return = entity_property_query($type, $property, $value, $limit);
+  return array('entity_fetched' => array_values($return));
+}
+
+/**
+ * Info alteration callback for the entity query action.
+ */
+function rules_action_entity_query_info_alter(&$element_info, RulesAbstractPlugin $element) {
+  $element->settings += array('type' => NULL, 'property' => NULL);
+  if ($element->settings['type']) {
+    $element_info['parameter']['property']['options list'] = 'rules_action_entity_query_property_options_list';
+
+    if ($element->settings['property']) {
+      $wrapper = rules_get_entity_metadata_wrapper_all_properties($element);
+      if (isset($wrapper->{$element->settings['property']}) && $property = $wrapper->{$element->settings['property']}) {
+        $element_info['parameter']['value']['type'] = $property->type();
+        $element_info['parameter']['value']['options list']  = $property->optionsList() ? 'rules_action_entity_query_value_options_list' : FALSE;
+      }
+    }
+  }
+  $element_info['provides']['entity_fetched']['type'] = 'list<' . $element->settings['type'] . '>';
+}
+
+/**
+ * Action: Create entities.
+ */
+function rules_action_entity_create($args, $element) {
+  $values = array();
+  foreach ($element->pluginParameterInfo() as $name => $info) {
+    if ($name != 'type') {
+      // Remove the parameter name prefix 'param_'.
+      $values[substr($name, 6)] = $args[$name];
+    }
+  }
+  try {
+    $data = entity_property_values_create_entity($args['type'], $values);
+    return array('entity_created' => $data);
+  }
+  catch (EntityMetadataWrapperException $e) {
+    throw new RulesEvaluationException('Unable to create entity @type": ' . $e->getMessage(), array('@type' => $args['type']), $element);
+  }
+}
+
+/**
+ * Info alteration callback for the entity create action.
+ */
+function rules_action_entity_create_info_alter(&$element_info, RulesAbstractPlugin $element) {
+  if (!empty($element->settings['type']) && entity_get_info($element->settings['type'])) {
+    $wrapper = entity_metadata_wrapper($element->settings['type']);
+    // Add the data type's needed parameter for loading to the parameter info.
+    foreach ($wrapper as $name => $child) {
+      $info = $child->info();
+      if (!empty($info['required'])) {
+        $info += array('type' => 'text');
+        // Prefix parameter names to avoid name clashes with existing parameters.
+        $element_info['parameter']['param_' . $name] = array_intersect_key($info, array_flip(array('type', 'label', 'description')));
+        $element_info['parameter']['param_' . $name]['options list']  = $child->optionsList() ? 'rules_action_entity_parameter_options_list' : FALSE;
+      }
+    }
+    $element_info['provides']['entity_created']['type'] = $element->settings['type'];
+    if (($bundleKey = $wrapper->entityKey('bundle')) && isset($element->settings['param_' . $bundleKey])) {
+      $element_info['provides']['entity_created']['bundle'] = $element->settings['param_' . $bundleKey];
+    }
+  }
+}
+
+/**
+ * Action: Save entities.
+ */
+function rules_action_entity_save($wrapper, $immediate = FALSE, $settings, $state, $element) {
+  $state->saveChanges($settings['data:select'], $wrapper, $immediate);
+}
+
+/**
+ * Action: Delete entities.
+ */
+function rules_action_entity_delete($wrapper, $settings, $state, $element) {
+  try {
+    $wrapper->delete();
+  }
+  catch (EntityMetadataWrapperException $e) {
+    throw new RulesEvaluationException($e->getMessage(), array(), $element);
+  }
+}
+
+/**
+ * Condition: Entity is new.
+ */
+function rules_condition_entity_is_new($wrapper, $settings, $state, $element) {
+  return !$wrapper->getIdentifier() || !empty($wrapper->value()->is_new);
+}
+
+/**
+ * Condition: Entity has field.
+ */
+function rules_condition_entity_has_field($wrapper, $field_name, $settings, $state) {
+  return isset($wrapper->$field_name) || isset($wrapper->value()->$field_name);
+}
+
+/**
+ * Condition: Entity is of type.
+ */
+function rules_condition_entity_is_of_type($wrapper, $type) {
+  return $wrapper->type() == $type;
+}
+
+/**
+ * Condition: Entity is of type and bundle.
+ */
+function rules_condition_entity_is_of_bundle($wrapper, $type, $bundles) {
+  return $wrapper->type() == $type && in_array($wrapper->getBundle(), $bundles);
+}
+
+/**
+ * Condition: User has access to field.
+ */
+function rules_condition_entity_field_access(EntityDrupalWrapper $wrapper, $field_name, $op, $account = NULL) {
+  $field = field_info_field($field_name);
+  return !empty($field) && field_access($op, $field, $wrapper->type(), $wrapper->value(), $account = NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/entity.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,579 @@
+<?php
+
+/**
+ * @file General entity related rules integration
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_file_info() on behalf of the entity module.
+ * @see rules_core_modules()
+ */
+function rules_entity_file_info() {
+  return array('modules/entity.eval');
+}
+
+/**
+ * Implements hook_rules_category_info() on behalf of the pseudo entity module.
+ */
+function rules_entity_category_info() {
+  return array(
+    'rules_entity' => array(
+      'label' => t('Entities'),
+      'equals group' => t('Entities'),
+      'weight' => -50,
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_action_info() on behalf of the entity module.
+ * @see rules_core_modules()
+ */
+function rules_entity_action_info() {
+  if (rules_entity_action_type_options('entity_fetch')) {
+    $return['entity_fetch'] = array(
+      'label' => t('Fetch entity by id'),
+      'parameter' => array(
+        'type' => array(
+          'type' => 'text',
+          'label' => t('Entity type'),
+          'options list' => 'rules_entity_action_type_options',
+          'description' => t('Specifies the type of entity that should be fetched.'),
+          'restriction' => 'input',
+        ),
+        'id' => array('type' => 'unknown', 'label' => t('Identifier')),
+      ),
+      'provides' => array(
+        'entity_fetched' => array('type' => 'unknown', 'label' => t('Fetched entity')),
+      ),
+      'group' => t('Entities'),
+      'access callback' => 'rules_entity_action_access',
+      'base' => 'rules_action_entity_fetch',
+      'callbacks' => array(
+        'access' => 'rules_action_entity_createfetch_access',
+        'form_alter' => 'rules_action_type_form_alter',
+      ),
+    );
+    $return['entity_query'] = array(
+      'label' => t('Fetch entity by property'),
+      'parameter' => array(
+        'type' => array(
+          'type' => 'text',
+          'label' => t('Entity type'),
+          'options list' => 'rules_entity_action_type_options',
+          'description' => t('Specifies the type of the entity that should be fetched.'),
+          'restriction' => 'input',
+        ),
+        'property' => array(
+          'type' => 'text',
+          'label' => t('Property'),
+          'description' => t('The property by which the entity is to be selected.'),
+          'restriction' => 'input',
+        ),
+        'value' => array(
+          'type' => 'unknown',
+          'label' => t('Value'),
+          'description' => t('The property value of the entity to be fetched.'),
+        ),
+        'limit' => array(
+          'type' => 'integer',
+          'label' => t('Limit result count'),
+          'description' => t('Limit the maximum number of fetched entities.'),
+          'optional' => TRUE,
+          'default value' => '10',
+        ),
+      ),
+      'provides' => array(
+        'entity_fetched' => array('type' => 'list', 'label' => t('Fetched entity')),
+      ),
+      'group' => t('Entities'),
+      'access callback' => 'rules_entity_action_access',
+      'base' => 'rules_action_entity_query',
+      'callbacks' => array(
+        'form_alter' => 'rules_action_type_form_alter',
+      ),
+    );
+  }
+
+  if (rules_entity_action_type_options('entity_create')) {
+    $return['entity_create'] = array(
+      'label' => t('Create a new entity'),
+      'named parameter' => TRUE,
+      'parameter' => array(
+        'type' => array(
+          'type' => 'text',
+          'label' => t('Entity type'),
+          'options list' => 'rules_entity_action_type_options',
+          'description' => t('Specifies the type of the entity that should be created.'),
+          'restriction' => 'input',
+        ),
+        // Further needed parameter depends on the type.
+      ),
+      'provides' => array(
+        'entity_created' => array(
+          'type' => 'unknown',
+          'label' => t('Created entity'),
+          'save' => TRUE,
+        ),
+      ),
+      'group' => t('Entities'),
+      'access callback' => 'rules_entity_action_access',
+      'base' => 'rules_action_entity_create',
+      'callbacks' => array(
+        'access' => 'rules_action_entity_createfetch_access',
+        'form_alter' => 'rules_action_type_form_alter',
+        'validate' => 'rules_action_create_type_validate',
+      ),
+    );
+  }
+
+  $return['entity_save'] = array(
+    'label' => t('Save entity'),
+    'parameter' => array(
+      'data' => array(
+        'type' => 'entity',
+        'label' => t('Entity'),
+        'description' => t('Specifies the entity, which should be saved permanently.'),
+        'restriction' => 'selector',
+        'wrapped' => TRUE,
+      ),
+      'immediate' => array(
+        'type' => 'boolean',
+        'label' => t('Force saving immediately'),
+        'description' => t('Usually saving is postponed till the end of the evaluation, so that multiple saves can be fold into one. If this set, saving is forced to happen immediately.'),
+        'default value' => FALSE,
+        'optional' => TRUE,
+        'restriction' => 'input',
+      ),
+    ),
+    'group' => t('Entities'),
+    'access callback' => 'rules_entity_action_access',
+    'base' => 'rules_action_entity_save',
+    'callbacks' => array(
+      'access' => 'rules_action_entity_savedelete_access',
+    ),
+  );
+
+  $return['entity_delete'] = array(
+    'label' => t('Delete entity'),
+    'parameter' => array(
+      'data' => array(
+        'type' => 'entity',
+        'label' => t('Entity'),
+        'description' => t('Specifies the entity, which should be deleted permanently.'),
+        'restriction' => 'selector',
+        'wrapped' => TRUE,
+      ),
+    ),
+    'group' => t('Entities'),
+    'access callback' => 'rules_entity_action_access',
+    'base' => 'rules_action_entity_delete',
+    'callbacks' => array(
+      'access' => 'rules_action_entity_savedelete_access',
+    ),
+  );
+  return $return;
+}
+
+/**
+ * Custom access callback for data create and fetch action.
+ */
+function rules_action_entity_createfetch_access(RulesAbstractPlugin $element) {
+  $op = $element->getElementName() == 'entity_create' ? 'create' : 'view';
+  return entity_access($op, $element->settings['type']);
+}
+
+/**
+ * Custom access callback for the data query action.
+ */
+function rules_action_entity_query_access(RulesAbstractPlugin $element) {
+  if (!rules_action_entity_createfetch_access($element)) {
+    return FALSE;
+  }
+  $properties = entity_get_all_property_info($element->settings['type']);
+  if (isset($element->settings['property']) && isset($properties[$element->settings['property']]['access callback'])) {
+    return call_user_func($properties[$element->settings['property']]['access callback'], 'view', $element->settings['property'], $element->settings['type'], NULL, NULL);
+  }
+  return TRUE;
+}
+
+/**
+ * Options list callback for a parameter of entity_create.
+ */
+function rules_action_entity_parameter_options_list(RulesPlugin $element, $param_name) {
+  // Remove the parameter name prefix 'param_'.
+  $property_name = substr($param_name, 6);
+  $wrapper = entity_metadata_wrapper($element->settings['type']);
+  // The possible values of the "value" parameter are those of the data param.
+  return $wrapper->$property_name->optionsList();
+}
+
+/**
+ * Custom access callback for data save and delete action.
+ */
+function rules_action_entity_savedelete_access(RulesAbstractPlugin $element) {
+  if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) {
+    $op = $element->getElementName() == 'entity_save' ? 'save' : 'delete';
+    return $wrapper instanceof EntityDrupalWrapper && $wrapper->entityAccess($op);
+  }
+  return FALSE;
+}
+
+/**
+ * Returns the options list for choosing a property of an entity type.
+ */
+function rules_action_entity_query_property_options_list(RulesAbstractPlugin $element) {
+  $element->settings += array('type' => NULL);
+  if ($element->settings['type']) {
+    $properties = entity_get_all_property_info($element->settings['type']);
+    return rules_extract_property($properties, 'label');
+  }
+}
+
+/**
+ * Returns the options list specified for the chosen property.
+ */
+function rules_action_entity_query_value_options_list(RulesAbstractPlugin $element) {
+  // Get the possible values for the selected property.
+  $element->settings += array('type' => NULL, 'property' => NULL);
+  if ($element->settings['type'] && $element->settings['property']) {
+    $wrapper = rules_get_entity_metadata_wrapper_all_properties($element);
+
+    if (isset($wrapper->{$element->settings['property']}) && $property = $wrapper->{$element->settings['property']}) {
+      return $property->optionsList('view');
+    }
+  }
+}
+
+/**
+ * Options list callback for data actions.
+ *
+ * @param $element
+ *   The element to return options for.
+ * @param $param
+ *   The name of the parameter to return options for.
+ */
+function rules_entity_action_type_options($element, $name = NULL) {
+  // We allow calling this function with just the element name too. That way
+  // we ease manual re-use.
+  $name = is_object($element) ? $element->getElementName() : $element;
+  return ($name == 'entity_create') ? rules_entity_type_options('create') : rules_entity_type_options();
+}
+
+/**
+ * Returns options containing entity types having the given key set in the info.
+ *
+ * Additionally, we exclude all entity types that are marked as configuration.
+ */
+function rules_entity_type_options($key = NULL) {
+  $info = entity_get_info();
+  $types = array();
+  foreach ($info as $type => $entity_info) {
+    if (empty($entity_info['configuration']) && empty($entity_info['exportable'])) {
+      if (!isset($key) || entity_type_supports($type, $key)) {
+        $types[$type] = $entity_info['label'];
+      }
+    }
+  }
+  return $types;
+}
+
+/**
+ * Options list callback for getting a list of possible entity bundles.
+ *
+ * @param $element
+ *   The element to return options for.
+ */
+function rules_entity_bundle_options(RulesAbstractPlugin $element) {
+  $bundles = array();
+  if (isset($element->settings['type'])) {
+    $entity_info = entity_get_info($element->settings['type']);
+    foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+      $bundles[$bundle_name] = $bundle_info['label'];
+    }
+  }
+  return $bundles;
+}
+
+/**
+ * Entity actions access callback.
+ *
+ * Returns TRUE if at least one type is available for configuring the action.
+ */
+function rules_entity_action_access($type, $name) {
+  if ($name == 'entity_fetch' || $name == 'entity_create' || $name == 'entity_query') {
+    $types = array_keys(rules_entity_action_type_options($name));
+    $op = $name == 'entity_create' ? 'create' : 'view';
+  }
+  elseif ($name == 'entity_save' || $name == 'entity_delete') {
+    $types = array_keys(entity_get_info());
+    $op = $name == 'entity_save' ? 'save' : 'delete';
+  }
+  foreach ($types as $key => $type) {
+    if (!entity_access($op, $type)) {
+      unset($types[$key]);
+    }
+  }
+  return !empty($types);
+}
+
+/**
+ * Implements hook_rules_condition_info() on behalf of the entity module.
+ * @see rules_core_modules()
+ */
+function rules_entity_condition_info() {
+  return array(
+    'entity_is_new' => array(
+      'label' => t('Entity is new'),
+      'parameter' => array(
+        'entity' => array(
+          'type' => 'entity',
+          'label' => t('Entity'),
+          'description' => t('Specifies the entity for which to evaluate the condition.'),
+          'restriction' => 'selector',
+        ),
+      ),
+      'group' => t('Entities'),
+      'base' => 'rules_condition_entity_is_new',
+    ),
+    'entity_has_field' => array(
+      'label' => t('Entity has field'),
+      'parameter' => array(
+        'entity' => array(
+          'type' => 'entity',
+          'label' => t('Entity'),
+          'description' => t('Specifies the entity for which to evaluate the condition.'),
+          'restriction' => 'selector',
+        ),
+        'field' => array(
+          'type' => 'text',
+          'label' => t('Field'),
+          'description' => t('The name of the field to check for.'),
+          'options list' => 'rules_condition_entity_has_field_options',
+          'restriction' => 'input',
+        ),
+      ),
+      'group' => t('Entities'),
+      'base' => 'rules_condition_entity_has_field',
+    ),
+    'entity_is_of_type' => array(
+      'label' => t('Entity is of type'),
+      'parameter' => array(
+        'entity' => array(
+          'type' => 'entity',
+          'label' => t('Entity'),
+          'description' => t('Specifies the entity for which to evaluate the condition.'),
+        ),
+        'type' => array(
+          'type' => 'token',
+          'label' => t('Entity type'),
+          'description' => t('The entity type to check for.'),
+          'options list' => 'rules_entity_action_type_options',
+          'restriction' => 'input',
+        ),
+      ),
+      'group' => t('Entities'),
+      'base' => 'rules_condition_entity_is_of_type',
+    ),
+    'entity_is_of_bundle' => array(
+      'label' => t('Entity is of bundle'),
+      'parameter' => array(
+        'entity' => array(
+          'type' => 'entity',
+          'label' => t('Entity'),
+          'description' => t('Specifies the entity for which to evaluate the condition.'),
+        ),
+        'type' => array(
+          'type' => 'token',
+          'label' => t('Entity type'),
+          'description' => t('The type of the checked entity.'),
+          'options list' => 'rules_entity_action_type_options',
+          'restriction' => 'input',
+        ),
+        'bundle' => array(
+          'type' => 'list<text>',
+          'label' => t('Entity bundle'),
+          'description' => t('The condition is met if the entity is of one of the selected bundles.'),
+          'options list' => 'rules_entity_bundle_options',
+          'restriction' => 'input',
+        ),
+      ),
+      'group' => t('Entities'),
+      'base' => 'rules_condition_entity_is_of_bundle',
+    ),
+    'entity_field_access' => array(
+      'label' => t('User has field access'),
+      'parameter' => array(
+        'entity' => array(
+          'type' => 'entity',
+          'label' => t('Entity'),
+          'description' => t('Specifies the entity for which to evaluate the condition.'),
+          'restriction' => 'selector',
+          'wrapped' => TRUE,
+        ),
+        'field' => array(
+          'type' => 'token',
+          'label' => t('Field name'),
+          'description' => t('The name of the field to check for.'),
+          'options list' => 'rules_condition_entity_has_field_options',
+          'restriction' => 'input',
+        ),
+        'op' => array(
+          'type' => 'text',
+          'label' => t('Access operation'),
+          'options list' => 'rules_condition_entity_field_access_op_options',
+          'restriction' => 'input',
+          'optional' => TRUE,
+          'default value' => 'view',
+        ),
+        'account' => array(
+          'type' => 'user',
+          'label' => t('User account'),
+          'description' => t('Specifies the user account for which to check access. If left empty, the currently logged in user will be used.'),
+          'restriction' => 'selector',
+          'optional' => TRUE,
+          'default value' => NULL,
+        ),
+      ),
+      'group' => t('Entities'),
+      'base' => 'rules_condition_entity_field_access',
+    ),
+  );
+}
+
+/**
+ * Help callback for condition entity_is_new.
+ */
+function rules_condition_entity_is_new_help() {
+  return t('This condition determines whether the specified entity has just been created and has not yet been saved to the database.');
+}
+
+/**
+ * Returns options for choosing a field for the selected entity.
+ */
+function rules_condition_entity_has_field_options(RulesAbstractPlugin $element) {
+  $options = array();
+  foreach (field_info_fields() as $field_name => $field) {
+    $options[$field_name] = $field_name;
+  }
+  return $options;
+}
+
+/**
+ * Returns options for choosing a field_access() operation.
+ */
+function rules_condition_entity_field_access_op_options(RulesAbstractPlugin $element) {
+  return array(
+    'view' => t('View'),
+    'edit' => t('Edit'),
+  );
+}
+
+/**
+ * Assert that the entity has the field, if there is metadata for the field.
+ */
+function rules_condition_entity_has_field_assertions($element) {
+  // Assert the field is there if the condition matches.
+  if ($wrapper = $element->applyDataSelector($element->settings['entity:select'])) {
+    $type = $wrapper->type();
+    $field_property = $element->settings['field'];
+    // Get all possible properties and check whether we have one for the field.
+    $properties = entity_get_all_property_info($type == 'entity' ? NULL : $type);
+
+    if (isset($properties[$field_property])) {
+      $assertion = array('property info' => array($field_property => $properties[$field_property]));
+      return array($element->settings['entity:select'] => $assertion);
+    }
+  }
+}
+
+/**
+ * Assert the selected entity type.
+ */
+function rules_condition_entity_is_of_type_assertions($element) {
+  if ($type = $element->settings['type']) {
+    return array('entity' => array('type' => $type));
+  }
+}
+
+/**
+ * Assert the selected entity type and bundle.
+ */
+function rules_condition_entity_is_of_bundle_assertions($element) {
+  if ($bundle = $element->settings['bundle']) {
+    $assertions = array();
+    $assertions['entity']['type'] = $element->settings['type'];
+    $assertions['entity']['bundle'] = $bundle;
+    return $assertions;
+  }
+}
+
+/**
+ * Process callback for the condition entity_is_of_bundle.
+ */
+function rules_condition_entity_is_of_bundle_process(RulesAbstractPlugin $element) {
+  // If we know the entity type, auto-populate it.
+  if (($info = $element->getArgumentInfo('entity')) && $info['type'] != 'entity') {
+    $element->settings['type'] = $info['type'];
+  }
+}
+
+/**
+ * Form alter callback for the condition entity_is_of_bundle.
+ *
+ * Use multiple steps to configure the condition as the needed bundle field list
+ * depends on the selected entity type.
+ */
+function rules_condition_entity_is_of_bundle_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+  if (empty($element->settings['entity:select'])) {
+    $step = 1;
+  }
+  elseif (empty($element->settings['type'])) {
+    $step = 2;
+  }
+  else {
+    $step = 3;
+  }
+
+  $form['reload'] = array(
+    '#weight' => $form['submit']['#weight'] + 1,
+    '#type' => 'submit',
+    '#name' => 'reload',
+    '#value' => $step != 3 ? t('Continue') : t('Reload form'),
+    '#limit_validation_errors' => array(array('parameter', 'entity'), array('parameter', 'type')),
+    '#submit' => array('rules_form_submit_rebuild'),
+    '#ajax' => rules_ui_form_default_ajax('fade'),
+    '#attributes' => array('class' => array('rules-hide-js')),
+  );
+  // Use ajax and trigger as the reload button.
+  $form['parameter']['type']['settings']['type']['#ajax'] = $form['reload']['#ajax'] + array(
+    'event' => 'change',
+    'trigger_as' => array('name' => 'reload'),
+  );
+
+  switch ($step) {
+    case 1:
+      $form['reload']['#limit_validation_errors'] = array(array('parameter', 'entity'));
+      unset($form['parameter']['type']);
+      unset($form['reload']['#attributes']['class']);
+      // NO break;
+    case 2:
+      $form['negate']['#access'] = FALSE;
+      unset($form['parameter']['bundle']);
+      unset($form['submit']);
+      break;
+    case 3:
+      if (($info = $element->getArgumentInfo('entity')) && $info['type'] != 'entity') {
+        // Hide the entity type parameter if not needed.
+        unset($form['parameter']['type']);
+      }
+      break;
+  }
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/events.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,205 @@
+<?php
+
+/**
+ * @file Invokes events on behalf core modules. Usually this should be
+ *   directly in the module providing rules integration instead.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+
+/**
+ * Gets an unchanged entity that doesn't contain any recent changes. This
+ * handler assumes the name of the variable for the changed entity is the same
+ * as for the unchanged entity but without the trailing "_unchanged"; e.g., for
+ * the "node_unchanged" variable the handler assumes there is a "node" variable.
+ */
+function rules_events_entity_unchanged($arguments, $name, $info) {
+  // Cut of the trailing _unchanged.
+  $var_name = substr($name, 0, -10);
+  $entity = $arguments[$var_name];
+  if (isset($entity->original)) {
+    return $entity->original;
+  }
+}
+
+/**
+ * Generic entity events, used for core-entities for which we provide Rules
+ * integration only.
+ * We are implementing the generic-entity hooks instead of the entity-type
+ * specific hooks to ensure we come last. See http://drupal.org/node/1211946
+ * for details.
+ */
+
+/**
+ * Implements hook_entity_view().
+ */
+function rules_entity_view($entity, $type, $view_mode, $langcode) {
+  switch ($type) {
+    case 'comment':
+      rules_invoke_event('comment_view--' . $entity->node_type, $entity, $view_mode);
+      rules_invoke_event('comment_view', $entity, $view_mode);
+      break;
+    case 'node':
+      rules_invoke_event('node_view--' . $entity->type, $entity, $view_mode);
+      rules_invoke_event('node_view', $entity, $view_mode);
+      break;
+    case 'user':
+      rules_invoke_event('user_view', $entity, $view_mode);
+      break;
+  }
+}
+
+/**
+ * Implements hook_entity_presave().
+ */
+function rules_entity_presave($entity, $type) {
+  switch ($type) {
+    case 'comment':
+      rules_invoke_event('comment_presave--' . $entity->node_type, $entity);
+      rules_invoke_event('comment_presave', $entity);
+      break;
+    case 'node':
+      rules_invoke_event('node_presave--' . $entity->type, $entity);
+      rules_invoke_event('node_presave', $entity);
+      break;
+    case 'taxonomy_term':
+      rules_invoke_event('taxonomy_term_presave--' . $entity->vocabulary_machine_name, $entity);
+      rules_invoke_event('taxonomy_term_presave', $entity);
+      break;
+    case 'taxonomy_vocabulary':
+    case 'user':
+      rules_invoke_event($type . '_presave', $entity);
+      break;
+  }
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function rules_entity_update($entity, $type) {
+  switch ($type) {
+    case 'comment':
+      rules_invoke_event('comment_update--' . $entity->node_type, $entity);
+      rules_invoke_event('comment_update', $entity);
+      break;
+    case 'node':
+      rules_invoke_event('node_update--' . $entity->type, $entity);
+      rules_invoke_event('node_update', $entity);
+      break;
+    case 'taxonomy_term':
+      rules_invoke_event('taxonomy_term_update--' . $entity->vocabulary_machine_name, $entity);
+      rules_invoke_event('taxonomy_term_update', $entity);
+      break;
+    case 'taxonomy_vocabulary':
+    case 'user':
+      rules_invoke_event($type . '_update', $entity);
+      break;
+  }
+}
+
+/**
+ * Implements hook_entity_insert().
+ */
+function rules_entity_insert($entity, $type) {
+  switch ($type) {
+    case 'comment':
+      rules_invoke_event('comment_insert--' . $entity->node_type, $entity);
+      rules_invoke_event('comment_insert', $entity);
+      break;
+    case 'node':
+      rules_invoke_event('node_insert--' . $entity->type, $entity);
+      rules_invoke_event('node_insert', $entity);
+      break;
+    case 'taxonomy_term':
+      rules_invoke_event('taxonomy_term_insert--' . $entity->vocabulary_machine_name, $entity);
+      rules_invoke_event('taxonomy_term_insert', $entity);
+      break;
+    case 'taxonomy_vocabulary':
+    case 'user':
+      rules_invoke_event($type . '_insert', $entity);
+      break;
+  }
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function rules_entity_delete($entity, $type) {
+  switch ($type) {
+    case 'comment':
+      rules_invoke_event('comment_delete--' . $entity->node_type, $entity);
+      rules_invoke_event('comment_delete', $entity);
+      break;
+    case 'node':
+      rules_invoke_event('node_delete--' . $entity->type, $entity);
+      rules_invoke_event('node_delete', $entity);
+      break;
+    case 'taxonomy_term':
+      rules_invoke_event('taxonomy_term_delete--' . $entity->vocabulary_machine_name, $entity);
+      rules_invoke_event('taxonomy_term_delete', $entity);
+      break;
+    case 'taxonomy_vocabulary':
+    case 'user':
+      rules_invoke_event($type . '_delete', $entity);
+      break;
+  }
+}
+
+/**
+ * Implements hook_user_login().
+ */
+function rules_user_login(&$edit, $account) {
+  rules_invoke_event('user_login', $account);
+}
+
+/**
+ * Implements hook_user_logout().
+ */
+function rules_user_logout($account) {
+  rules_invoke_event('user_logout', $account);
+}
+
+/**
+ * System events. Note that rules_init() is the main module file is used to
+ * invoke the init event.
+ */
+
+/**
+ * Implements hook_cron().
+ */
+function rules_cron() {
+  rules_invoke_event('cron');
+}
+
+/**
+ * Implements hook_watchdog().
+ */
+function rules_watchdog($log_entry) {
+  rules_invoke_event('watchdog', $log_entry);
+}
+
+/**
+ * Getter callback for the log entry message property.
+ */
+function rules_system_log_get_message($log_entry) {
+  return t($log_entry['message'], (array)$log_entry['variables']);
+}
+
+/**
+ * Gets all view modes of an entity for an entity_view event.
+ */
+function rules_get_entity_view_modes($name, $var_info) {
+  // Read the entity type from a special key out of the variable info.
+  $entity_type = $var_info['options list entity type'];
+  $info = entity_get_info($entity_type);
+  foreach ($info['view modes'] as $mode => $mode_info) {
+    $modes[$mode] = $mode_info['label'];
+  }
+  return $modes;
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/node.eval.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * @file
+ * Contains rules integration for the node module needed during evaluation.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Base class providing node condition defaults.
+ */
+abstract class RulesNodeConditionBase extends RulesConditionHandlerBase {
+
+  public static function defaults() {
+    return array(
+      'parameter' => array(
+        'node' => array('type' => 'node', 'label' => t('Content')),
+      ),
+      'category' => 'node',
+      'access callback' => 'rules_node_integration_access',
+    );
+  }
+}
+
+/**
+ * Condition: Check for selected content types
+ */
+class RulesNodeConditionType extends RulesNodeConditionBase {
+
+  /**
+   * Defines the condition.
+   */
+  public static function getInfo() {
+    $info = self::defaults() + array(
+      'name' => 'node_is_of_type',
+      'label' => t('Content is of type'),
+      'help' => t('Evaluates to TRUE if the given content is of one of the selected content types.'),
+    );
+    $info['parameter']['type'] = array(
+      'type' => 'list<text>',
+      'label' => t('Content types'),
+      'options list' => 'node_type_get_names',
+      'description' => t('The content type(s) to check for.'),
+      'restriction' => 'input',
+    );
+    return $info;
+  }
+
+  /**
+   * Executes the condition.
+   */
+  public function execute($node, $types) {
+    return in_array($node->type, $types);
+  }
+
+  /**
+   * Provides the content type of a node as asserted metadata.
+   */
+  function assertions() {
+    return array('node' => array('bundle' => $this->element->settings['type']));
+  }
+}
+
+/**
+ * Condition: Check if the node is published.
+ */
+class RulesNodeConditionPublished extends RulesNodeConditionBase {
+
+  /**
+   * Defines the condition.
+   */
+  public static function getInfo() {
+    return self::defaults() + array(
+      'name' => 'node_is_published',
+      'label' => t('Content is published'),
+    );
+  }
+
+  /**
+   * Executes the condition.
+   */
+  public function execute($node) {
+    return $node->status == 1;
+  }
+}
+
+/**
+ * Condition: Check if the node is sticky.
+ */
+class RulesNodeConditionSticky extends RulesNodeConditionBase {
+
+  /**
+   * Defines the condition.
+   */
+  public static function getInfo() {
+    return self::defaults() + array(
+      'name' => 'node_is_sticky',
+      'label' => t('Content is sticky'),
+    );
+  }
+
+  /**
+   * Executes the condition.
+   */
+  public function execute($node) {
+    return $node->sticky == 1;
+  }
+}
+
+/**
+ * Condition: Check if the node is promoted to the frontpage
+ */
+class RulesNodeConditionPromoted extends RulesNodeConditionBase {
+
+  /**
+   * Defines the condition.
+   */
+  public static function getInfo() {
+    return self::defaults() + array(
+      'name' => 'node_is_promoted',
+      'label' => t('Content is promoted to frontpage'),
+    );
+  }
+
+  /**
+   * Executes the condition.
+   */
+  public function execute($node) {
+    return $node->promote == 1;
+  }
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/node.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * @file rules integration for the node module
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_category_info() on behalf of the node module.
+ */
+function rules_node_category_info() {
+  return array(
+    'node' => array(
+      'label' => t('Node'),
+      'equals group' => t('Node'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_file_info() on behalf of the node module.
+ */
+function rules_node_file_info() {
+  return array('modules/node.eval');
+}
+
+/**
+ * Implements hook_rules_event_info() on behalf of the node module.
+ */
+function rules_node_event_info() {
+  $items = array(
+    'node_insert' => array(
+      'label' => t('After saving new content'),
+      'category' => 'node',
+      'variables' => rules_events_node_variables(t('created content')),
+      'access callback' => 'rules_node_integration_access',
+      'class' => 'RulesNodeEventHandler',
+    ),
+    'node_update' => array(
+      'label' => t('After updating existing content'),
+      'category' => 'node',
+      'variables' => rules_events_node_variables(t('updated content'), TRUE),
+      'access callback' => 'rules_node_integration_access',
+      'class' => 'RulesNodeEventHandler',
+    ),
+    'node_presave' => array(
+      'label' => t('Before saving content'),
+      'category' => 'node',
+      'variables' => rules_events_node_variables(t('saved content'), TRUE),
+      'access callback' => 'rules_node_integration_access',
+      'class' => 'RulesNodeEventHandler',
+    ),
+    'node_view' => array(
+      'label' => t('Content is viewed'),
+      'category' => 'node',
+      'help' => t("Note that if drupal's page cache is enabled, this event won't be generated for pages served from cache."),
+      'variables' => rules_events_node_variables(t('viewed content')) + array(
+        'view_mode' => array(
+          'type' => 'text',
+          'label' => t('view mode'),
+          'options list' => 'rules_get_entity_view_modes',
+          // Add the entity-type for the options list callback.
+          'options list entity type' => 'node',
+        ),
+      ),
+      'access callback' => 'rules_node_integration_access',
+      'class' => 'RulesNodeEventHandler',
+    ),
+    'node_delete' => array(
+      'label' => t('After deleting content'),
+      'category' => 'node',
+      'variables' => rules_events_node_variables(t('deleted content')),
+      'access callback' => 'rules_node_integration_access',
+      'class' => 'RulesNodeEventHandler',
+    ),
+  );
+  // Specify that on presave the node is saved anyway.
+  $items['node_presave']['variables']['node']['skip save'] = TRUE;
+  return $items;
+}
+
+/**
+ * Returns some parameter suitable for using it with a node
+ */
+function rules_events_node_variables($node_label, $update = FALSE) {
+  $args = array(
+    'node' => array('type' => 'node', 'label' => $node_label),
+  );
+  if ($update) {
+    $args += array(
+      'node_unchanged' => array(
+        'type' => 'node',
+        'label' => t('unchanged content'),
+        'handler' => 'rules_events_entity_unchanged',
+      ),
+    );
+  }
+  return $args;
+}
+
+/**
+ * Implements hook_rules_action_info() on behalf of the node module.
+ */
+function rules_node_action_info() {
+  $defaults = array(
+    'parameter' => array(
+      'node' => array('type' => 'node', 'label' => t('Content'), 'save' => TRUE),
+    ),
+    'category' => 'node',
+    'access callback' => 'rules_node_admin_access',
+  );
+  // Add support for hand-picked core actions.
+  $core_actions = node_action_info();
+  $actions = array('node_publish_action', 'node_unpublish_action', 'node_make_sticky_action', 'node_make_unsticky_action', 'node_promote_action', 'node_unpromote_action');
+  foreach ($actions as $base) {
+    $action_name = str_replace('_action', '', $base);
+    $items[$action_name] = $defaults + array(
+      'label' => $core_actions[$base]['label'],
+      'base' => $base,
+    );
+  }
+  return $items;
+}
+
+/**
+ * Node integration access callback.
+ */
+function rules_node_integration_access($type, $name) {
+  if ($type == 'event' || $type == 'condition') {
+    return entity_access('view', 'node');
+  }
+}
+
+/**
+ * Node integration admin access callback.
+ */
+function rules_node_admin_access() {
+  return user_access('administer nodes');
+}
+
+
+/**
+ * Event handler support node bundle event settings.
+ */
+class RulesNodeEventHandler extends RulesEventHandlerEntityBundle {
+
+  /**
+   * Returns the label to use for the bundle property.
+   *
+   * @return string
+   */
+  protected function getBundlePropertyLabel() {
+    return t('type');
+  }
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/path.eval.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,148 @@
+<?php
+
+/**
+ * @file
+ * Contains rules integration for the path module needed during evaluation.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Action implementation: Path alias.
+ */
+function rules_action_path_alias($source, $alias, $langcode = LANGUAGE_NONE) {
+  if (!$alias) {
+    path_delete(array('source' => $source, 'language' => $langcode));
+  }
+  elseif (!$source) {
+    path_delete(array('alias' => $alias, 'language' => $langcode));
+  }
+  // Only set the alias if the alias is not taken yet.
+  elseif (!path_load(array('alias' => $alias, 'language' => $langcode))) {
+    // Update the existing path or create a new one.
+    if ($path = path_load(array('source' => $source, 'language' => $langcode))) {
+      $path['alias'] = $alias;
+    }
+    else {
+      $path = array('source' => $source, 'alias' => $alias, 'language' => $langcode);
+    }
+    path_save($path);
+  }
+  else {
+    rules_log('The configured alias %alias already exists. Aborting.', array('%alias' => $alias));
+  }
+}
+
+/**
+ * Action Implementation: Set the URL alias for a node.
+ */
+function rules_action_node_path_alias($node, $alias) {
+  $langcode = isset($node->language) ? $node->language : LANGUAGE_NONE;
+  // Only set the alias if the alias is not taken yet.
+  if (($path = path_load(array('alias' => $alias, 'language' => $langcode))) && (empty($node->path['pid']) || $node->path['pid'] != $path['pid'])) {
+    rules_log('The configured alias %alias already exists. Aborting.', array('%alias' => $alias));
+    return FALSE;
+  }
+  $node->path['alias'] = $alias;
+}
+
+/**
+ * Action Implementation: Set the URL alias for a node.
+ */
+function rules_action_taxonomy_term_path_alias($term, $alias) {
+  // Only set the alias if the alias is not taken yet.
+  if (($path = path_load(array('alias' => $alias, 'language' => LANGUAGE_NONE))) && (empty($term->path['pid']) || $term->path['pid'] != $path['pid'])) {
+    rules_log('The configured alias %alias already exists. Aborting.', array('%alias' => $alias));
+    return FALSE;
+  }
+  $term->path['alias'] = $alias;
+}
+
+/**
+ * Condition implementation: Check if the path has an alias.
+ */
+function rules_condition_path_has_alias($source, $langcode = LANGUAGE_NONE) {
+  return (bool) drupal_lookup_path('alias', $source, $langcode);
+}
+
+/**
+ * Condition implementation: Check if the URL alias exists.
+ */
+function rules_condition_path_alias_exists($alias, $langcode = LANGUAGE_NONE) {
+  return (bool) drupal_lookup_path('source', $alias, $langcode);
+}
+
+/**
+ * Cleans the given path by replacing non ASCII characters with the replacment character.
+ *
+ * Path cleaning may be adapted by overriding the configuration variables
+ * @code rules_clean_path @endcode,
+ * @code rules_path_replacement_char @endcode and
+ * @code rules_path_transliteration @endcode
+ * in the site's settings.php file.
+ */
+function rules_path_default_cleaning_method($path) {
+  $replace = variable_get('rules_path_replacement_char', '-');
+  if ($replace) {
+    // If the transliteration module is enabled, transliterate the alias first.
+    if (module_exists('transliteration') && variable_get('rules_path_transliteration', TRUE)) {
+      $path = transliteration_get($path);
+    }
+
+    $array = variable_get('rules_clean_path', array('/[^a-zA-Z0-9\-_]+/', $replace));
+    $array[2] = $path;
+    // Replace it and remove trailing and leading replacement characters.
+    $output = trim(call_user_func_array('preg_replace', $array), $replace);
+
+    if (variable_get('rules_path_lower_case', TRUE)) {
+      $output = drupal_strtolower($output);
+    }
+    return $output;
+  }
+  else {
+    return $path;
+  }
+}
+
+/**
+ * Cleans the given string so it can be used as part of a URL path.
+ */
+function rules_clean_path($path) {
+  $function = variable_get('rules_path_cleaning_callback', 'rules_path_default_cleaning_method');
+  if (!function_exists($function)) {
+    rules_log('An invalid URL path cleaning callback has been configured. Falling back to the default cleaning method.', array(), RulesLog::WARN);
+    $function = 'rules_path_default_cleaning_method';
+  }
+  return $function($path);
+}
+
+/**
+ * CTools path cleaning callback.
+ *
+ * @see rules_admin_settings()
+ */
+function rules_path_clean_ctools($path) {
+  // Make use of the CTools cleanstring implementation.
+  ctools_include('cleanstring');
+  $settings = array(
+    'separator' => variable_get('rules_path_replacement_char', '-'),
+    'transliterate' => module_exists('transliteration') && variable_get('rules_path_transliteration', TRUE),
+    'lower case' => variable_get('rules_path_lower_case', TRUE),
+  );
+  return ctools_cleanstring($path, $settings);
+}
+
+/**
+ * Pathauto path cleaning callback.
+ *
+ * @see rules_admin_settings()
+ */
+function rules_path_clean_pathauto($path) {
+  module_load_include('inc', 'pathauto');
+  return pathauto_cleanstring($path);
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/path.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,171 @@
+<?php
+
+/**
+ * @file rules integration for the path module
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_file_info() on behalf of the path module.
+ */
+function rules_path_file_info() {
+  return array('modules/path.eval');
+}
+
+/**
+ * Implements hook_rules_action_info() on behalf of the path module.
+ */
+function rules_path_action_info() {
+  return array(
+    'path_alias' => array(
+      'label' => t('Create or delete any URL alias'),
+      'group' => t('Path'),
+      'parameter' => array(
+        'source' => array(
+          'type' => 'text',
+          'label' => t('Existing system path'),
+          'description' => t('Specifies the existing path you wish to alias. For example: node/28, forum/1, taxonomy/term/1+2.') .' '. t('Leave it empty to delete URL aliases pointing to the given path alias.'),
+          'optional' => TRUE,
+        ),
+        'alias' => array(
+          'type' => 'text',
+          'label' => t('URL alias'),
+          'description' => t('Specify an alternative path by which this data can be accessed. For example, "about" for an about page. Use a relative path and do not add a trailing slash.') .' '. t('Leave it empty to delete URL aliases pointing to the given system path.'),
+          'optional' => TRUE,
+          'cleaning callback' => 'rules_path_clean_replacement_values',
+        ),
+        'language' => array(
+          'type' => 'token',
+          'label' => t('Language'),
+          'description' => t('If specified, the language for which the URL alias applies.'),
+          'options list' => 'entity_metadata_language_list',
+          'optional' => TRUE,
+          'default value' => LANGUAGE_NONE,
+        ),
+      ),
+      'base' => 'rules_action_path_alias',
+      'callbacks' => array('dependencies' => 'rules_path_dependencies'),
+      'access callback' => 'rules_path_integration_access',
+    ),
+    'node_path_alias' => array(
+      'label' => t("Create or delete a content's URL alias"),
+      'group' => t('Path'),
+      'parameter' => array(
+        'node' => array(
+          'type' => 'node',
+          'label' => t('Content'),
+          'save' => TRUE,
+        ),
+        'alias' => array(
+          'type' => 'text',
+          'label' => t('URL alias'),
+          'description' => t('Specify an alternative path by which the content can be accessed. For example, "about" for an about page. Use a relative path and do not add a trailing slash.') .' '. t('Leave it empty to delete the URL alias.'),
+          'optional' => TRUE,
+          'cleaning callback' => 'rules_path_clean_replacement_values',
+        ),
+      ),
+      'base' => 'rules_action_node_path_alias',
+      'callbacks' => array('dependencies' => 'rules_path_dependencies'),
+      'access callback' => 'rules_path_integration_access',
+    ),
+    'taxonomy_term_path_alias' => array(
+      'label' => t("Create or delete a taxonomy term's URL alias"),
+      'group' => t('Path'),
+      'parameter' => array(
+        'node' => array(
+          'type' => 'taxonomy_term',
+          'label' => t('Taxonomy term'),
+          'save' => TRUE,
+        ),
+        'alias' => array(
+          'type' => 'text',
+          'label' => t('URL alias'),
+          'description' => t('Specify an alternative path by which the term can be accessed. For example, "content/drupal" for a Drupal term. Use a relative path and do not add a trailing slash.') .' '. t('Leave it empty to delete the URL alias.'),
+          'optional' => TRUE,
+          'cleaning callback' => 'rules_path_clean_replacement_values',
+        ),
+      ),
+      'base' => 'rules_action_node_path_alias',
+      'callbacks' => array('dependencies' => 'rules_path_dependencies'),
+      'access callback' => 'rules_path_integration_access',
+    ),
+  );
+}
+
+/**
+ * Callback to specify the path module as dependency.
+ */
+function rules_path_dependencies() {
+  return array('path');
+}
+
+/**
+ * Path integration access callback.
+ */
+function rules_path_integration_access($type, $name) {
+  if ($type == 'action' && $name == 'path_alias') {
+    return user_access('administer url aliases');
+  }
+  return user_access('create url aliases');
+}
+
+/**
+ * Implements hook_rules_condition_info() on behalf of the path module.
+ */
+function rules_path_condition_info() {
+  return array(
+    'path_has_alias' => array(
+      'label' => t('Path has URL alias'),
+      'group' => t('Path'),
+      'parameter' => array(
+        'source' => array(
+          'type' => 'text',
+          'label' => t('Existing system path'),
+          'description' => t('Specifies the existing path you wish to check for. For example: node/28, forum/1, taxonomy/term/1+2.'),
+          'optional' => TRUE,
+        ),
+        'language' => array(
+          'type' => 'token',
+          'label' => t('Language'),
+          'description' => t('If specified, the language for which the URL alias applies.'),
+          'options list' => 'entity_metadata_language_list',
+          'optional' => TRUE,
+          'default value' => LANGUAGE_NONE,
+        ),
+      ),
+      'base' => 'rules_condition_path_has_alias',
+      'callbacks' => array('dependencies' => 'rules_path_dependencies'),
+      'access callback' => 'rules_path_integration_access',
+    ),
+    'path_alias_exists' => array(
+      'label' => t('URL alias exists'),
+      'group' => t('Path'),
+      'parameter' => array(
+        'alias' => array(
+          'type' => 'text',
+          'label' => t('URL alias'),
+          'description' => t('Specify the URL alias to check for. For example, "about" for an about page.'),
+          'optional' => TRUE,
+          'cleaning callback' => 'rules_path_clean_replacement_values',
+        ),
+        'language' => array(
+          'type' => 'token',
+          'label' => t('Language'),
+          'description' => t('If specified, the language for which the URL alias applies.'),
+          'options list' => 'entity_metadata_language_list',
+          'optional' => TRUE,
+          'default value' => LANGUAGE_NONE,
+        ),
+      ),
+      'base' => 'rules_condition_path_alias_exists',
+      'callbacks' => array('dependencies' => 'rules_path_dependencies'),
+      'access callback' => 'rules_path_integration_access',
+    ),
+  );
+}
+
+/**
+ * @}
+ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/php.eval.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * @file
+ * Contains rules integration for the php module needed during evaluation.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * A class implementing a rules input evaluator processing PHP.
+ */
+class RulesPHPEvaluator extends RulesDataInputEvaluator {
+
+  public static function access() {
+    return user_access('use PHP for settings');
+  }
+
+  public static function getUsedVars($text, $var_info) {
+    if (strpos($text, '<?') !== FALSE) {
+      $used_vars = array();
+      foreach ($var_info as $name => $info) {
+        if (strpos($text, '$' . $name) !== FALSE) {
+          $used_vars[] = $name;
+        }
+      }
+      return $used_vars;
+    }
+  }
+
+  public function prepare($text, $var_info) {
+    // A returned NULL skips the evaluator.
+    $this->setting = self::getUsedVars($text, $var_info);
+  }
+
+  /**
+   * Evaluates PHP code contained in $text. This doesn't apply $options, thus
+   * the PHP code is responsible for behaving appropriately.
+   */
+  public function evaluate($text, $options, RulesState $state) {
+    $vars['eval_options'] = $options;
+    foreach ($this->setting as $key => $var_name) {
+      $vars[$var_name] = $state->get($var_name);
+    }
+    return rules_php_eval($text, rules_unwrap_data($vars));
+  }
+
+  public static function help($var_info) {
+    module_load_include('inc', 'rules', 'rules/modules/php.rules');
+
+    $render = array(
+      '#type' => 'fieldset',
+      '#title' => t('PHP Evaluation'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    ) + rules_php_evaluator_help($var_info);
+
+    return $render;
+  }
+}
+
+/**
+ * A data processor using PHP.
+ */
+class RulesPHPDataProcessor extends RulesDataProcessor {
+
+  protected static function form($settings, $var_info) {
+    $settings += array('code' => '');
+    $form = array(
+      '#type' => 'fieldset',
+      '#title' => t('PHP evaluation'),
+      '#collapsible' => TRUE,
+      '#collapsed' => empty($settings['code']),
+      '#description' => t('Enter PHP code to process the selected argument value.'),
+    );
+    $form['code'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Code'),
+      '#description' => t('Enter PHP code without &lt;?php ?&gt; delimiters that returns the processed value. The selected value is available in the variable $value. Example: %code', array('%code' => 'return $value + 1;')),
+      '#default_value' => $settings['code'],
+      '#weight' => 5,
+    );
+    return $form;
+  }
+
+  public static function access() {
+    return user_access('use PHP for settings');
+  }
+
+  public function process($value, $info, RulesState $state, RulesPlugin $element) {
+    $value = isset($this->processor) ? $this->processor->process($value, $info, $state, $element) : $value;
+    return rules_php_eval_return($this->setting['code'], array('value' => $value));
+  }
+}
+
+/**
+ * Action and condition callback: Execute PHP code.
+ */
+function rules_execute_php_eval($code, $settings, $state, $element) {
+  $data = array();
+  if (!empty($settings['used_vars'])) {
+    foreach ($settings['used_vars'] as $key => $var_name) {
+      $data[$var_name] = $state->get($var_name);
+    }
+  }
+  return rules_php_eval_return($code, rules_unwrap_data($data));
+}
+
+/**
+ * Evalutes the given PHP code, with the given variables defined.
+ *
+ * @param $code
+ *   The PHP code to run, with <?php ?>
+ * @param $arguments
+ *   Array containing variables to be extracted to the code.
+ *
+ * @return
+ *   The output of the php code.
+ */
+function rules_php_eval($code, $arguments = array()) {
+  extract($arguments);
+
+  ob_start();
+  print eval('?>'. $code);
+  $output = ob_get_contents();
+  ob_end_clean();
+
+  return $output;
+}
+
+/**
+ * Evalutes the given PHP code, with the given variables defined. This is like
+ * rules_php_eval() but does return the returned data from the PHP code.
+ *
+ * @param $code
+ *   The PHP code to run, without <?php ?>
+ * @param $arguments
+ * Array containing variables to be extracted to the code.
+ *
+ * @return
+ *   The return value of the evaled code.
+ */
+function rules_php_eval_return($code, $arguments = array()) {
+  extract($arguments);
+  return eval($code);
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/php.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * @file rules integration for the php module
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_file_info() on behalf of the php module.
+ */
+function rules_php_file_info() {
+  return array('modules/php.eval');
+}
+
+/**
+ * Implements hook_rules_evaluator_info() on behalf of the php module.
+ */
+function rules_php_evaluator_info() {
+  return array(
+    'php' => array(
+      'class' => 'RulesPHPEvaluator',
+      'type' => array('text', 'uri'),
+      'weight' => -10,
+      'module' => 'php',
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_data_processor_info() on behalf of the php module.
+ */
+function rules_php_data_processor_info() {
+  return array(
+    'php' => array(
+      'class' => 'RulesPHPDataProcessor',
+      'type' => array('text', 'token',  'decimal', 'integer', 'date', 'duration', 'boolean', 'uri'),
+      'weight' => 10,
+      'module' => 'php',
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_action_info() on behalf of the php module.
+ */
+function rules_php_action_info() {
+  return array(
+    'php_eval' => array(
+      'label' => t('Execute custom PHP code'),
+      'group' => t('PHP'),
+      'parameter' => array(
+        'code' => array(
+          'restriction' => 'input',
+          'type' => 'text',
+          'label' => t('PHP code'),
+          'description' => t('Enter PHP code without &lt;?php ?&gt; delimiters.'),
+        ),
+      ),
+      'base' => 'rules_execute_php_eval',
+      'access callback' => 'rules_php_integration_access',
+    ),
+  );
+}
+
+/**
+ * Alter the form for improved UX.
+ */
+function rules_execute_php_eval_form_alter(&$form, &$form_state) {
+  // Remove the PHP evaluation help to avoid confusion whether <?php tags should
+  // be used. But keep the help about available variables.
+  $form['parameter']['code']['settings']['help']['php']['#type'] = 'container';
+  $form['parameter']['code']['settings']['help']['php']['top']['#markup'] = t('The following variables are available and may be used by your PHP code:');
+}
+
+/**
+ * Process the settings to prepare code execution.
+ */
+function rules_execute_php_eval_process(RulesAbstractPlugin $element) {
+  $element->settings['used_vars'] = RulesPHPEvaluator::getUsedVars('<?' . $element->settings['code'], $element->availableVariables());
+}
+
+/**
+ * Specify the php module as dependency.
+ */
+function rules_execute_php_eval_dependencies() {
+  return array('php');
+}
+
+/**
+ * PHP integration access callback.
+ */
+function rules_php_integration_access() {
+  return user_access('use PHP for settings');
+}
+
+/**
+ * Implements hook_rules_condition_info() on behalf of the PHP module.
+ */
+function rules_php_condition_info() {
+  return array(
+    'php_eval' => array(
+      'label' => t('Execute custom PHP code'),
+      'group' => t('PHP'),
+      'parameter' => array(
+        'code' => array(
+          'restriction' => 'input',
+          'type' => 'text',
+          'label' => t('PHP code'),
+          'description' => t('Enter PHP code without &lt;?php ?&gt; delimiters that returns a boolean value; e.g. <code>@code</code>.', array('@code' => "return arg(0) == 'node';")),
+        ),
+      ),
+      'base' => 'rules_execute_php_eval',
+      'access callback' => 'rules_php_integration_access',
+    ),
+  );
+}
+
+/**
+ * Generates help for the PHP actions, conditions and input evaluator.
+ */
+function rules_php_evaluator_help($var_info, $action_help = FALSE) {
+  $render['top'] = array(
+    '#prefix' => '<p>',
+    '#suffix' => '</p>',
+    '#markup' => t('PHP code inside of &lt;?php ?&gt; delimiters will be evaluated and replaced by its output. E.g. &lt;? echo 1+1?&gt; will be replaced by 2.')
+                 . ' ' . t('Furthermore you can make use of the following variables:'),
+  );
+  $render['vars'] = array(
+    '#theme' => 'table',
+    '#header' => array(t('Variable name'), t('Type'), t('Description')),
+    '#attributes' => array('class' => array('rules-php-help')),
+  );
+
+  $cache = rules_get_cache();
+  foreach ($var_info as $name => $info) {
+    $row   = array();
+    $row[] = '$'. check_plain($name);
+    $label = isset($cache['data_info'][$info['type']]['label']) ? $cache['data_info'][$info['type']]['label'] : $info['type'];
+    $row[] = check_plain(drupal_ucfirst($label));
+    $row[] = check_plain($info['label']);
+    $render['vars']['#rows'][] = $row;
+  }
+
+  if ($action_help) {
+    $render['updated_help'] = array(
+      '#prefix' => '<p>',
+      '#suffix' => '</p>',
+      '#markup' => t("If you want to change a variable just return an array of new variable values, e.g.: !code", array('!code' => '<pre>return array("node" => $node);</pre>')),
+    );
+  }
+  return $render;
+}
+
+/**
+ * @}
+ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/rules_core.eval.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,242 @@
+<?php
+
+/**
+ * @file
+ * Contains rules core integration needed during evaluation.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Action and condition callback: Invokes a rules component.
+ *
+ * We do not use the execute() method, but handle executing ourself. That way
+ * we can utilize the existing state for saving passed variables.
+ */
+function rules_element_invoke_component($arguments, RulesPlugin $element) {
+  $info = $element->info();
+  $state = $arguments['state'];
+  $wrapped_args = $state->currentArguments;
+
+  if ($component = rules_get_cache('comp_' . $info['#config_name'])) {
+    $replacements = array('%label' => $component->label(), '@plugin' => $component->plugin());
+    // Handle recursion prevention.
+    if ($state->isBlocked($component)) {
+      return rules_log('Not evaluating @plugin %label to prevent recursion.', $replacements, RulesLog::INFO, $component);
+    }
+    $state->block($component);
+    rules_log('Evaluating @plugin %label.', $replacements, RulesLog::INFO, $component, TRUE);
+    module_invoke_all('rules_config_execute', $component);
+
+    // Manually create a new evaluation state and evaluate the component.
+    $args = array_intersect_key($wrapped_args, $component->parameterInfo());
+    $new_state = $component->setUpState($wrapped_args);
+    $return = $component->evaluate($new_state);
+
+    // Care for the right return value in case we have to provide vars.
+    if ($component instanceof RulesActionInterface && !empty($info['provides'])) {
+      $return = array();
+      foreach ($info['provides'] as $var => $var_info) {
+        $return[$var] = $new_state->get($var);
+      }
+    }
+
+    // Now merge the info about to be saved variables in the parent state.
+    $state->mergeSaveVariables($new_state, $component, $element->settings);
+    $state->unblock($component);
+
+    // Cleanup the state, what saves not mergable variables now.
+    $new_state->cleanup();
+    rules_log('Finished evaluation of @plugin %label.', $replacements, RulesLog::INFO, $component, FALSE);
+    return $return;
+  }
+  else {
+    throw new RulesEvaluationException('Unable to get the component %name', array('%name' => $info['#config_name']), $element, RulesLog::ERROR);
+  }
+}
+
+/**
+ * A class implementing a rules input evaluator processing date input. This is
+ * needed to treat relative date inputs for strtotime right, consider "now".
+ */
+class RulesDateInputEvaluator extends RulesDataInputEvaluator {
+
+  const DATE_REGEX_LOOSE = '/^(\d{4})-?(\d{2})-?(\d{2})([T\s]?(\d{2}):?(\d{2}):?(\d{2})?)?$/';
+
+  public function prepare($text, $var_info) {
+    if (is_numeric($text)) {
+      // Let rules skip this input evaluators in case it's already a timestamp.
+      $this->setting = NULL;
+    }
+  }
+
+  public function evaluate($text, $options, RulesState $state) {
+    return self::gmstrtotime($text);
+  }
+
+  /**
+   * Convert a time string to a GMT (UTC) unix timestamp.
+   */
+  public static function gmstrtotime($date) {
+    // Pass the current timestamp in UTC to ensure the retrieved time is UTC.
+    return strtotime($date, time());
+  }
+
+  /**
+   * Determine whether the given date string specifies a fixed date.
+   */
+  public static function isFixedDateString($date) {
+    return is_string($date) && preg_match(self::DATE_REGEX_LOOSE, $date);
+  }
+}
+
+/**
+ * A class implementing a rules input evaluator processing URI inputs to make
+ * sure URIs are absolute and path aliases get applied.
+ */
+class RulesURIInputEvaluator extends RulesDataInputEvaluator {
+
+  public function prepare($uri, $var_info) {
+    if (!isset($this->processor) && valid_url($uri, TRUE)) {
+      // Only process if another evaluator is used or the url is not absolute.
+      $this->setting = NULL;
+    }
+  }
+
+  public function evaluate($uri, $options, RulesState $state) {
+    if (!url_is_external($uri)) {
+      // Extract the path and build the URL using the url() function, so URL
+      // aliases are applied and query parameters and fragments get handled.
+      $url = drupal_parse_url($uri);
+      $url_options = array('absolute' => TRUE);
+      $url_options['query'] = $url['query'];
+      $url_options['fragment'] = $url['fragment'];
+      return url($url['path'], $url_options);
+    }
+    elseif (valid_url($uri)) {
+      return $uri;
+    }
+    throw new RulesEvaluationException('Input evaluation generated an invalid URI.', array(), NULL, RulesLog::WARN);
+  }
+}
+
+/**
+ * A data processor for applying date offsets.
+ */
+class RulesDateOffsetProcessor extends RulesDataProcessor {
+
+  protected static function form($settings, $var_info) {
+    $settings += array('value' => '');
+    $form = array(
+      '#type' => 'fieldset',
+      '#title' => t('Add offset'),
+      '#collapsible' => TRUE,
+      '#collapsed' => empty($settings['value']),
+      '#description' => t('Add an offset to the selected date.'),
+    );
+    $form['value'] = array(
+      '#type' => 'rules_duration',
+      '#title' => t('Offset'),
+      '#description' => t('Note that you can also specify negative numbers.'),
+      '#default_value' => $settings['value'],
+      '#weight' => 5,
+    );
+    return $form;
+  }
+
+  public function process($value, $info, RulesState $state, RulesPlugin $element) {
+    $value = isset($this->processor) ? $this->processor->process($value, $info, $state, $element) : $value;
+    return RulesDateOffsetProcessor::applyOffset($value, $this->setting['value']);
+  }
+
+  /**
+   * Intelligently applies the given date offset in seconds.
+   *
+   * Intelligently apply duration values > 1 day, i.e. convert the duration
+   * to its biggest possible unit (months, days) and apply it to the date with
+   * the given unit. That's necessary as the number of days in a month
+   * differs, as well as the number of hours for a day (on DST changes).
+   */
+  public static function applyOffset($timestamp, $offset) {
+    if (abs($offset) >= 86400) {
+
+      // Get the days out of the seconds.
+      $days = intval($offset / 86400);
+      $sec = $offset % 86400;
+      // Get the months out of the number of days.
+      $months = intval($days / 30);
+      $days = $days % 30;
+
+      // Apply the offset using the DateTime::modify and convert it back to a
+      // timestamp.
+      $date = date_create("@$timestamp");
+      $date->modify("$months months $days days $sec seconds");
+      return $date->format('U');
+    }
+    else {
+      return $timestamp + $offset;
+    }
+  }
+}
+
+/**
+ * A data processor for applying numerical offsets.
+ */
+class RulesNumericOffsetProcessor extends RulesDataProcessor {
+
+  protected static function form($settings, $var_info) {
+    $settings += array('value' => '');
+    $form = array(
+      '#type' => 'fieldset',
+      '#title' => t('Add offset'),
+      '#collapsible' => TRUE,
+      '#collapsed' => empty($settings['value']),
+      '#description' => t('Add an offset to the selected number. E.g. an offset of "1" adds 1 to the number before it is passed on as argument.'),
+    );
+    $form['value'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Offset'),
+      '#description' => t('Note that you can also specify negative numbers.'),
+      '#default_value' => $settings['value'],
+      '#element_validate' => array('rules_ui_element_integer_validate'),
+      '#weight' => 5,
+    );
+    return $form;
+  }
+
+  public function process($value, $info, RulesState $state, RulesPlugin $element) {
+    $value = isset($this->processor) ? $this->processor->process($value, $info, $state, $element) : $value;
+    return $value + $this->setting['value'];
+  }
+}
+
+
+/**
+ * A custom wrapper class for vocabularies that is capable of loading vocabularies by machine name.
+ */
+class RulesTaxonomyVocabularyWrapper extends EntityDrupalWrapper {
+
+  /**
+   * Overridden to support identifying vocabularies by machine names.
+   */
+  protected function setEntity($data) {
+    if (isset($data) && $data !== FALSE && !is_object($data) && !is_numeric($data)) {
+      // The vocabulary name has been passed.
+      parent::setEntity(taxonomy_vocabulary_machine_name_load($data));
+    }
+    else {
+      parent::setEntity($data);
+    }
+  }
+
+  /**
+   * Overriden to permit machine names as values.
+   */
+  public function validate($value) {
+    if (isset($value) && is_string($value)) {
+      return TRUE;
+    }
+    return parent::validate($value);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/rules_core.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,332 @@
+<?php
+
+/**
+ * @file Rules core integration providing data types and conditions and
+ * actions to invoke configured components.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_category_info() on behalf of the rules_core.
+ */
+function rules_rules_core_category_info() {
+  return array(
+    'rules_components' => array(
+      'label' => t('Components'),
+      'equals group' => t('Components'),
+      'weight' => 50,
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_file_info() on behalf of the pseudo rules_core module.
+ *
+ * @see rules_core_modules()
+ */
+function rules_rules_core_file_info() {
+  return array('modules/rules_core.eval');
+}
+
+/**
+ * Implements hook_rules_data_info() on behalf of the pseudo rules_core module.
+ *
+ * @see rules_core_modules()
+ */
+function rules_rules_core_data_info() {
+  $return = array(
+    'text' => array(
+      'label' => t('text'),
+      'ui class' => 'RulesDataUIText',
+      'token type' => 'rules_text',
+    ),
+    'token' => array(
+      'label' => t('text token'),
+      'parent' => 'text',
+      'ui class' => 'RulesDataUITextToken',
+      'token type' => 'rules_token',
+    ),
+    // A formatted text as used by entity metadata.
+    'text_formatted' => array(
+      'label' => t('formatted text'),
+      'ui class' => 'RulesDataUITextFormatted',
+      'wrap' => TRUE,
+      'property info' => entity_property_text_formatted_info(),
+    ),
+    'decimal' => array(
+      'label' => t('decimal number'),
+      'parent' => 'text',
+      'ui class' => 'RulesDataUIDecimal',
+      'token type' => 'rules_decimal',
+    ),
+    'integer' => array(
+      'label' => t('integer'),
+      'class' => 'RulesIntegerWrapper',
+      'parent' => 'decimal',
+      'ui class' => 'RulesDataUIInteger',
+      'token type' => 'rules_integer',
+    ),
+    'date' => array(
+      'label' => t('date'),
+      'ui class' => 'RulesDataUIDate',
+      'token type' => 'rules_date',
+    ),
+    'duration' => array(
+      'label' => t('duration'),
+      'parent' => 'integer',
+      'ui class' => 'RulesDataUIDuration',
+      'token type' => 'rules_duration',
+    ),
+    'boolean' => array(
+      'label' => t('truth value'),
+      'ui class' => 'RulesDataUIBoolean',
+      'token type' => 'rules_boolean',
+    ),
+    'uri' => array(
+      'label' => t('URI'),
+      'parent' => 'text',
+      // Clean inserted tokens with "rawurlencode".
+      'cleaning callback' => 'rawurlencode',
+      'ui class' => 'RulesDataUIURI',
+      'token type' => 'rules_uri',
+    ),
+    'list' => array(
+      'label' => t('list', array(), array('context' => 'data_types')),
+      'wrap' => TRUE,
+      'group' => t('List', array(), array('context' => 'data_types')),
+    ),
+    'list<text>' => array(
+      'label' => t('list of text'),
+      'ui class' => 'RulesDataUIListText',
+      'wrap' => TRUE,
+      'group' => t('List', array(), array('context' => 'data_types')),
+    ),
+    'list<integer>' => array(
+      'label' => t('list of integer'),
+      'ui class' => 'RulesDataUIListInteger',
+      'wrap' => TRUE,
+      'group' => t('List', array(), array('context' => 'data_types')),
+    ),
+    'list<token>' => array(
+      'label' => t('list of text tokens'),
+      'ui class' => 'RulesDataUIListToken',
+      'wrap' => TRUE,
+      'group' => t('List', array(), array('context' => 'data_types')),
+    ),
+    'entity' => array(
+      'label' => t('any entity'),
+      'group' => t('Entity'),
+      'is wrapped' => TRUE,
+    ),
+  );
+  foreach (entity_get_info() as $type => $info) {
+    if (!empty($info['label'])) {
+      $return[$type] = array(
+        'label' => strtolower($info['label'][0]) . substr($info['label'], 1),
+        'parent' => 'entity',
+        'wrap' => TRUE,
+        'group' => t('Entity'),
+        'ui class' => empty($info['exportable']) ? 'RulesDataUIEntity' : 'RulesDataUIEntityExportable',
+      );
+      // If this entity type serves as bundle for another one, provide an
+      // options list for selecting a bundle entity.
+      if (!empty($info['bundle of'])) {
+        $return[$type]['ui class'] =  'RulesDataUIBundleEntity';
+      }
+    }
+  }
+
+  if (module_exists('taxonomy')) {
+    // For exportability identify vocabularies by name.
+    $return['taxonomy_vocabulary']['wrapper class'] = 'RulesTaxonomyVocabularyWrapper';
+    $return['taxonomy_vocabulary']['ui class'] = 'RulesDataUITaxonomyVocabulary';
+  }
+
+  return $return;
+}
+
+/**
+ * Implements hook_rules_data_info_alter() on behalf of the pseudo rules_core module.
+ *
+ * Makes sure there is a list<type> data type for each type registered.
+ *
+ * @see rules_rules_data_info_alter()
+ */
+function rules_rules_core_data_info_alter(&$data_info) {
+  foreach ($data_info as $type => $info) {
+    if (!entity_property_list_extract_type($type)) {
+      $list_type = "list<$type>";
+      if (!isset($data_info[$list_type])) {
+        $data_info[$list_type] = array(
+          'label' => t('list of @type_label items', array('@type_label' => $info['label'])),
+          'wrap' => TRUE,
+          'group' => t('List', array(), array('context' => 'data_types')),
+        );
+        if (isset($info['parent']) && $info['parent'] == 'entity') {
+          $data_info[$list_type]['ui class'] = 'RulesDataUIListEntity';
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_rules_evaluator_info() on behalf of the pseudo rules_core
+ * module.
+ *
+ * @see rules_core_modules()
+ */
+function rules_rules_core_evaluator_info() {
+  return array(
+    // Process strtotime() inputs to timestamps.
+    'date' => array(
+      'class' => 'RulesDateInputEvaluator',
+      'type' => 'date',
+      'weight' => -10,
+     ),
+    // Post-process any input value to absolute URIs.
+    'uri' => array(
+      'class' => 'RulesURIInputEvaluator',
+      'type' => 'uri',
+      'weight' => 50,
+     ),
+  );
+}
+
+/**
+ * Implements hook_rules_data_processor_info() on behalf of the pseudo
+ * rules_core module.
+ *
+ * @see rules_core_modules()
+ */
+function rules_rules_core_data_processor_info() {
+  return array(
+    'date_offset' => array(
+      'class' => 'RulesDateOffsetProcessor',
+      'type' => 'date',
+      'weight' => -2,
+     ),
+    'num_offset' => array(
+      'class' => 'RulesNumericOffsetProcessor',
+      'type' => array('integer', 'decimal'),
+      'weight' => -2,
+     ),
+  );
+}
+
+/**
+ * Implements hook_rules_condition_info() on behalf of the pseudo rules_core
+ * module.
+ *
+ * @see rules_core_modules()
+ */
+function rules_rules_core_condition_info() {
+  $defaults = array(
+    'group' => t('Components'),
+    'base' => 'rules_element_invoke_component',
+    'named parameter' => TRUE,
+    'access callback' => 'rules_element_invoke_component_access_callback',
+  );
+  $items = array();
+  foreach (rules_get_components(FALSE, 'condition') as $name => $config) {
+    $items['component_' . $name] = $defaults + array(
+      'label' => $config->plugin() . ': ' . drupal_ucfirst($config->label()),
+      'parameter' => $config->parameterInfo(),
+    );
+    $items['component_' . $name]['#config_name'] = $name;
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_rules_action_info() on behalf of the pseudo rules_core
+ * module.
+ *
+ * @see rules_core_modules()
+ */
+function rules_rules_core_action_info() {
+  $defaults = array(
+    'group' => t('Components'),
+    'base' => 'rules_element_invoke_component',
+    'named parameter' => TRUE,
+    'access callback' => 'rules_element_invoke_component_access_callback',
+  );
+  $items = array();
+  foreach (rules_get_components(FALSE, 'action') as $name => $config) {
+    $items['component_' . $name] = $defaults + array(
+      'label' => $config->plugin() . ': ' . drupal_ucfirst($config->label()),
+      'parameter' => $config->parameterInfo(),
+      'provides' => $config->providesVariables(),
+    );
+    $items['component_' . $name]['#config_name'] = $name;
+  }
+  return $items;
+}
+
+/**
+ * Implements RulesPluginUIInterface::operations() for the action.
+ */
+function rules_element_invoke_component_operations(RulesPlugin $element) {
+  $defaults = $element->extender('RulesPluginUI')->operations();
+  $info = $element->info();
+
+  // Add an operation for editing the component.
+  $defaults['#links']['component'] = array(
+    'title' => t('edit component'),
+    'href' => RulesPluginUI::path($info['#config_name']),
+  );
+  return $defaults;
+}
+
+/**
+ * Validate callback to make sure the invoked component exists and is not dirty.
+ *
+ * @see rules_scheduler_action_schedule_validate()
+ */
+function rules_element_invoke_component_validate(RulesPlugin $element) {
+  $info = $element->info();
+  $component = rules_config_load($info['#config_name']);
+  // Check if a component exists.
+  if (!$component) {
+    throw new RulesIntegrityException(t('The component %config does not exist.', array('%config' => $info['#config_name'])), $element);
+  }
+  // Check if a component is marked as dirty.
+  rules_config_update_dirty_flag($component);
+  if (!empty($component->dirty)) {
+    throw new RulesIntegrityException(t('The utilized component %config fails the integrity check.', array('%config' => $info['#config_name'])), $element);
+  }
+}
+
+/**
+ * Implements the features export callback of the RulesPluginFeaturesIntegrationInterace.
+ */
+function rules_element_invoke_component_features_export(&$export, &$pipe, $module_name = '', $element) {
+  // Add the used component to the pipe.
+  $info = $element->info();
+  $pipe['rules_config'][] = $info['#config_name'];
+}
+
+/**
+ * Access callback for the invoke component condition/action.
+ */
+function rules_element_invoke_component_access_callback($type, $name) {
+  // Cut of the leading 'component_' from the action name.
+  $component = rules_config_load(substr($name, 10));
+
+  if (!$component) {
+    // Missing component.
+    return FALSE;
+  }
+  // If access is not exposed for this component, default to component access.
+  if (empty($component->access_exposed)) {
+    return $component->access();
+  }
+  // Apply the permissions.
+  return user_access('bypass rules access') || user_access("use Rules component $component->name");
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/system.eval.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,267 @@
+<?php
+
+/**
+ * @file
+ * Contains rules integration for the system module needed during evaluation.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Action: Show a drupal message.
+ */
+function rules_action_drupal_message($message, $status, $repeat) {
+  drupal_set_message(filter_xss_admin($message), $status, $repeat);
+}
+
+/**
+ * Action: Page redirect.
+ *
+ * @see rules_page_build()
+ * @see rules_drupal_goto_alter()
+ */
+function rules_action_drupal_goto($url, $force = FALSE, $destination = FALSE) {
+  // Don't let administrators lock them out from Rules administration pages.
+  if (isset($_GET['q']) && strpos($_GET['q'], 'admin/config/workflow/rules') === 0) {
+    rules_log('Skipped page redirect on Rules administration page.', array(), RulesLog::WARN);
+    return;
+  }
+  // Do not redirect during batch processing.
+  if (($batch = batch_get()) && isset($batch['current_set'])) {
+    rules_log('Skipped page redirect during batch processing.');
+    return;
+  }
+
+  // Keep the current destination parameter if there is one set.
+  if ($destination) {
+    $url .= strpos($url, '?') === FALSE ? '?' : '&';
+    $url .= drupal_http_build_query(drupal_get_destination());
+  }
+  // If force is enabled, remove any destination parameter.
+  if ($force && isset($_GET['destination'])) {
+    unset($_GET['destination']);
+  }
+  // We don't invoke drupal_goto() right now, as this would end the the current
+  // page execution unpredictly for modules. So we'll take over drupal_goto()
+  // calls from somewhere else via hook_drupal_goto_alter() and make sure
+  // a drupal_goto() is invoked before the page is output with
+  // rules_page_build().
+  $GLOBALS['_rules_action_drupal_goto_do'] = array($url, $force);
+}
+
+/**
+ * Action: Set breadcrumb.
+ */
+function rules_action_breadcrumb_set(array $titles, array $paths) {
+  $trail = array(l(t('Home'), ''));
+  foreach ($titles as $i => $title) {
+    // Skip empty titles.
+    if ($title = trim($title)) {
+      // Output plaintext instead of a link if there is a title
+      // without a path.
+      $path = trim($paths[$i]);
+      if (!empty($paths[$i]) && $paths[$i] != '<none>') {
+        $trail[] = l($title, trim($paths[$i]));
+      }
+      else {
+        $trail[] = check_plain($title);
+      }
+    }
+  }
+  drupal_set_breadcrumb($trail);
+}
+
+/**
+ * Action Implementation: Send mail.
+ */
+function rules_action_mail($to, $subject, $message, $from = NULL, $langcode, $settings, RulesState $state, RulesPlugin $element) {
+  $to = str_replace(array("\r", "\n"), '', $to);
+  $from = !empty($from) ? str_replace(array("\r", "\n"), '', $from) : NULL;
+  $params = array(
+    'subject' => $subject,
+    'message' => $message,
+    'langcode' => $langcode,
+  );
+  // Set a unique key for this mail.
+  $name = isset($element->root()->name) ? $element->root()->name : 'unnamed';
+  $key = 'rules_action_mail_' . $name . '_' . $element->elementId();
+  $languages = language_list();
+  $language = isset($languages[$langcode]) ? $languages[$langcode] : language_default();
+
+  $message = drupal_mail('rules', $key, $to, $language, $params, $from);
+  if ($message['result']) {
+    watchdog('rules', 'Successfully sent email to %recipient', array('%recipient' => $to));
+  }
+}
+
+/**
+ * Action: Send mail to all users of a specific role group(s).
+ */
+function rules_action_mail_to_users_of_role($roles, $subject, $message, $from = NULL, $settings, RulesState $state, RulesPlugin $element) {
+  $from = !empty($from) ? str_replace(array("\r", "\n"), '', $from) : NULL;
+
+  // All authenticated users, which is everybody.
+  if (in_array(DRUPAL_AUTHENTICATED_RID, $roles)) {
+    $result = db_query('SELECT mail FROM {users} WHERE uid > 0');
+  }
+  else {
+    $rids = implode(',', $roles);
+    // Avoid sending emails to members of two or more target role groups.
+    $result = db_query('SELECT DISTINCT u.mail FROM {users} u INNER JOIN {users_roles} r ON u.uid = r.uid WHERE r.rid IN ('. $rids .')');
+  }
+
+  // Now, actually send the mails.
+  $params = array(
+    'subject' => $subject,
+    'message' => $message,
+  );
+  // Set a unique key for this mail.
+  $name = isset($element->root()->name) ? $element->root()->name : 'unnamed';
+  $key = 'rules_action_mail_to_users_of_role_' . $name . '_' . $element->elementId();  $languages = language_list();
+
+  $message = array('result' => TRUE);
+  foreach ($result as $row) {
+    $message = drupal_mail('rules', $key, $row->mail, language_default(), $params, $from);
+    if (!$message['result']) {
+      break;
+    }
+  }
+  if ($message['result']) {
+    $role_names = array_intersect_key(user_roles(TRUE), array_flip($roles));
+    watchdog('rules', 'Successfully sent email to the role(s) %roles.', array('%roles' => implode(', ', $role_names)));
+  }
+}
+
+/**
+ * Implements hook_mail().
+ *
+ * Set's the message subject and body as configured.
+ */
+function rules_mail($key, &$message, $params) {
+
+  $message['subject'] .= str_replace(array("\r", "\n"), '', $params['subject']);
+  $message['body'][] = $params['message'];
+}
+
+/**
+ * A class implementing a rules input evaluator processing tokens.
+ */
+class RulesTokenEvaluator extends RulesDataInputEvaluator {
+
+  public function prepare($text, $var_info) {
+    $text = is_array($text) ? implode('', $text) : $text;
+    // Skip this evaluator if there are no tokens.
+    $this->setting = token_scan($text) ? TRUE : NULL;
+  }
+
+  /**
+   * We replace the tokens on our own as we cannot use token_replace(), because
+   * token usually assumes that $data['node'] is a of type node, which doesn't
+   * hold in general in our case.
+   * So we properly map variable names to variable data types and then run the
+   * replacement ourself.
+   */
+  public function evaluate($text, $options, RulesState $state) {
+    $var_info = $state->varInfo();
+    $options += array('sanitize' => FALSE);
+
+    $replacements = array();
+    $data = array();
+    // We also support replacing tokens in a list of textual values.
+    $whole_text = is_array($text) ? implode('', $text) : $text;
+    foreach (token_scan($whole_text) as $var_name => $tokens) {
+      $var_name = str_replace('-', '_', $var_name);
+      if (isset($var_info[$var_name]) && ($token_type = _rules_system_token_map_type($var_info[$var_name]['type']))) {
+        // We have to key $data with the type token uses for the variable.
+        $data = rules_unwrap_data(array($token_type => $state->get($var_name)), array($token_type => $var_info[$var_name]));
+        $replacements += token_generate($token_type, $tokens, $data, $options);
+      }
+      else {
+        $replacements += token_generate($var_name, $tokens, array(), $options);
+      }
+      // Remove tokens if no replacement value is found. As token_replace() does
+      // if 'clear' is set.
+      $replacements += array_fill_keys($tokens, '');
+    }
+
+    // Optionally clean the list of replacement values.
+    if (!empty($options['callback']) && function_exists($options['callback'])) {
+      $function = $options['callback'];
+      $function($replacements, $data, $options);
+    }
+
+    // Actually apply the replacements.
+    $tokens = array_keys($replacements);
+    $values = array_values($replacements);
+    if (is_array($text)) {
+      foreach ($text as $i => $text_item) {
+        $text[$i] = str_replace($tokens, $values, $text_item);
+      }
+      return $text;
+    }
+    return str_replace($tokens, $values, $text);
+  }
+
+  /**
+   * Create documentation about the available replacement patterns.
+   *
+   * @param array $var_info
+   *   Array with the available variables.
+   *
+   * @return array
+   *   Renderable array with the replacement pattern documentation.
+   */
+  public static function help($var_info) {
+    $render = array(
+      '#type' => 'fieldset',
+      '#title' => t('Replacement patterns'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#description' => t('Note that token replacements containing chained objects – such as [node:author:uid] – are not listed here, but are still available. The <em>data selection</em> input mode may help you find more complex replacement patterns. See <a href="@url">the online documentation</a> for more information about complex replacement patterns.',
+        array('@url' => rules_external_help('chained-tokens'))),
+    );
+    $token_info = token_info();
+    foreach ($var_info as $name => $info) {
+      $token_types[$name] = _rules_system_token_map_type($info['type']);
+    }
+
+    foreach ($token_types as $name => $token_type) {
+      if (isset($token_info['types'][$token_type])) {
+        $render[$name] = array(
+          '#theme' => 'table',
+          '#header' => array(t('Token'), t('Label'), t('Description')),
+          '#prefix' => '<h3>' . t('Replacement patterns for %label', array('%label' => $var_info[$name]['label'])) . '</h3>',
+        );
+        foreach ($token_info['tokens'][$token_type] as $token => $info) {
+          $token = '[' . str_replace('_', '-', $name) . ':' . $token . ']';
+          $render[$name]['#rows'][$token] = array(
+            check_plain($token),
+            check_plain($info['name']),
+            check_plain($info['description']),
+          );
+        }
+      }
+    }
+    return $render;
+  }
+}
+
+/**
+ * Looks for a token type mapping. Defaults to passing through the type.
+ */
+function _rules_system_token_map_type($type) {
+  $entity_info = entity_get_info();
+  if (isset($entity_info[$type]['token type'])) {
+    return $entity_info[$type]['token type'];
+  }
+  $cache = rules_get_cache();
+  if (isset($cache['data_info'][$type]['token type'])) {
+    return $cache['data_info'][$type]['token type'];
+  }
+  return $type;
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/system.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,288 @@
+<?php
+
+/**
+ * @file rules integration for the system module
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_file_info() on behalf of the system module.
+ */
+function rules_system_file_info() {
+  return array('modules/system.eval');
+}
+
+/**
+ * Implements hook_rules_event_info() on behalf of the system module.
+ */
+function rules_system_event_info() {
+  return array(
+    'init' => array(
+      'label' => t('Drupal is initializing'),
+      'group' => t('System'),
+      'help' => t("Be aware that some actions might initialize the theme system. After that, it's impossible for any module to change the used theme."),
+      'access callback' => 'rules_system_integration_access',
+    ),
+    'cron' => array(
+      'label' => t('Cron maintenance tasks are performed'),
+      'group' => t('System'),
+      'access callback' => 'rules_system_integration_access',
+    ),
+    'watchdog' => array(
+      'label' => t('System log entry is created'),
+      'variables' => array(
+        'log_entry' => array(
+          'type' => 'log_entry',
+          'label' => t('Log entry'),
+        ),
+      ),
+      'group' => t('System'),
+      'access callback' => 'rules_system_integration_access',
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_data_info() on behalf of the system module.
+ * @see rules_core_modules()
+ */
+function rules_system_data_info() {
+  return array(
+    'log_entry' => array(
+      'label' => t('watchdog log entry'),
+      'wrap' => TRUE,
+      'property info' => _rules_system_watchdog_log_entry_info(),
+    ),
+  );
+}
+
+/**
+ * Defines property info for watchdog log entries, used by the log entry data
+ * type to provide an useful metadata wrapper.
+ */
+function _rules_system_watchdog_log_entry_info() {
+  return array(
+    'type' => array(
+      'type' => 'text',
+      'label' => t('The category to which this message belongs'),
+    ),
+    'message' => array(
+      'type' => 'text',
+      'label' => ('Log message'),
+      'getter callback' => 'rules_system_log_get_message',
+      'sanitized' => TRUE,
+    ),
+    'severity' => array(
+      'type' => 'integer',
+      'label' => t('Severity'),
+      'options list' => 'watchdog_severity_levels',
+    ),
+    'request_uri' => array(
+      'type' => 'uri',
+      'label' => t('Request uri'),
+    ),
+    'link' => array(
+      'type' => 'text',
+      'label' => t('An associated, HTML formatted link'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_action_info() on behalf of the system module.
+ */
+function rules_system_action_info() {
+  return array(
+    'drupal_message' => array(
+      'label' => t('Show a message on the site'),
+      'group' => t('System'),
+      'parameter' => array(
+        'message' => array(
+          'type' => 'text',
+          'label' => t('Message'),
+          'sanitize' => TRUE,
+          'translatable' => TRUE,
+        ),
+        'type' => array(
+          'type' => 'token',
+          'label' => t('Message type'),
+          'options list' => 'rules_action_drupal_message_types',
+          'default value' => 'status',
+          'optional' => TRUE,
+        ),
+        'repeat' => array(
+          'type' => 'boolean',
+          'label' => t('Repeat message'),
+          'description' => t("If disabled and the message has been already shown, then the message won't be repeated."),
+          'default value' => TRUE,
+          'optional' => TRUE,
+          'restriction' => 'input',
+        ),
+      ),
+      'base' => 'rules_action_drupal_message',
+      'access callback' => 'rules_system_integration_access',
+    ),
+    'redirect' => array(
+      'label' => t('Page redirect'),
+      'group' => t('System'),
+      'parameter' => array(
+        'url' => array(
+          'type' => 'uri',
+          'label' => t('URL'),
+          'description' => t('A Drupal path, path alias, or external URL to redirect to. Enter (optional) queries after "?" and (optional) anchor after "#".'),
+        ),
+        'force' => array(
+          'type' => 'boolean',
+          'label' => t('Force redirect'),
+          'restriction' => 'input',
+          'description' => t("Force the redirect even if another destination parameter is present. Per default Drupal would redirect to the path given as destination parameter, in case it is set. Usually the destination parameter is set by appending it to the URL, e.g. !example_url", array('!example_url' => 'http://example.com/user/login?destination=node/2')),
+          'optional' => TRUE,
+          'default value' => TRUE,
+        ),
+        'destination' => array(
+          'type' => 'boolean',
+          'label' => t('Append destination parameter'),
+          'restriction' => 'input',
+          'description' => t('Whether to append a destination parameter to the URL, so another redirect issued later on would lead back to the origin page.'),
+          'optional' => TRUE,
+          'default value' => FALSE,
+        ),
+      ),
+      'base' => 'rules_action_drupal_goto',
+      'access callback' => 'rules_system_integration_access',
+    ),
+    'breadcrumb_set' => array(
+      'label' => t('Set breadcrumb'),
+      'group' => t('System'),
+      'parameter' => array(
+        'titles' => array(
+          'type' => 'list<text>',
+          'label' => t('Titles'),
+          'description' => t('A list of titles for the breadcrumb links.'),
+          'translatable' => TRUE,
+        ),
+        'paths' => array(
+          'type' => 'list<text>',
+          'label' => t('Paths'),
+          'description' => t('A list of Drupal paths for the breadcrumb links, matching the order of the titles.'),
+        ),
+      ),
+      'base' => 'rules_action_breadcrumb_set',
+      'access callback' => 'rules_system_integration_access',
+    ),
+    'mail' => array(
+      'label' => t('Send mail'),
+      'group' => t('System'),
+      'parameter' => array(
+        'to' => array(
+          'type' => 'text',
+          'label' => t('To'),
+          'description' => t('The e-mail address or addresses where the message will be sent to. The formatting of this string must comply with RFC 2822.'),
+        ),
+        'subject' => array(
+          'type' => 'text',
+          'label' => t('Subject'),
+          'description' => t("The mail's subject."),
+          'translatable' => TRUE,
+        ),
+        'message' => array(
+          'type' => 'text',
+          'label' => t('Message'),
+          'description' => t("The mail's message body."),
+          'translatable' => TRUE,
+        ),
+        'from' => array(
+          'type' => 'text',
+          'label' => t('From'),
+          'description' => t("The mail's from address. Leave it empty to use the site-wide configured address."),
+          'optional' => TRUE,
+        ),
+        'language' => array(
+          'type' => 'token',
+          'label' => t('Language'),
+          'description' => t('If specified, the language used for getting the mail message and subject.'),
+          'options list' => 'entity_metadata_language_list',
+          'optional' => TRUE,
+          'default value' => LANGUAGE_NONE,
+          'default mode' => 'selector',
+        ),
+      ),
+      'base' => 'rules_action_mail',
+      'access callback' => 'rules_system_integration_access',
+    ),
+    'mail_to_users_of_role' => array(
+      'label' => t('Send mail to all users of a role'),
+      'group' => t('System'),
+      'parameter' => array(
+        'roles' => array(
+          'type' => 'list<integer>',
+          'label' => t('Roles'),
+          'options list' => 'entity_metadata_user_roles',
+          'description' => t('Select the roles whose users should receive the mail.'),
+        ),
+        'subject' => array(
+          'type' => 'text',
+          'label' => t('Subject'),
+          'description' => t("The mail's subject."),
+        ),
+        'message' => array(
+          'type' => 'text',
+          'label' => t('Message'),
+          'description' => t("The mail's message body."),
+        ),
+        'from' => array(
+          'type' => 'text',
+          'label' => t('From'),
+          'description' => t("The mail's from address. Leave it empty to use the site-wide configured address."),
+          'optional' => TRUE,
+        ),
+      ),
+      'base' => 'rules_action_mail_to_users_of_role',
+      'access callback' => 'rules_system_integration_access',
+    ),
+  );
+}
+
+/**
+ * Help callback for the "Send mail to users of a role" action.
+ */
+function rules_action_mail_to_users_of_role_help() {
+  return t('WARNING: This may cause problems if there are too many users of these roles on your site, as your server may not be able to handle all the mail requests all at once.');
+}
+
+/**
+ * System integration access callback.
+ */
+function rules_system_integration_access($type, $name) {
+  return user_access('administer site configuration');
+}
+
+/**
+ * Options list callback defining drupal_message types.
+ */
+function rules_action_drupal_message_types() {
+  return array(
+    'status' => t('Status'),
+    'warning' => t('Warning'),
+    'error' => t('Error'),
+  );
+}
+
+/**
+ * Implements hook_rules_evaluator_info() on behalf of the system module.
+ */
+function rules_system_evaluator_info() {
+  return array(
+    'token' => array(
+      'class' => 'RulesTokenEvaluator',
+      'type' => array('text', 'uri', 'list<text>', 'list<uri>'),
+      'weight' => 0,
+     ),
+  );
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/taxonomy.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file rules integration for the taxonomy_term module
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_event_info().
+ */
+function rules_taxonomy_event_info() {
+  $defaults_term = array(
+    'group' => t('Taxonomy'),
+    'access callback' => 'rules_taxonomy_term_integration_access',
+    'module' => 'taxonomy',
+    'class' => 'RulesTaxonomyEventHandler',
+  );
+  $defaults_vocab = array(
+    'group' => t('Taxonomy'),
+    'access callback' => 'rules_taxonomy_vocabulary_integration_access',
+    'module' => 'taxonomy',
+  );
+  return array(
+    'taxonomy_term_insert' => $defaults_term + array(
+      'label' => t('After saving a new term'),
+      'variables' => array(
+        'term' => array('type' => 'taxonomy_term', 'label' => t('created term')),
+      ),
+    ),
+    'taxonomy_term_update' => $defaults_term + array(
+      'label' => t('After updating an existing term'),
+      'variables' => array(
+        'term' => array('type' => 'taxonomy_term', 'label' => t('updated term')),
+        'term_unchanged' => array('type' => 'taxonomy_term', 'label' => t('unchanged term'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+    ),
+    'taxonomy_term_presave' => $defaults_term + array(
+      'label' => t('Before saving a taxonomy term'),
+      'variables' => array(
+        'term' => array('type' => 'taxonomy_term', 'label' => t('saved term'), 'skip save' => TRUE),
+        'term_unchanged' => array('type' => 'taxonomy_term', 'label' => t('unchanged term'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+    ),
+    'taxonomy_term_delete' => $defaults_term + array(
+      'label' => t('After deleting a term'),
+      'variables' => array(
+        'term' => array('type' => 'taxonomy_term', 'label' => t('deleted term')),
+      ),
+    ),
+    'taxonomy_vocabulary_insert' => $defaults_vocab + array(
+      'label' => t('After saving a new vocabulary'),
+      'variables' => array(
+        'vocabulary' => array('type' => 'taxonomy_vocabulary', 'label' => t('created vocabulary')),
+      ),
+    ),
+    'taxonomy_vocabulary_update' => $defaults_vocab + array(
+      'label' => t('After updating an existing vocabulary'),
+      'variables' => array(
+        'vocabulary' => array('type' => 'taxonomy_vocabulary', 'label' => t('updated vocabulary')),
+        'vocabulary_unchanged' => array('type' => 'taxonomy_vocabulary', 'label' => t('unchanged vocabulary'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+    ),
+    'taxonomy_vocabulary_presave' => $defaults_vocab + array(
+      'label' => t('Before saving a vocabulary'),
+      'variables' => array(
+        'vocabulary' => array('type' => 'taxonomy_vocabulary', 'label' => t('saved vocabulary'), 'skip save' => TRUE),
+        'vocabulary_unchanged' => array('type' => 'taxonomy_vocabulary', 'label' => t('unchanged vocabulary'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+    ),
+    'taxonomy_vocabulary_delete' => $defaults_vocab + array(
+      'label' => t('After deleting a vocabulary'),
+      'variables' => array(
+        'vocabulary' => array('type' => 'taxonomy_vocabulary', 'label' => t('deleted vocabulary')),
+      ),
+    ),
+  );
+}
+
+/**
+ * Taxonomy term integration access callback.
+ */
+function rules_taxonomy_term_integration_access($type, $name) {
+  if ($type == 'event' || $type == 'condition') {
+    return entity_access('view', 'taxonomy_term');
+  }
+}
+
+/**
+ * Taxonomy vocabulary integration access callback.
+ */
+function rules_taxonomy_vocabulary_integration_access($type, $name) {
+  if ($type == 'event' || $type == 'condition') {
+    return entity_access('view', 'taxonomy_vocabulary');
+  }
+}
+
+/**
+ * Event handler support taxonomy bundle event settings.
+ */
+class RulesTaxonomyEventHandler extends RulesEventHandlerEntityBundle {
+
+  /**
+   * Returns the label to use for the bundle property.
+   *
+   * @return string
+   */
+  protected function getBundlePropertyLabel() {
+    return t('vocabulary');
+  }
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/user.eval.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Contains rules integration for the user module needed during evaluation.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Condition user: condition to check whether user has particular roles
+ */
+function rules_condition_user_has_role($account, $roles, $operation = 'AND') {
+  switch ($operation) {
+    case 'OR':
+      foreach ($roles as $rid) {
+        if (isset($account->roles[$rid])) {
+          return TRUE;
+        }
+      }
+      return FALSE;
+
+    case 'AND':
+      foreach ($roles as $rid) {
+        if (!isset($account->roles[$rid])) {
+          return FALSE;
+        }
+      }
+      return TRUE;
+  }
+}
+
+/**
+ * Condition: User is blocked.
+ */
+function rules_condition_user_is_blocked($account) {
+  return $account->status == 0;
+}
+
+/**
+ * Action: Adds roles to a particular user.
+ */
+function rules_action_user_add_role($account, $roles) {
+  if ($account->uid || !empty($account->is_new)) {
+    // Get role list (minus the anonymous)
+    $role_list = user_roles(TRUE);
+
+    foreach ($roles as $rid) {
+      $account->roles[$rid] = $role_list[$rid];
+    }
+    if (!empty($account->is_new) && $account->uid) {
+      // user_save() inserts roles after invoking hook_user_insert() anyway, so
+      // we skip saving to avoid errors due saving them twice.
+      return FALSE;
+    }
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Action: Remove roles from a given user.
+ */
+function rules_action_user_remove_role($account, $roles) {
+  if ($account->uid || !empty($account->is_new)) {
+    foreach ($roles as $rid) {
+      // If the user has this role, remove it.
+      if (isset($account->roles[$rid])) {
+        unset($account->roles[$rid]);
+      }
+    }
+    if (!empty($account->is_new) && $account->uid) {
+      // user_save() inserts roles after invoking hook_user_insert() anyway, so
+      // we skip saving to avoid errors due saving them twice.
+      return FALSE;
+    }
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Action: Block a user.
+ */
+function rules_action_user_block($account) {
+  $account->status = 0;
+  drupal_session_destroy_uid($account->uid);
+}
+
+/**
+ * Action: Unblock a user.
+ */
+function rules_action_user_unblock($account) {
+  $account->status = 1;
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/modules/user.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,236 @@
+<?php
+
+/**
+ * @file rules integration for the user module
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_file_info() on behalf of the user module.
+ */
+function rules_user_file_info() {
+  return array('modules/user.eval');
+}
+
+/**
+ * Implementation of hook_rules_event_info().
+ */
+function rules_user_event_info() {
+  return array(
+    'user_insert' => array(
+      'label' => t('After saving a new user account'),
+      'group' => t('User'),
+      'variables' => array(
+        'account' => array('type' => 'user', 'label' => t('registered user')),
+      ),
+      'access callback' => 'rules_user_integration_access',
+    ),
+    'user_update' => array(
+      'label' => t('After updating an existing user account'),
+      'group' => t('User'),
+      'variables' => array(
+        'account' => array('type' => 'user', 'label' => t('updated user')),
+        'account_unchanged' => array('type' => 'user', 'label' => t('unchanged user'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+      'access callback' => 'rules_user_integration_access',
+    ),
+    'user_presave' => array(
+      'label' => t('Before saving a user account'),
+      'group' => t('User'),
+      'variables' => array(
+        'account' => array('type' => 'user', 'label' => t('saved user'), 'skip save' => TRUE),
+        'account_unchanged' => array('type' => 'user', 'label' => t('unchanged user'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+      'access callback' => 'rules_user_integration_access',
+    ),
+    'user_view' => array(
+      'label' => t('User account page is viewed'),
+      'group' => t('User'),
+      'variables' => array(
+        'account' => array('type' => 'user', 'label' => t('viewed user')),
+        'view_mode' => array(
+          'type' => 'text',
+          'label' => t('view mode'),
+          'options list' => 'rules_get_entity_view_modes',
+        ),
+      ),
+      'access callback' => 'rules_user_integration_access',
+      'help' => t("Note that if drupal's page cache is enabled, this event won't be generated for pages served from cache."),
+    ),
+    'user_delete' => array(
+      'label' => t('After a user account has been deleted'),
+      'group' => t('User'),
+      'variables' => array(
+        'account' => array('type' => 'user', 'label' => t('deleted user')),
+      ),
+      'access callback' => 'rules_user_integration_access',
+    ),
+    'user_login' => array(
+      'label' => t('User has logged in'),
+      'group' => t('User'),
+      'variables' => array(
+        'account' => array('type' => 'user', 'label' => t('logged in user')),
+      ),
+      'access callback' => 'rules_user_integration_access',
+    ),
+    'user_logout' => array(
+      'label' => t('User has logged out'),
+      'group' => t('User'),
+      'variables' => array(
+        'account' => array('type' => 'user', 'label' => t('logged out user')),
+      ),
+      'access callback' => 'rules_user_integration_access',
+    ),
+  );
+}
+
+/**
+ * Options list for user cancel methods.
+ * @todo: Use for providing a user_cancel action.
+ */
+function rules_user_cancel_methods() {
+  module_load_include('inc', 'user', 'user.pages');
+  foreach (user_cancel_methods() as $method => $form) {
+    $methods[$method] = $form['#title'];
+  }
+  return $methods;
+}
+
+/**
+ * User integration access callback.
+ */
+function rules_user_integration_access($type, $name) {
+  if ($type == 'event' || $type == 'condition') {
+    return entity_access('view', 'user');
+  }
+  // Else return admin access.
+  return user_access('administer users');
+}
+
+/**
+ * Implements hook_rules_condition_info() on behalf of the user module.
+ */
+function rules_user_condition_info() {
+  return array(
+    'user_has_role' => array(
+      'label' => t('User has role(s)'),
+      'parameter' => array(
+        'account' => array('type' => 'user', 'label' => t('User')),
+        'roles' => array(
+          'type' => 'list<integer>',
+          'label' => t('Roles'),
+          'options list' => 'rules_user_roles_options_list',
+        ),
+        'operation' => array(
+          'type' => 'text',
+          'label' => t('Match roles'),
+          'options list' => 'rules_user_condition_operations',
+          'restriction' => 'input',
+          'optional' => TRUE,
+          'default value' => 'AND',
+          'description' => t('If matching against all selected roles, the user must have <em>all</em> the roles selected.'),
+        ),
+      ),
+      'group' => t('User'),
+      'access callback' => 'rules_user_integration_access',
+      'base' => 'rules_condition_user_has_role',
+    ),
+    'user_is_blocked' => array(
+      'label' => t('User is blocked'),
+      'parameter' => array(
+        'account' => array('type' => 'user', 'label' => t('User')),
+      ),
+      'group' => t('User'),
+      'access callback' => 'rules_user_integration_access',
+      'base' => 'rules_condition_user_is_blocked',
+    ),
+  );
+}
+
+/**
+ * User has role condition help callback.
+ */
+function rules_condition_user_has_role_help() {
+  return t('Whether the user has the selected role(s).');
+}
+
+/**
+ * Options list callback for the operation parameter of condition user has role.
+ */
+function rules_user_condition_operations() {
+  return array(
+    'AND' => t('all'),
+    'OR' => t('any'),
+  );
+}
+
+/**
+ * Implements hook_rules_action_info() on behalf of the user module.
+ */
+function rules_user_action_info() {
+  $defaults = array(
+   'parameter' => array(
+      'account' => array(
+        'type' => 'user',
+        'label' => t('User'),
+        'description' => t('The user whose roles should be changed.'),
+        'save' => TRUE,
+      ),
+      'roles' => array(
+        'type' => 'list<integer>',
+        'label' => t('Roles'),
+        'options list' => 'rules_user_roles_options_list',
+      ),
+    ),
+    'group' => t('User'),
+    'access callback' => 'rules_user_role_change_access',
+  );
+  $items['user_add_role'] = $defaults + array(
+    'label' => t('Add user role'),
+    'base' => 'rules_action_user_add_role',
+  );
+  $items['user_remove_role'] = $defaults + array(
+    'label' => t('Remove user role'),
+    'base' => 'rules_action_user_remove_role',
+  );
+  $defaults = array(
+   'parameter' => array(
+      'account' => array(
+        'type' => 'user',
+        'label' => t('User'),
+        'save' => TRUE,
+      ),
+    ),
+    'group' => t('User'),
+    'access callback' => 'rules_user_integration_access',
+  );
+  $items['user_block'] = $defaults + array(
+    'label' => t('Block a user'),
+    'base' => 'rules_action_user_block',
+  );
+  $items['user_unblock'] = $defaults + array(
+    'label' => t('Unblock a user'),
+    'base' => 'rules_action_user_unblock',
+  );
+  return $items;
+}
+
+/**
+ * User integration role actions access callback.
+ */
+function rules_user_role_change_access() {
+  return entity_metadata_user_roles() && user_access('administer permissions');
+}
+
+/**
+ * Options list callback for user roles.
+ */
+function rules_user_roles_options_list($element) {
+  return entity_metadata_user_roles('roles', array(), $element instanceof RulesConditionInterface ? 'view' : 'edit');
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1098 @@
+<?php
+
+/**
+ * @file
+ * This file contains no working PHP code; it exists to provide additional
+ * documentation for doxygen as well as to document hooks in the standard
+ * Drupal manner.
+ */
+
+
+/**
+ * @defgroup rules Rules module integrations.
+ *
+ * Module integrations with the rules module.
+ *
+ * The Rules developer documentation describes how modules can integrate with
+ * rules: http://drupal.org/node/298486.
+ */
+
+/**
+ * @defgroup rules_hooks Rules' hooks
+ * @{
+ * Hooks that can be implemented by other modules in order to extend rules.
+ */
+
+/**
+ * Define rules compatible actions.
+ *
+ * This hook is required in order to add a new rules action. It should be
+ * placed into the file MODULENAME.rules.inc, which gets automatically included
+ * when the hook is invoked.
+ *
+ * However, as an alternative to implementing this hook, class based plugin
+ * handlers may be provided by implementing RulesActionHandlerInterface. See
+ * the interface for details.
+ *
+ * @return
+ *   An array of information about the module's provided rules actions.
+ *   The array contains a sub-array for each action, with the action name as
+ *   the key. Actions names may only contain lowercase alpha-numeric characters
+ *   and underscores and should be prefixed with the providing module name.
+ *   Possible attributes for each sub-array are:
+ *   - label: The label of the action. Start capitalized. Required.
+ *   - group: A group for this element, used for grouping the actions in the
+ *     interface. Should start with a capital letter and be translated.
+ *     Required.
+ *   - parameter: (optional) An array describing all parameter of the action
+ *     with the parameter's name as key. Each parameter has to be
+ *     described by a sub-array with possible attributes as described
+ *     afterwards, whereas the name of a parameter needs to be a lowercase,
+ *     valid PHP variable name.
+ *   - provides: (optional) An array describing the variables the action
+ *     provides to the evaluation state with the variable name as key. Each
+ *     variable has to be described by a sub-array with possible attributes as
+ *     described afterwards, whereas the name of a parameter needs to be a
+ *     lowercase, valid PHP variable name.
+ *   - 'named parameter': (optional) If set to TRUE, the arguments will be
+ *     passed as a single array with the parameter names as keys. This emulates
+ *     named parameters in PHP and is in particular useful if the number of
+ *     parameters can vary. Defaults to FALSE.
+ *   - base: (optional) The base for action implementation callbacks to use
+ *     instead of the action's name. Defaults to the action name.
+ *   - callbacks: (optional) An array which allows to set specific function
+ *     callbacks for the action. The default for each callback is the actions
+ *     base appended by '_' and the callback name.
+ *   - 'access callback': (optional) A callback which has to return whether the
+ *     currently logged in user is allowed to configure this action. See
+ *     rules_node_integration_access() for an example callback.
+ *  Each 'parameter' array may contain the following properties:
+ *   - label: The label of the parameter. Start capitalized. Required.
+ *   - type: The rules data type of the parameter, which is to be passed to the
+ *     action. All types declared in hook_rules_data_info() may be specified, as
+ *     well as an array of possible types. Also lists and lists of a given type
+ *     can be specified by using the notating list<integer> as introduced by
+ *     the entity metadata module, see hook_entity_property_info(). The special
+ *     keyword '*' can be used when all types should be allowed. Required.
+ *   - bundles: (optional) An array of bundle names. When the specified type is
+ *     set to a single entity type, this may be used to restrict the allowed
+ *     bundles.
+ *   - description: (optional) If necessary, a further description of the
+ *     parameter.
+ *   - options list: (optional) A callback that returns an array of possible
+ *     values for this parameter. The callback has to return an array as used
+ *     by hook_options_list(). For an example implementation see
+ *     rules_data_action_type_options().
+ *   - save: (optional) If this is set to TRUE, the parameter will be saved by
+ *     rules when the rules evaluation ends. This is only supported for savable
+ *     data types. If the action returns FALSE, saving is skipped.
+ *   - optional: (optional) May be set to TRUE, when the parameter isn't
+ *     required.
+ *   - 'default value': (optional) The value to pass to the action, in case the
+ *     parameter is optional and there is no specified value.
+ *   - 'allow null': (optional) Usually Rules will not pass any NULL values as
+ *     argument, but abort the evaluation if a NULL value is present. If set to
+ *     TRUE, Rules will not abort and pass the NULL value through. Defaults to
+ *     FALSE.
+ *   - restriction: (optional) Restrict how the argument for this parameter may
+ *     be provided. Supported values are 'selector' and 'input'.
+ *   - default mode: (optional) Customize the default mode for providing the
+ *     argument value for a parameter. Supported values are 'selector' and
+ *     'input'. The default depends on the required data type.
+ *   - sanitize: (optional) Allows parameters of type 'text' to demand an
+ *     already sanitized argument. If enabled, any user specified value won't be
+ *     sanitized itself, but replacements applied by input evaluators are as
+ *     well as values retrieved from selected data sources.
+ *   - translatable: (optional) If set to TRUE, the provided argument value
+ *     of the parameter is translatable via i18n String translation. This is
+ *     applicable for textual parameters only, i.e. parameters of type 'text',
+ *     'token', 'list<text>' and 'list<token>'. Defaults to FALSE.
+ *   - ui class: (optional) Allows overriding the UI class, which is used to
+ *     generate the configuration UI of a parameter. Defaults to the UI class of
+ *     the specified data type.
+ *   - cleaning callback: (optional) A callback that input evaluators may use
+ *     to clean inserted replacements; e.g. this is used by the token evaluator.
+ *   - wrapped: (optional) Set this to TRUE in case the data should be passed
+ *     wrapped. This only applies to wrapped data types, e.g. entities.
+ *  Each 'provides' array may contain the following properties:
+ *   - label: The label of the variable. Start capitalized. Required.
+ *   - type: The rules data type of the variable. All types declared in
+ *     hook_rules_data_info() may be specified. Types may be parametrized e.g.
+ *     the types node<page> or list<integer> are valid.
+ *   - save: (optional) If this is set to TRUE, the provided variable is saved
+ *     by rules when the rules evaluation ends. Only possible for savable data
+ *     types. Defaults to FALSE.
+ *
+ *  The module has to provide an implementation for each action, being a
+ *  function named as specified in the 'base' key or for the execution callback.
+ *  All other possible callbacks are optional.
+ *  Supported action callbacks by rules are defined and documented in the
+ *  RulesPluginImplInterface. However any module may extend the action plugin
+ *  based upon a defined interface using hook_rules_plugin_info(). All methods
+ *  defined in those interfaces can be overridden by the action implementation.
+ *  The callback implementations for those interfaces may reside in any file
+ *  specified in hook_rules_file_info().
+ *
+ *  @see hook_rules_file_info()
+ *  @see rules_action_execution_callback()
+ *  @see hook_rules_plugin_info()
+ *  @see RulesPluginImplInterface
+ */
+function hook_rules_action_info() {
+  return array(
+    'mail_user' => array(
+      'label' => t('Send a mail to a user'),
+      'parameter' => array(
+        'user' => array('type' => 'user', 'label' => t('Recipient')),
+      ),
+      'group' => t('System'),
+      'base' => 'rules_action_mail_user',
+      'callbacks' => array(
+        'validate' => 'rules_action_custom_validation',
+        'help' => 'rules_mail_help',
+      ),
+    ),
+  );
+}
+
+/**
+ * Define categories for Rules items, e.g. actions, conditions or events.
+ *
+ * Categories are similar to the previously used 'group' key in e.g.
+ * hook_rules_action_info(), but have a machine name and some more optional
+ * keys like a weight, or an icon.
+ *
+ * For best compatibility, modules may keep using the 'group' key for referring
+ * to categories. However, if a 'group' key and a 'category' is given the group
+ * will be treated as grouping in the given category (e.g. group "paypal" in
+ * category "commerce payment").
+ *
+ * @return
+ *   An array of information about the module's provided categories.
+ *   The array contains a sub-array for each category, with the category name as
+ *   the key. Names may only contain lowercase alpha-numeric characters
+ *   and underscores and should be prefixed with the providing module name.
+ *   Possible attributes for each sub-array are:
+ *   - label: The label of the category. Start capitalized. Required.
+ *   - weight: (optional) A weight for sorting the category. Defaults to 0.
+ *   - equals group: (optional) For BC, categories may be defined that equal
+ *     a previsouly used 'group'.
+ *   - icon: (optional) The file path of an icon to use, relative to the module
+ *     or specified icon path. The icon should be a transparent SVG containing
+ *     no colors (only #fff). See https://drupal.org/node/2090265 for
+ *     instructions on how to create a suiting icon.
+ *     Note that the icon is currently not used by Rules, however other UIs
+ *     building upon Rules (like fluxkraft) do, and future releases of Rules
+ *     might do as well. Consequently, the definition of an icon is optional.
+ *     However, if both an icon font and icon is given, the icon is preferred.
+ *   - icon path: (optional) The base path for the icon. Defaults to the
+ *     providing module's directory.
+ *   - icon font class: (optional) An icon font class referring to a suiting
+ *     icon. Icon font class names should map to the ones as defined by Font
+ *     Awesome, while themes might want to choose to provide another icon font.
+ *     See http://fortawesome.github.io/Font-Awesome/cheatsheet/.
+ *   - icon background color: (optional) The color used as icon background.
+ *     Should have a high contrast to white. Defaults to #ddd.
+ */
+function hook_rules_category_info() {
+  return array(
+    'rules_data' => array(
+      'label' => t('Data'),
+      'equals group' => t('Data'),
+      'weight' => -50,
+    ),
+    'fluxtwitter' => array(
+      'label' => t('Twitter'),
+      'icon font class' => 'icon-twitter',
+      'icon font background color' => '#30a9fd',
+    ),
+  );
+}
+
+/**
+ * Specify files containing rules integration code.
+ *
+ * All files specified in that hook will be included when rules looks for
+ * existing callbacks for any plugin. Rules remembers which callback is found in
+ * which file and automatically includes the right file before it is executing
+ * a plugin method callback. The file yourmodule.rules.inc is added by default
+ * and need not be specified here.
+ * This allows you to add new include files only containing functions serving as
+ * plugin method callbacks in any file without having to care about file
+ * inclusion.
+ *
+ * @return
+ *   An array of file names without the file ending which defaults to '.inc'.
+ */
+function hook_rules_file_info() {
+  return array('yourmodule.rules-eval');
+}
+
+/**
+ * Specifies directories for class-based plugin handler discovery.
+ *
+ * Implementing this hook is not a requirement, it is just one option to load
+ * the files containing the classes during discovery - see
+ * rules_discover_plugins().
+ *
+ * @return string|array
+ *   A directory relative to the module directory, which holds the files
+ *   containing rules plugin handlers, or multiple directories keyed by the
+ *   module the directory is contained in.
+ *   All files in those directories having a 'php' or 'inc' file extension will
+ *   be loaded during discovery. Optionally, wildcards ('*') may be used to
+ *   match multiple directories.
+ *
+ * @see rules_discover_plugins()
+ */
+function hook_rules_directory() {
+  return 'lib/Drupal/fluxtwitter/Rules/*';
+}
+
+/**
+ * The execution callback for an action.
+ *
+ * It should be placed in any file included by your module or in a file
+ * specified using hook_rules_file_info().
+ *
+ * @param
+ *   The callback gets arguments passed as described as parameter in
+ *   hook_rules_action_info() as well as an array containing the action's
+ *   configuration settings.
+ * @return
+ *   The action may return an array containg parameter or provided variables
+ *   with their names as key. This is used update the value of a parameter or to
+ *   provdide the value for a provided variable.
+ *   Apart from that any parameters which have the key 'save' set to TRUE will
+ *   be remembered to be saved by rules unless the action returns FALSE.
+ *   Conditions have to return a boolean value in any case.
+ *
+ * @see hook_rules_action_info()
+ * @see hook_rules_file_info()
+ */
+function rules_action_execution_callback($node, $title, $settings) {
+  $node->title = $title;
+  return array('node' => $node);
+}
+
+/**
+ * Define rules conditions.
+ *
+ * This hook is required in order to add a new rules condition. It should be
+ * placed into the file MODULENAME.rules.inc, which gets automatically included
+ * when the hook is invoked.
+ *
+ * However, as an alternative to implementing this hook, class based plugin
+ * handlers may be provided by implementing RulesConditionHandlerInterface. See
+ * the interface for details.
+ *
+ * Adding conditions works exactly the same way as adding actions, with the
+ * exception that conditions can't provide variables and cannot save parameters.
+ * Thus the 'provides' attribute is not supported. Furthermore the condition
+ * implementation callback has to return a boolean value.
+ *
+ * @see hook_rules_action_info()
+ */
+function hook_rules_condition_info() {
+  return array(
+    'rules_condition_text_compare' => array(
+      'label' => t('Textual comparison'),
+      'parameter' => array(
+        'text1' => array('label' => t('Text 1'), 'type' => 'text'),
+        'text2' => array('label' => t('Text 2'), 'type' => 'text'),
+      ),
+      'group' => t('Rules'),
+    ),
+  );
+}
+
+/**
+ * Define rules events.
+ *
+ * This hook is required in order to add a new rules event. It should be
+ * placed into the file MODULENAME.rules.inc, which gets automatically included
+ * when the hook is invoked.
+ * The module has to invoke the event when it occurs using rules_invoke_event().
+ * This function call has to happen outside of MODULENAME.rules.inc,
+ * usually it's invoked directly from the providing module but wrapped by a
+ * module_exists('rules') check.
+ *
+ * However, as an alternative to implementing this hook, class based event
+ * handlers may be provided by implementing RulesEventHandlerInterface. See
+ * the interface for details.
+ *
+ * @return
+ *   An array of information about the module's provided rules events. The array
+ *   contains a sub-array for each event, with the event name as the key. The
+ *   name may only contain lower case alpha-numeric characters and underscores
+ *   and should be prefixed with the providing module name. Possible attributes
+ *   for each sub-array are:
+ *   - label: The label of the event. Start capitalized. Required.
+ *   - group: A group for this element, used for grouping the events in the
+ *     interface. Should start with a capital letter and be translated.
+ *     Required.
+ *   - class: (optional) An event handler class implementing the
+ *     RulesEventHandlerInterface. If none is specified the
+ *     RulesEventDefaultHandler class will be used. While the default event
+ *     handler has no settings, custom event handlers may be implemented to
+ *     to make an event configurable. See RulesEventHandlerInterface.
+ *   - access callback: (optional) An callback, which has to return whether the
+ *     currently logged in user is allowed to configure rules for this event.
+ *     Access should be only granted, if the user at least may access all the
+ *     variables provided by the event.
+ *   - help: (optional) A help text for rules reaction on this event.
+ *   - variables: (optional) An array describing all variables that are
+ *     available for elements reacting on this event. Each variable has to be
+ *     described by a sub-array with the possible attributes:
+ *     - label: The label of the variable. Start capitalized. Required.
+ *     - type: The rules data type of the variable. All types declared in
+ *       hook_rules_data_info() or supported by hook_entity_property_info() may
+ *       be specified.
+ *     - bundle: (optional) If the type is an entity type, the bundle of the
+ *       entity.
+ *     - description: (optional) A description for the variable.
+ *     - 'options list': (optional) A callback that returns an array of possible
+ *       values for this variable as specified for entity properties at
+ *       hook_entity_property_info().
+ *     - 'skip save': (optional) If the variable is saved after the event has
+ *       occurred anyway, set this to TRUE. So rules won't save the variable a
+ *       second time. Defaults to FALSE.
+ *     - handler: (optional) A handler to load the actual variable value. This
+ *       is useful for lazy loading variables. The handler gets all so far
+ *       available variables passed in the order as defined. Also see
+ *       http://drupal.org/node/884554.
+ *       Note that for lazy-loading entities just the entity id may be passed
+ *       as variable value, so a handler is not necessary in that case.
+ *
+ *  @see rules_invoke_event()
+ */
+function hook_rules_event_info() {
+  $items = array(
+    'node_insert' => array(
+      'label' => t('After saving new content'),
+      'group' => t('Node'),
+      'variables' => rules_events_node_variables(t('created content')),
+    ),
+    'node_update' => array(
+      'label' => t('After updating existing content'),
+      'group' => t('Node'),
+      'variables' => rules_events_node_variables(t('updated content'), TRUE),
+    ),
+    'node_presave' => array(
+      'label' => t('Content is going to be saved'),
+      'group' => t('Node'),
+      'variables' => rules_events_node_variables(t('saved content'), TRUE),
+    ),
+    'node_view' => array(
+      'label' => t('Content is going to be viewed'),
+      'group' => t('Node'),
+      'variables' => rules_events_node_variables(t('viewed content')) + array(
+        'view_mode' => array('type' => 'text', 'label' => t('view mode')),
+      ),
+    ),
+    'node_delete' => array(
+      'label' => t('After deleting content'),
+      'group' => t('Node'),
+      'variables' => rules_events_node_variables(t('deleted content')),
+    ),
+  );
+  // Specify that on presave the node is saved anyway.
+  $items['node_presave']['variables']['node']['skip save'] = TRUE;
+  return $items;
+}
+
+/**
+ * Define rules data types.
+ *
+ * This hook is required in order to add a new rules data type. It should be
+ * placed into the file MODULENAME.rules.inc, which gets automatically included
+ * when the hook is invoked.
+ * Rules builds upon the entity metadata module, thus to improve the support of
+ * your data in rules, make it an entity if possible and provide metadata about
+ * its properties and CRUD functions by integrating with the entity metadata
+ * module.
+ * For a list of data types defined by rules see rules_rules_core_data_info().
+ *
+ *
+ * @return
+ *   An array of information about the module's provided data types. The array
+ *   contains a sub-array for each data type, with the data type name as the
+ *   key. The name may only contain lower case alpha-numeric characters and
+ *   underscores and should be prefixed with the providing module name. Possible
+ *   attributes for each sub-array are:
+ *   - label: The label of the data type. Start uncapitalized. Required.
+ *   - parent: (optional) A parent type may be set to specify a sub-type
+ *     relationship, which will be only used for checking compatible types. E.g.
+ *     the 'entity' data type is parent of the 'node' data type, thus a node may
+ *     be also used for any action needing an 'entity' parameter. Can be set to
+ *     any known rules data type.
+ *   - ui class: (optional) Specify a class that is used to generate the
+ *     configuration UI to configure parameters of this type. The given class
+ *     must extend RulesDataUI and may implement the
+ *     RulesDataDirectInputFormInterface in order to allow the direct data input
+ *     configuration mode. For supporting selecting values from options lists,
+ *     the UI class may implement RulesDataInputOptionsListInterface also.
+ *     Defaults to RulesDataUI.
+ *   - wrap: (optional) If set to TRUE, the data is wrapped internally using
+ *     wrappers provided by the entity API module. This is required for entities
+ *     and data structures to support selecting a property via the data selector
+ *     and for intelligent saving.
+ *   - is wrapped: (optional) In case the data wrapper is already wrapped when
+ *     passed to Rules and Rules should not unwrap it when passing the data as
+ *     argument, e.g. to an action, set this to TRUE. The default FALSE is fine
+ *     in most cases.
+ *   - wrapper class: (optional) Allows the specification of a custom wrapper
+ *     class, which has to inherit from 'EntityMetadataWrapper'. If given Rules
+ *     makes use of the class for wrapping the data of the given type. However
+ *     note that if data is already wrapped when it is passed to Rules, the
+ *     existing wrappers will be kept.
+ *     For modules implementing identifiable data types being non-entites the
+ *     class RulesIdentifiableDataWrapper is provided, which can be used as base
+ *     for a custom wrapper class. See RulesIdentifiableDataWrapper for details.
+ *   - property info: (optional) May be used for non-entity data structures to
+ *     provide info about the data properties, such that data selectors via an
+ *     entity metadata wrapper are supported. Specify an array as expected by
+ *     the $info parameter of entity_metadata_wrapper().
+ *   - creation callback: (optional) If 'property info' is given, an optional
+ *     callback that makes use of the property info to create a new instance of
+ *     this data type. Entities should use hook_entity_info() to specify the
+ *     'creation callback' instead, as utilized by the entity API module. See
+ *     rules_action_data_create_array() for an example callback.
+ *   - property defaults: (optional) May be used for non-entity data structures
+ *     to to provide property info defaults for the data properties. Specify an
+ *     array as expected by entity_metadata_wrapper().
+ *   - group: (optional) A group for this element, used for grouping the data
+ *     types in the interface. Should start with a capital letter and be
+ *     translated.
+ *   - token type: (optional) The type name as used by the token module.
+ *     Defaults to the type name as used by rules. Use FALSE to let token ignore
+ *     this type.
+ *   - cleaning callback: (optional) A callback that input evaluators may use
+ *     to clean inserted replacements; e.g. this is used by the token evaluator.
+ *
+ *  @see entity_metadata_wrapper()
+ *  @see hook_rules_data_info_alter()
+ *  @see rules_rules_core_data_info()
+ */
+function hook_rules_data_info() {
+  return array(
+    'node' => array(
+      'label' => t('content'),
+      'parent' => 'entity',
+      'group' => t('Node'),
+    ),
+    // Formatted text as used by in hook_entity_property_info() for text fields.
+    'text_formatted' => array(
+      'label' => t('formatted text'),
+      'ui class' => 'RulesDataUITextFormatted',
+      'wrap' => TRUE,
+      'property info' => entity_property_text_formatted_info(),
+    ),
+  );
+}
+
+/**
+ * Defines rules plugins.
+ *
+ * A rules configuration may consist of elements being instances of any rules
+ * plugin. This hook can be used to define new or to extend rules plugins.
+ *
+ * @return
+ *   An array of information about the module's provided rules plugins. The
+ *   array contains a sub-array for each plugin, with the plugin name as the
+ *   key. The name may only contain lower case alpha-numeric characters,
+ *   underscores and spaces and should be prefixed with the providing module
+ *   name. Possible attributes for
+ *   each sub-array are:
+ *   - label: A label for the plugin. Start capitalized. Required only for
+ *     components (see below).
+ *   - class: The implementation class. Has to extend the RulesPlugin class.
+ *   - embeddable: A container class in which elements of those plugin may be
+ *     embedded via the UI or FALSE to disallow embedding it via the UI. This
+ *     has no implications on the API level though. Common classes that are
+ *     used here are RulesConditionContainer and RulesActionContainer.
+ *   - component: If set to TRUE, the rules admin UI will list elements of those
+ *     plugin in the components UI and allows the creation of new components
+ *     based upon this plugin. Optional.
+ *   - extenders: This allows one to specify faces extenders, which may be used
+ *     to dynamically implement interfaces. Optional. All extenders specified
+ *     here are setup automatically by rules once the object is created. To
+ *     specify set this to an array, where the keys are the implemented
+ *     interfaces pointing to another array with the keys:
+ *     - class: The class of the extender, implementing the FacesExtender
+ *       and the specified interface. Either 'class' or 'methods' has to exist.
+ *     - methods: An array of callbacks that implement the methods of the
+ *       interface where the method names are the keys and the callback names
+ *       the values. There has to be a callback for each defined method.
+ *     - file: An optional array describing the file to include when a method
+ *       of the interface is invoked. The array entries known are 'type',
+ *       'module', and 'name' matching the parameters of module_load_include().
+ *       Only 'module' is required as 'type' defaults to 'inc' and 'name' to
+ *       NULL.
+ *   - overrides: An optional array, which may be used to specify callbacks to
+ *     override specific methods. For that the following keys are supported:
+ *     - methods: As in the extenders array, but you may specify as many methods
+ *       here as you like.
+ *     - file: Optionally an array specifying a file to include for a method.
+ *       For each method appearing in methods a file may be specified by using
+ *       the method name as key and another array as value, which describes the
+ *       file to include - looking like the file array supported by 'extenders'.
+ *   - import keys: (optional) Embeddable plugins may specify an array of import
+ *     keys, which the plugin make use for exporting. Defaults to the upper
+ *     case plugin name, thus the key 'OR' in an export triggers the creation
+ *     of the 'or' plugin. Note that only uppercase values are allowed, as
+ *     lower case values are treated as action or condition exports.
+ *
+ *  @see class RulesPlugin
+ *  @see hook_rules_plugin_info_alter()
+ */
+function hook_rules_plugin_info() {
+  return array(
+    'or' => array(
+      'label' => t('Condition set (OR)'),
+      'class' => 'RulesOr',
+      'embeddable' => 'RulesConditionContainer',
+      'component' => TRUE,
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesConditionContainerUI',
+        ),
+      ),
+    ),
+    'rule' => array(
+      'class' => 'Rule',
+      'embeddable' => 'RulesRuleSet',
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesRuleUI',
+        ),
+      ),
+      'import keys' => array('DO', 'IF'),
+    ),
+  );
+}
+
+/**
+ * Declare provided rules input evaluators.
+ *
+ * The hook implementation should be placed into the file MODULENAME.rules.inc,
+ * which gets automatically included when the hook is invoked.
+ * For implementing an input evaluator a class has to be provided which
+ * extends the abstract RulesDataInputEvaluator class. Therefore the abstract
+ * methods prepare() and evaluate() have to be implemented, as well as access()
+ * and help() could be overridden in order to control access permissions or to
+ * provide some usage help.
+ *
+ * @return
+ *   An array of information about the module's provided input evaluators. The
+ *   array contains a sub-array for each evaluator, with the evaluator name as
+ *   the key. The name may only contain lower case alpha-numeric characters and
+ *   underscores and should be prefixed with the providing module name. Possible
+ *   attributes for each sub-array are:
+ *   - class: The implementation class, which has to extend the
+ *     RulesDataInputEvaluator class. Required.
+ *   - weight: A weight for controlling the evaluation order of multiple
+ *     evaluators. Required.
+ *   - type: Optionally, the data types for which the input evaluator should be
+ *     used. Defaults to 'text'. Multiple data types may be specified using an
+ *     array.
+ *
+ *  @see class RulesDataInputEvaluator
+ *  @see hook_rules_evaluator_info_alter()
+ */
+function hook_rules_evaluator_info() {
+  return array(
+    'token' => array(
+      'class' => 'RulesTokenEvaluator',
+      'type' => array('text', 'uri'),
+      'weight' => 0,
+     ),
+  );
+}
+
+/**
+ * Declare provided rules data processors.
+ *
+ * The hook implementation should be placed into the file MODULENAME.rules.inc,
+ * which gets automatically included when the hook is invoked.
+ * For implementing a data processors a class has to be provided which
+ * extends the abstract RulesDataProcessor class. Therefore the abstract
+ * method process() has to be implemented, but also the methods form() and
+ * access() could be overridden in order to provide a configuration form or
+ * to control access permissions.
+ *
+ * @return
+ *   An array of information about the module's provided data processors. The
+ *   array contains a sub-array for each processor, with the processor name as
+ *   the key. The name may only contain lower case alpha-numeric characters and
+ *   underscores and should be prefixed with the providing module name, whereas
+ *   'select' is reserved as well.
+ *   Possible attributes for each sub-array are:
+ *   - class: The implementation class, which has to extend the
+ *     RulesDataProcessor class. Required.
+ *   - weight: A weight for controlling the processing order of multiple data
+ *     processors. Required.
+ *   - type: Optionally, the data types for which the data processor should be
+ *     used. Defaults to 'text'. Multiple data types may be specified using an
+ *     array.
+ *
+ *  @see class RulesDataProcessor
+ *  @see hook_rules_data_processor_info_alter()
+ */
+function hook_rules_data_processor_info() {
+  return array(
+    'date_offset' => array(
+      'class' => 'RulesDateOffsetProcessor',
+      'type' => 'date',
+      'weight' => -2,
+     ),
+  );
+}
+
+/**
+ * Alter rules compatible actions.
+ *
+ * The implementation should be placed into the file MODULENAME.rules.inc, which
+ * gets automatically included when the hook is invoked.
+ *
+ * @param $actions
+ *   The items of all modules as returned from hook_rules_action_info().
+ *
+ * @see hook_rules_action_info().
+ */
+function hook_rules_action_info_alter(&$actions) {
+  // The rules action is more powerful, so hide the core action
+  unset($actions['rules_core_node_assign_owner_action']);
+  // We prefer handling saving by rules - not by the user.
+  unset($actions['rules_core_node_save_action']);
+}
+
+/**
+ * Alter rules conditions.
+ *
+ * The implementation should be placed into the file MODULENAME.rules.inc, which
+ * gets automatically included when the hook is invoked.
+ *
+ * @param $conditions
+ *   The items of all modules as returned from hook_rules_condition_info().
+ *
+ * @see hook_rules_condition_info()
+ */
+function hook_rules_condition_info_alter(&$conditions) {
+  // Change conditions.
+}
+
+/**
+ * Alter rules events.
+ *
+ * The implementation should be placed into the file MODULENAME.rules.inc, which
+ * gets automatically included when the hook is invoked.
+ *
+ * @param $events
+ *   The items of all modules as returned from hook_rules_event_info().
+ *
+ * @see hook_rules_event_info().
+ */
+function hook_rules_event_info_alter(&$events) {
+  // Change events.
+}
+
+/**
+ * Alter rules data types.
+ *
+ * The implementation should be placed into the file MODULENAME.rules.inc, which
+ * gets automatically included when the hook is invoked.
+ *
+ * @param $data_info
+ *   The items of all modules as returned from hook_rules_data_info().
+ *
+ * @see hook_rules_data_info()
+ */
+function hook_rules_data_info_alter(&$data_info) {
+  // Change data types.
+}
+
+/**
+ * Alter rules plugin info.
+ *
+ * The implementation should be placed into the file MODULENAME.rules.inc, which
+ * gets automatically included when the hook is invoked.
+ *
+ * @param $plugin_info
+ *   The items of all modules as returned from hook_rules_plugin_info().
+ *
+ * @see hook_rules_plugin_info()
+ */
+function hook_rules_plugin_info_alter(&$plugin_info) {
+  // Change plugin info.
+}
+
+/**
+ * Alter rules input evaluator info.
+ *
+ * The implementation should be placed into the file MODULENAME.rules.inc, which
+ * gets automatically included when the hook is invoked.
+ *
+ * @param $evaluator_info
+ *   The items of all modules as returned from hook_rules_evaluator_info().
+ *
+ * @see hook_rules_evaluator_info()
+ */
+function hook_rules_evaluator_info_alter(&$evaluator_info) {
+  // Change evaluator info.
+}
+
+/**
+ * Alter rules data_processor info.
+ *
+ * The implementation should be placed into the file MODULENAME.rules.inc, which
+ * gets automatically included when the hook is invoked.
+ *
+ * @param $processor_info
+ *   The items of all modules as returned from hook_rules_data_processor_info().
+ *
+ * @see hook_rules_data_processor_info()
+ */
+function hook_rules_data_processor_info_alter(&$processor_info) {
+  // Change processor info.
+}
+
+/**
+ * Act on rules configuration being loaded from the database.
+ *
+ * This hook is invoked during rules configuration loading, which is handled
+ * by entity_load(), via classes RulesEntityController and EntityCRUDController.
+ *
+ * @param $configs
+ *   An array of rules configurations being loaded, keyed by id.
+ */
+function hook_rules_config_load($configs) {
+  $result = db_query('SELECT id, foo FROM {mytable} WHERE id IN(:ids)', array(':ids' => array_keys($configs)));
+  foreach ($result as $record) {
+    $configs[$record->id]->foo = $record->foo;
+  }
+}
+
+/**
+ * Respond to creation of a new rules configuration.
+ *
+ * This hook is invoked after the rules configuration is inserted into the
+ * the database.
+ *
+ * @param RulesPlugin $config
+ *   The rules configuration that is being created.
+ */
+function hook_rules_config_insert($config) {
+  db_insert('mytable')
+    ->fields(array(
+      'nid' => $config->id,
+      'plugin' => $config->plugin,
+    ))
+    ->execute();
+}
+
+/**
+ * Act on a rules configuration being inserted or updated.
+ *
+ * This hook is invoked before the rules configuration is saved to the
+ * database.
+ *
+ * @param RulesPlugin $config
+ *   The rules configuration that is being inserted or updated.
+ */
+function hook_rules_config_presave($config) {
+  if ($config->id && $config->owner == 'your_module') {
+    // Add custom condition.
+    $config->conditon(/* Your condition */);
+  }
+}
+
+/**
+ * Respond to updates to a rules configuration.
+ *
+ * This hook is invoked after the configuration has been updated in the
+ * database.
+ *
+ * @param RulesPlugin $config
+ *   The rules configuration that is being updated.
+ */
+function hook_rules_config_update($config) {
+  db_update('mytable')
+    ->fields(array('plugin' => $config->plugin))
+    ->condition('id', $config->id)
+    ->execute();
+}
+
+/**
+ * Respond to rules configuration deletion.
+ *
+ * This hook is invoked after the configuration has been removed from the
+ * database.
+ *
+ * @param RulesPlugin $config
+ *   The rules configuration that is being deleted.
+ */
+function hook_rules_config_delete($config) {
+  db_delete('mytable')
+    ->condition('id', $config->id)
+    ->execute();
+}
+
+/**
+ * Respond to rules configuration execution.
+ *
+ * This hook is invoked right before the rules configuration is executed.
+ *
+ * @param RulesPlugin $config
+ *   The rules configuration that is being executed.
+ */
+function hook_rules_config_execute($config) {
+
+}
+
+/**
+ * Define default rules configurations.
+ *
+ * This hook is invoked when rules configurations are loaded. The implementation
+ * should be placed into the file MODULENAME.rules_defaults.inc, which gets
+ * automatically included when the hook is invoked.
+ *
+ * @return
+ *   An array of rules configurations with the configuration names as keys.
+ *
+ * @see hook_default_rules_configuration_alter()
+ * @see hook_rules_config_defaults_rebuild()
+ */
+function hook_default_rules_configuration() {
+  $rule = rules_reaction_rule();
+  $rule->label = 'example default rule';
+  $rule->active = FALSE;
+  $rule->event('node_update')
+       ->condition(rules_condition('data_is', array('data:select' => 'node:status', 'value' => TRUE))->negate())
+       ->condition('data_is', array('data:select' => 'node:type', 'value' => 'page'))
+       ->action('drupal_message', array('message' => 'A node has been updated.'));
+
+  $configs['rules_test_default_1'] = $rule;
+  return $configs;
+}
+
+/**
+ * Alter default rules configurations.
+ *
+ * The implementation should be placed into the file
+ * MODULENAME.rules_defaults.inc, which gets automatically included when the
+ * hook is invoked.
+ *
+ * @param $configs
+ *   The default configurations of all modules as returned from
+ *   hook_default_rules_configuration().
+ *
+ * @see hook_default_rules_configuration()
+ */
+function hook_default_rules_configuration_alter(&$configs) {
+  // Add custom condition.
+  $configs['foo']->condition('bar');
+}
+
+/**
+ * Act after rebuilding default configurations.
+ *
+ * This hook is invoked by the entity module after default rules configurations
+ * have been rebuilt; i.e. defaults have been saved to the database.
+ *
+ * @param $rules_configs
+ *   The array of default rules configurations which have been inserted or
+ *   updated, keyed by name.
+ * @param $originals
+ *   An array of original rules configurations keyed by name; i.e. the rules
+ *   configurations before the current defaults have been applied. For inserted
+ *   rules configurations no original is available.
+ *
+ * @see hook_default_rules_configuration()
+ * @see entity_defaults_rebuild()
+ */
+function hook_rules_config_defaults_rebuild($rules_configs, $originals) {
+  // Once all defaults have been rebuilt, update all i18n strings at once. That
+  // way we build the rules cache once the rebuild is complete and avoid
+  // rebuilding caches for each updated rule.
+  foreach ($rules_configs as $name => $rule_config) {
+    if (empty($originals[$name])) {
+      rules_i18n_rules_config_insert($rule_config);
+    }
+    else {
+      rules_i18n_rules_config_update($rule_config, $originals[$name]);
+    }
+  }
+}
+
+/**
+ * Alter rules components before execution.
+ *
+ * This hooks allows altering rules components before they are cached for later
+ * re-use. Use this hook only for altering the component in order to prepare
+ * re-use through rules_invoke_component() or the provided condition/action.
+ * Note that this hook is only invoked for any components cached for execution,
+ * but not for components that are programmatically created and executed on the
+ * fly (without saving them).
+ *
+ * @param $plugin
+ *   The name of the component plugin.
+ * @param $component
+ *   The component that is to be cached.
+ *
+ * @see rules_invoke_component()
+ */
+function hook_rules_component_alter($plugin, RulesPlugin $component) {
+
+}
+
+/**
+ * Alters event sets.
+ *
+ * This hooks allows altering rules event sets, which contain all rules that are
+ * triggered upon a specific event. Rules internally caches all rules associated
+ * to an event in an event set, which is cached for fast evaluation. This hook
+ * is invoked just before any event set is cached, thus it allows altering of
+ * the to be executed rules without the changes to appear in the UI, e.g. to add
+ * a further condition to some rules.
+ *
+ * @param $event_name
+ *   The name of the event.
+ * @param $event_set
+ *   The event set that is to be cached.
+ *
+ * @see rules_invoke_event()
+ */
+function hook_rules_event_set_alter($event_name, RulesEventSet $event_set) {
+
+}
+
+/**
+ * D6 to D7 upgrade procedure hook for mapping action or condition names.
+ *
+ * If for a module the action or condition name changed since Drupal 6, this
+ * "hook" can be implemented in order to map to the new name of the action or
+ * condition.
+ *
+ * This is no real hook, but a callback that is invoked for each Drupal 6
+ * action or condition that is to be upgraded to Drupal 7. E.g. the function
+ * name called for the action "rules_action_set_node_title" would be
+ * "rules_action_set_node_title_upgrade_map_name".
+ *
+ * @param $element
+ *   The element array of a configured condition or action which is to be
+ *   upgraded.
+ * @return
+ *   The name of the action or condition which should be used.
+ */
+function hook_rules_action_base_upgrade_map_name($element) {
+  return 'data_set';
+}
+
+/**
+ * D6 to D7 upgrade procedure hook for mapping action or condition configuration.
+ *
+ * During upgrading Drupal 6 rule configurations to Drupal 7 Rules is taking
+ * care of upgrading the configuration of all known parameters, which only works
+ * if the parameter name has not changed.
+ * If something changed, this callback can be used to properly apply the
+ * configruation of the Drupal 6 action ($element) to the Drupal 7 version
+ * ($target).
+ *
+ * This is no real hook, but a callback that is invoked for each Drupal 6
+ * action or condition that is to be upgraded to Drupal 7. E.g. the function
+ * name called for the action "rules_action_set_node_title" would be
+ * "rules_action_set_node_title_upgrade".
+ *
+ * @param $element
+ *   The element array of a configured condition or action which is to be
+ *   upgraded.
+ * @param $target
+ *   The Drupal 7 version of the configured element.
+ *
+ * @see hook_rules_element_upgrade_alter()
+ */
+function hook_rules_action_base_upgrade($element, RulesPlugin $target) {
+  $target->settings['data:select'] = $element['#settings']['#argument map']['node'] . ':title';
+  $target->settings['value'] = $element['#settings']['title'];
+}
+
+/**
+ * D6 to D7 upgrade procedure hook for mapping action or condition configuration.
+ *
+ * A alter hook that is called after the action/condition specific callback for
+ * each element of a configuration that is upgraded.
+ *
+ * @param $element
+ *   The element array of a configured condition or action which is to be
+ *   upgraded.
+ * @param $target
+ *   The Drupal 7 version of the configured element.
+ *
+ * @see hook_rules_action_base_upgrade()
+ */
+function hook_rules_element_upgrade_alter($element, $target) {
+
+}
+
+/**
+ * Allows modules to alter or to extend the provided Rules UI.
+ *
+ * Use this hook over the regular hook_menu_alter() as the Rules UI is re-used
+ * and embedded by modules. See rules_ui().
+ *
+ * @param $items
+ *   The menu items to alter.
+ * @param $base_path
+ *   The base path of the Rules UI.
+ * @param $base_count
+ *   The count of the directories contained in the base path.
+ */
+function hook_rules_ui_menu_alter(&$items, $base_path, $base_count) {
+  $items[$base_path . '/manage/%rules_config/schedule'] = array(
+    'title callback' => 'rules_get_title',
+    'title arguments' => array('Schedule !plugin "!label"', $base_count + 1),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_scheduler_schedule_form', $base_count + 1, $base_path),
+    'access callback' => 'rules_config_access',
+    'access arguments' => array('update', $base_count + 1),
+    'file' => 'rules_scheduler.admin.inc',
+    'file path' => drupal_get_path('module', 'rules_scheduler'),
+  );
+}
+
+/**
+ * Control access to Rules configurations.
+ *
+ * Modules may implement this hook if they want to have a say in whether or not
+ * a given user has access to perform a given operation on a Rules
+ * configuration.
+ *
+ * @param $op
+ *   The operation being performed. One of 'view', 'create', 'update' or
+ *   'delete'.
+ * @param $rules_config
+ *   (optional) A Rules configuration to check access for. If nothing is given,
+ *   access for all Rules configurations is determined.
+ * @param $account
+ *   (optional) The user to check for. If no account is passed, access is
+ *   determined for the current user.
+ * @return boolean
+ *   Return TRUE to grant access, FALSE to explicitly deny access. Return NULL
+ *   or nothing to not affect the operation.
+ *   Access is granted as soon as a module grants access and no one denies
+ *   access. Thus if no module explicitly grants access, access will be denied.
+ *
+ * @see rules_config_access()
+ */
+function hook_rules_config_access($op, $rules_config = NULL, $account = NULL) {
+  // Instead of returning FALSE return nothing, so others still can grant
+  // access.
+  if (isset($rules_config) && $rules_config->owner == 'mymodule' && user_access('my modules permission')) {
+    return TRUE;
+  }
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Provides Features integration for the Rules module, based upon the features
+ * integration provided by the Entity API.
+ */
+
+
+/**
+ * Controller handling the features integration.
+ */
+class RulesFeaturesController extends EntityDefaultFeaturesController {
+
+  /**
+   * Defines the result for hook_features_api().
+   */
+  public function api() {
+    $info = parent::api();
+    $info['rules_config']['default_file'] = FEATURES_DEFAULTS_CUSTOM;
+    $info['rules_config']['default_filename'] = 'rules_defaults';
+    return $info;
+  }
+
+  /**
+   * Generates the result for hook_features_export().
+   * Overridden to add in rules specific stuff.
+   */
+  public function export($data, &$export, $module_name = '') {
+    $pipe = parent::export($data, $export, $module_name);
+    foreach (entity_load_multiple_by_name($this->type, $data) as $name => $rules_config) {
+      // Add in the dependencies.
+      $export['dependencies'] += drupal_map_assoc($rules_config->dependencies());
+      // Add in plugin / element specific additions.
+      $iterator = new RecursiveIteratorIterator($rules_config, RecursiveIteratorIterator::SELF_FIRST);
+      foreach ($iterator as $element) {
+        if ($element->facesAs('RulesPluginFeaturesIntegrationInterace')) {
+          // Directly use __call() so we cann pass $export by reference.
+          $element->__call('features_export', array(&$export, &$pipe, $module_name));
+        }
+      }
+    }
+    return $pipe;
+  }
+}
+
+/**
+ * Default extension callback used as default for the abstract plugin class.
+ * Actions / conditions may override this with their own implementation, which
+ * actually does something.
+ *
+ * @see RulesPluginFeaturesIntegrationInterace
+ */
+function rules_features_abstract_default_features_export(&$export, &$pipe, $module_name = '', $element) {
+
+}
+
+/**
+ * Interface that allows rules plugins or actions/conditions to customize the
+ * features export by implementing the interface using the faces extensions
+ * mechanism.
+ *
+ * @see hook_rules_plugin_info()
+ * @see hook_rules_action_info()
+ */
+interface RulesPluginFeaturesIntegrationInterace {
+
+  /**
+   * Allows customizing the features export for a given rule element.
+   */
+  function features_export(&$export, &$pipe, $module_name = '');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,30 @@
+name = Rules
+description = React on events and conditionally evaluate actions.
+package = Rules
+core = 7.x
+files[] = rules.features.inc
+files[] = tests/rules.test
+files[] = includes/faces.inc
+files[] = includes/rules.core.inc
+files[] = includes/rules.event.inc
+files[] = includes/rules.processor.inc
+files[] = includes/rules.plugins.inc
+files[] = includes/rules.state.inc
+files[] = includes/rules.dispatcher.inc
+files[] = modules/node.eval.inc
+files[] = modules/php.eval.inc
+files[] = modules/rules_core.eval.inc
+files[] = modules/system.eval.inc
+files[] = ui/ui.controller.inc
+files[] = ui/ui.core.inc
+files[] = ui/ui.data.inc
+files[] = ui/ui.plugins.inc
+dependencies[] = entity_token
+dependencies[] = entity
+
+; Information added by drupal.org packaging script on 2013-09-16
+version = "7.x-2.4"
+core = "7.x"
+project = "rules"
+datestamp = "1379354606"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,470 @@
+<?php
+
+/**
+ * @file Rules - Installation file.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function rules_install() {
+  module_load_include('inc', 'rules', 'modules/events');
+  // Set the modules' weight to 20, see
+  // http://drupal.org/node/445084#comment-1533280 for the reasoning.
+  db_query("UPDATE {system} SET weight = 20 WHERE name = 'rules'");
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function rules_uninstall() {
+  variable_del('rules_event_whitelist');
+  variable_del('rules_debug');
+}
+
+/**
+ * Implements hook_schema().
+ */
+function rules_schema() {
+  $schema['rules_config'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'The internal identifier for any configuration.',
+      ),
+      'name' => array(
+        'type' => 'varchar',
+        'length' => '64',
+        'not null' => TRUE,
+        'description' => 'The name of the configuration.',
+      ),
+      'label' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'description' => 'The label of the configuration.',
+        'default' => 'unlabeled',
+      ),
+     'plugin' => array(
+        'type' => 'varchar',
+        'length' => 127,
+        'not null' => TRUE,
+        'description' => 'The name of the plugin of this configuration.',
+      ),
+      'active' => array(
+        'description' => 'Boolean indicating whether the configuration is active. Usage depends on how the using module makes use of it.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'Weight of the configuration. Usage depends on how the using module makes use of it.',
+      ),
+      'status' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        // Set the default to ENTITY_CUSTOM without using the constant as it is
+        // not safe to use it at this point.
+        'default' => 0x01,
+        'size' => 'tiny',
+        'description' => 'The exportable status of the entity.',
+      ),
+      'dirty' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'Dirty configurations fail the integrity check, e.g. due to missing dependencies.',
+      ),
+      'module' => array(
+        'description' => 'The name of the providing module if the entity has been defined in code.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+      ),
+      'owner' => array(
+        'description' => 'The name of the module via which the rule has been configured.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => 'rules',
+      ),
+      'access_exposed' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'Whether to use a permission to control access for using components.',
+      ),
+      'data' => array(
+        'type' => 'blob',
+        'size' => 'big',
+        'not null' => FALSE,
+        'serialize' => TRUE,
+        'description' => 'Everything else, serialized.',
+      ),
+    ),
+    'primary key' => array('id'),
+    'unique keys' => array(
+      'name' => array('name'),
+    ),
+    'indexes' => array(
+      'plugin' => array('plugin'),
+    ),
+  );
+  $schema['rules_trigger'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The primary identifier of the configuration.',
+      ),
+      'event' => array(
+        'type' => 'varchar',
+        'length' => '127',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The name of the event on which the configuration should be triggered.',
+      ),
+    ),
+    'primary key' => array('id', 'event'),
+    'foreign keys' => array(
+      'table' => 'rules_config',
+      'columns' => array('id' => 'id'),
+    ),
+  );
+  $schema['rules_tags'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The primary identifier of the configuration.',
+      ),
+      'tag' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'description' => 'The tag string associated with this configuration',
+      ),
+    ),
+    'primary key' => array('id', 'tag'),
+    'foreign keys' => array(
+      'table' => 'rules_config',
+      'columns' => array('id' => 'id'),
+    ),
+  );
+  $schema['rules_dependencies'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The primary identifier of the configuration.',
+      ),
+      'module' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'description' => 'The name of the module that is required for the configuration.',
+      ),
+    ),
+    'primary key' => array('id', 'module'),
+    'indexes' => array(
+      'module' => array('module'),
+    ),
+    'foreign keys' => array(
+      'table' => 'rules_config',
+      'columns' => array('id' => 'id'),
+    ),
+  );
+  $schema['cache_rules'] = drupal_get_schema_unprocessed('system', 'cache');
+  $schema['cache_rules']['description'] = 'Cache table for the rules engine to store configured items.';
+  return $schema;
+}
+
+/**
+ * Upgrade from Rules 6.x-1.x to 7.x.
+ */
+function rules_update_7200() {
+  // Create the new db tables first.
+  $schema['rules_config'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'The internal identifier for any configuration.',
+      ),
+      'name' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'description' => 'The name of the configuration.',
+      ),
+      'label' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'description' => 'The label of the configuration.',
+        'default' => 'unlabeled',
+      ),
+     'plugin' => array(
+        'type' => 'varchar',
+        'length' => 127,
+        'not null' => TRUE,
+        'description' => 'The name of the plugin of this configuration.',
+      ),
+      'active' => array(
+        'description' => 'Boolean indicating whether the configuration is active. Usage depends on how the using module makes use of it.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'Weight of the configuration. Usage depends on how the using module makes use of it.',
+      ),
+      'status' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        // Set the default to ENTITY_CUSTOM without using the constant as it is
+        // not safe to use it at this point.
+        'default' => 0x01,
+        'size' => 'tiny',
+        'description' => 'The exportable status of the entity.',
+      ),
+      'module' => array(
+        'description' => 'The name of the providing module if the entity has been defined in code.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+      ),
+      'data' => array(
+        'type' => 'blob',
+        'size' => 'big',
+        'not null' => FALSE,
+        'serialize' => TRUE,
+        'description' => 'Everything else, serialized.',
+      ),
+    ),
+    'primary key' => array('id'),
+    'unique keys' => array(
+      'name' => array('name'),
+    ),
+  );
+  $schema['rules_trigger'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'The primary identifier of the configuration.',
+      ),
+      'event' => array(
+        'type' => 'varchar',
+        'length' => '127',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The name of the event on which the configuration should be triggered.',
+      ),
+    ),
+    'primary key' => array('id', 'event'),
+    'foreign keys' => array(
+      'table' => 'rules_config',
+      'columns' => array('id' => 'id'),
+    ),
+  );
+  db_create_table('rules_config', $schema['rules_config']);
+  db_create_table('rules_trigger', $schema['rules_trigger']);
+  // The cache table already exists, but changed. So re-create it.
+  db_drop_table('cache_rules');
+  $schema['cache_rules'] = drupal_get_schema_unprocessed('system', 'cache');
+  $schema['cache_rules']['description'] = 'Cache table for the rules engine to store configured items.';
+  db_create_table('cache_rules', $schema['cache_rules']);
+  // Remove deprecated variables.
+  variable_del('rules_inactive_sets');
+  variable_del('rules_show_fixed');
+  variable_del('rules_hide_token_message');
+  variable_del('rules_counter');
+
+  return t('The database tables for Rules 2.x have been created. The old tables from Rules 1.x are still available and contain your rules, which are not updated yet.');
+}
+
+/**
+ * Add in the exportable entity db columns as required by the entity API.
+ */
+function rules_update_7201() {
+  // Previously this was update 7200, so check whether we need to run it really.
+  // The update has been moved as 7200 needs to be the 6.x-7.x upgrade.
+  if (!db_field_exists('rules_config', 'status')) {
+    db_add_field('rules_config', 'status', array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'default' => ENTITY_CUSTOM,
+      'size' => 'tiny',
+      'description' => 'The exportable status of the entity.',
+    ));
+    // The module column did already exist before.
+  }
+}
+
+/**
+ * Add an index for the rules configuration plugin column.
+ */
+function rules_update_7202() {
+  db_add_index('rules_config', 'plugin', array('plugin'));
+}
+
+/**
+ * Fix the length of the rules_config.name column.
+ */
+function rules_update_7203() {
+  db_drop_unique_key('rules_config', 'name');
+  $keys = array(
+    'unique keys' => array(
+      'name' => array('name'),
+    ),
+  );
+  db_change_field('rules_config', 'name', 'name', array(
+    'type' => 'varchar',
+    'length' => '64',
+    'not null' => TRUE,
+    'description' => 'The name of the configuration.',
+  ), $keys);
+}
+
+/**
+ * Add a table for rules-config tags.
+ */
+function rules_update_7204() {
+  if (!db_table_exists('rules_tags')) {
+    $schema['rules_tags'] = array(
+      'fields' => array(
+        'id' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'description' => 'The primary identifier of the configuration.',
+        ),
+        'tag' => array(
+          'type' => 'varchar',
+          'length' => '255',
+          'not null' => TRUE,
+          'description' => 'The tag string associated with this configuration',
+        ),
+      ),
+      'primary key' => array('id', 'tag'),
+      'foreign keys' => array(
+        'table' => 'rules_config',
+        'columns' => array('id' => 'id'),
+      ),
+    );
+    db_create_table('rules_tags', $schema['rules_tags']);
+  }
+}
+
+/**
+ * Add the rules_dependencies table and the rules_config.dirty column.
+ */
+function rules_update_7205() {
+  if (!db_table_exists('rules_dependencies')) {
+    $schema['rules_dependencies'] = array(
+      'fields' => array(
+        'id' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'description' => 'The primary identifier of the configuration.',
+        ),
+        'module' => array(
+          'type' => 'varchar',
+          'length' => '255',
+          'not null' => TRUE,
+          'description' => 'The name of the module that is required for the configuration.',
+        ),
+      ),
+      'primary key' => array('id', 'module'),
+      'indexes' => array(
+        'module' => array('module'),
+      ),
+      'foreign keys' => array(
+        'table' => 'rules_config',
+        'columns' => array('id' => 'id'),
+      ),
+    );
+    db_create_table('rules_dependencies', $schema['rules_dependencies']);
+  }
+  if (!db_field_exists('rules_config', 'dirty')) {
+    db_add_field('rules_config', 'dirty', array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'default' => 0,
+      'size' => 'tiny',
+    ));
+  }
+}
+
+/**
+ * Flush all caches.
+ */
+function rules_update_7206() {
+  // The update system is going to flush all caches anyway, so nothing to do.
+}
+
+/**
+ * Flush all caches.
+ */
+function rules_update_7207() {
+  // The update system is going to flush all caches anyway, so nothing to do.
+}
+
+/**
+ * Flush all caches to update the data_is_empty condition info.
+ */
+function rules_update_7208() {
+  // The update system is going to flush all caches anyway, so nothing to do.
+}
+
+/**
+ * Creates a flag that enables a permission for using components.
+ */
+function rules_update_7209() {
+  // Create a access exposed flag column.
+  db_add_field('rules_config', 'access_exposed', array(
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0,
+    'size' => 'tiny',
+    'description' => 'Whether to use a permission to control access for using components.',
+  ));
+}
+
+/**
+ * Deletes the unused rules_empty_sets variable.
+ */
+function rules_update_7210() {
+  variable_del('rules_empty_sets');
+}
+
+/**
+ * Creates the "owner" column.
+ */
+function rules_update_7211() {
+  // Create a owner column.
+  db_add_field('rules_config', 'owner', array(
+    'description' => 'The name of the module via which the rule has been configured.',
+    'type' => 'varchar',
+    'length' => 255,
+    'not null' => TRUE,
+    'default' => 'rules',
+  ));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1636 @@
+<?php
+
+/**
+ * @file Rules engine module
+ */
+
+/**
+ * Implements hook_init().
+ */
+function rules_init() {
+  module_load_include('inc', 'rules', 'modules/events');
+  rules_invoke_event('init');
+}
+
+/**
+ * Returns an instance of the rules UI controller, which eases re-using the Rules UI.
+ *
+ * See the rules_admin.module for example usage.
+ *
+ * @return RulesUIController
+ */
+function rules_ui() {
+  $static = drupal_static(__FUNCTION__);
+  if (!isset($static)) {
+    $static = new RulesUIController();
+  }
+  return $static;
+}
+
+/**
+ * Returns a new rules action.
+ *
+ * @param $name
+ *   The action's name.
+ * @param $settings
+ *   The action's settings array.
+ * @return RulesAction
+ */
+function rules_action($name, $settings = array()) {
+  return rules_plugin_factory('action', $name, $settings);
+}
+
+/**
+ * Returns a new rules condition.
+ *
+ * @param $name
+ *   The condition's name.
+ * @param $settings
+ *   The condition's settings array.
+ * @return RulesCondition
+ */
+function rules_condition($name, $settings = array()) {
+  return rules_plugin_factory('condition', $name, $settings);
+}
+
+/**
+ * Creates a new rule.
+ *
+ * @param $variables
+ *   The array of variables to setup in the evaluation state, making them
+ *   available for the configuraion elements. Values for the variables need to
+ *   be passed as argument when the rule is executed. Only Rule instances with
+ *   no variables can be embedded in other configurations, e.g. rule sets.
+ *   The array has to be keyed by variable name and contain a sub-array for each
+ *   variable that has the same structure as the arrays used for describing
+ *   parameters of an action, see hook_rules_action_info(). However, in addition
+ *   to that the following keys are supported:
+ *    - parameter: (optional) If set to FALSE, no parameter for the variable
+ *      is created - thus no argument needs to be passed to the rule for the
+ *      variable upon execution. As a consequence no value will be set
+ *      initially, but the "Set data value" action may be used to do so. This is
+ *      in particular useful for defining variables which can be provided to the
+ *      caller (see $provides argument) but need not be passed in as parameter.
+ * @param $provides
+ *   The names of variables which should be provided to the caller. Only
+ *   variables contained in $variables may be specified.
+ * @return Rule
+ */
+function rule($variables = NULL, $provides = array()) {
+  return rules_plugin_factory('rule', $variables, $provides);
+}
+
+/**
+ * Creates a new reaction rule.
+ *
+ * @return RulesReactionRule
+ */
+function rules_reaction_rule() {
+  return rules_plugin_factory('reaction rule');
+}
+
+/**
+ * Creates a logical OR condition container.
+ *
+ * @param $variables
+ *   An optional array as for rule().
+ * @return RulesOr
+ */
+function rules_or($variables = NULL) {
+  return rules_plugin_factory('or', $variables);
+}
+
+/**
+ * Creates a logical AND condition container.
+ *
+ * @param $variables
+ *   An optional array as for rule().
+ * @return RulesAnd
+ */
+function rules_and($variables = NULL) {
+  return rules_plugin_factory('and', $variables);
+}
+
+/**
+ * Creates a loop.
+ *
+ * @param $settings
+ *   The loop settings, containing
+ *     'list:select': The data selector for the list to loop over.
+ *     'item:var': Optionally a name for the list item variable.
+ *     'item:label': Optionally a lebel for the list item variable.
+ * @param $variables
+ *   An optional array as for rule().
+ * @return RulesLoop
+ */
+function rules_loop($settings = array(), $variables = NULL) {
+  return rules_plugin_factory('loop', $settings, $variables);
+}
+
+/**
+ * Creates a rule set.
+ *
+ * @param $variables
+ *   An array as for rule().
+ * @param $provides
+ *   The names of variables which should be provided to the caller. See rule().
+ * @return RulesRuleSet
+ */
+function rules_rule_set($variables = array(), $provides = array()) {
+  return rules_plugin_factory('rule set', $variables, $provides);
+}
+
+/**
+ * Creates an action set.
+ *
+ * @param $variables
+ *   An array as for rule().
+ * @param $provides
+ *   The names of variables which should be provided to the caller. See rule().
+ * @return RulesActionSet
+ */
+function rules_action_set($variables = array(), $provides = array()) {
+  return rules_plugin_factory('action set', $variables, $provides);
+}
+
+/**
+ * Log a message to the rules logger.
+ *
+ * @param $msg
+ *   The message to log.
+ * @param $args
+ *   An array of placeholder arguments as used by t().
+ * @param $priority
+ *   A priority as defined by the RulesLog class.
+ * @param RulesPlugin $element
+ *  (optional) The RulesElement causing the log entry.
+ * @param boolean $scope
+ *  (optional) This may be used to denote the beginning (TRUE) or the end
+ *  (FALSE) of a new execution scope.
+ */
+function rules_log($msg, $args = array(), $priority = RulesLog::INFO, RulesPlugin $element = NULL, $scope = NULL) {
+  static $logger, $settings;
+
+  // Statically cache the variable settings as this is called very often.
+  if (!isset($settings)) {
+    $settings['rules_log_errors'] = variable_get('rules_log_errors', RulesLog::WARN);
+    $settings['rules_debug_log'] = variable_get('rules_debug_log', FALSE);
+    $settings['rules_debug'] = variable_get('rules_debug', FALSE);
+  }
+
+  if ($priority >= $settings['rules_log_errors']) {
+    $link = NULL;
+    if (isset($element) && isset($element->root()->name)) {
+      $link = l(t('edit configuration'), RulesPluginUI::path($element->root()->name, 'edit', $element));
+    }
+    watchdog('rules', $msg, $args, $priority == RulesLog::WARN ? WATCHDOG_WARNING : WATCHDOG_ERROR, $link);
+  }
+  // Do nothing in case debugging is totally disabled.
+  if (!$settings['rules_debug_log'] && !$settings['rules_debug']) {
+    return;
+  }
+  if (!isset($logger)) {
+    $logger = RulesLog::logger();
+  }
+  $path = isset($element) && isset($element->root()->name) ? RulesPluginUI::path($element->root()->name, 'edit', $element) : NULL;
+  $logger->log($msg, $args, $priority, $scope, $path);
+}
+
+/**
+ * Fetches module definitions for the given hook name.
+ *
+ * Used for collecting events, rules, actions and condtions from other modules.
+ *
+ * @param $hook
+ *   The hook of the definitions to get from invoking hook_rules_{$hook}.
+ */
+function rules_fetch_data($hook) {
+  $data = &drupal_static(__FUNCTION__, array());
+  static $discover = array(
+    'action_info' => 'RulesActionHandlerInterface',
+    'condition_info' => 'RulesConditionHandlerInterface',
+    'event_info' => 'RulesEventHandlerInterface',
+  );
+
+  if (!isset($data[$hook])) {
+    foreach (module_implements('rules_' . $hook) as $module) {
+      $result = call_user_func($module . '_rules_' . $hook);
+      if (isset($result) && is_array($result)) {
+        foreach ($result as $name => $item) {
+          $item += array('module' => $module);
+          $data[$hook][$name] = $item;
+        }
+      }
+    }
+    // Support class discovery.
+    if (isset($discover[$hook])) {
+      $data[$hook] += rules_discover_plugins($discover[$hook]);
+    }
+    drupal_alter('rules_'. $hook, $data[$hook]);
+  }
+  return $data[$hook];
+}
+
+/**
+ * Discover plugin implementations.
+ *
+ * Class based plugin handlers must be loaded when rules caches are rebuilt,
+ * such that they get discovered properly. You have the following options:
+ *  - Put it into a regular module file (discouraged)
+ *  - Put it into your module.rules.inc file
+ *  - Put it in any file and declare it using hook_rules_file_info()
+ *  - Put it in any file and declare it using hook_rules_directory()
+ *
+ * In addition to that, the class must be loadable via regular class
+ * auto-loading, thus put the file holding the class in your info file or use
+ * another class-loader.
+ *
+ * @param string $class
+ *   The class or interface the plugins must implement. For a plugin to be
+ *   discovered it must have a static getInfo() method also.
+ *
+ * @return array
+ *   An info-hook style array containing info about discovered plugins.
+ *
+ * @see RulesActionHandlerInterface
+ * @see RulesConditionHandlerInterface
+ * @see RulesEventHandlerInterface
+ */
+function rules_discover_plugins($class) {
+  // Make sure all files possibly holding plugins are included.
+  RulesAbstractPlugin::includeFiles();
+
+  $items = array();
+  foreach (get_declared_classes() as $plugin_class) {
+    if (is_subclass_of($plugin_class, $class) && method_exists($plugin_class, 'getInfo')) {
+      $info = call_user_func(array($plugin_class, 'getInfo'));
+      $info['class'] = $plugin_class;
+      $info['module'] = _rules_discover_module($plugin_class);
+      $items[$info['name']] = $info;
+    }
+  }
+  return $items;
+}
+
+/**
+ * Determines the module providing the given class.
+ */
+function _rules_discover_module($class) {
+  $paths = &drupal_static(__FUNCTION__);
+
+  if (!isset($paths)) {
+    // Build up a map of modules keyed by their directory.
+    foreach (system_list('module_enabled') as $name => $module_info) {
+      $paths[dirname($module_info->filename)] = $name;
+    }
+  }
+
+  // Retrieve the class file and convert its absolute path to a regular Drupal
+  // path relative to the installation root.
+  $reflection = new ReflectionClass($class);
+  $path = str_replace(realpath(DRUPAL_ROOT) . DIRECTORY_SEPARATOR, '', realpath(dirname($reflection->getFileName())));
+  $path = DIRECTORY_SEPARATOR != '/' ? str_replace(DIRECTORY_SEPARATOR, '/', $path) : $path;
+
+  // Go up the path until we match a module up.
+  $parts = explode('/', $path);
+  while (!isset($paths[$path]) && array_pop($parts)) {
+    $path = dirname($path);
+  }
+  return isset($paths[$path]) ? $paths[$path] : FALSE;
+}
+
+/**
+ * Gets a rules cache entry.
+ */
+function &rules_get_cache($cid = 'data') {
+  // Make use of the fast, advanced drupal static pattern.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['cache'] = &drupal_static(__FUNCTION__, array());
+  }
+  $cache = &$drupal_static_fast['cache'];
+
+  if (!isset($cache[$cid])) {
+    // The main 'data' cache includes translated strings, so each language is
+    // cached separately.
+    $cid_suffix = $cid == 'data' ? ':' . $GLOBALS['language']->language : '';
+
+    if ($get = cache_get($cid . $cid_suffix, 'cache_rules')) {
+      $cache[$cid] = $get->data;
+    }
+    elseif ($cid === 'data') {
+      // There is no 'data' cache so we need to rebuild it. Make sure subsequent
+      // cache gets of the main 'data' cache during rebuild get the interim
+      // cache by passing in the reference of the static cache variable.
+      _rules_rebuild_cache($cache['data']);
+    }
+    elseif (strpos($cid, 'comp_') === 0) {
+      $cache[$cid] = FALSE;
+      _rules_rebuild_component_cache();
+    }
+    elseif (strpos($cid, 'event_') === 0) {
+      $cache[$cid] = FALSE;
+      RulesEventSet::rebuildEventCache();
+    }
+    else {
+      $cache[$cid] = FALSE;
+    }
+  }
+  return $cache[$cid];
+}
+
+/**
+ * Rebuilds the rules cache.
+ *
+ * This rebuilds the rules 'data' cache and invokes rebuildCache() methods on
+ * all plugin classes, which allows plugins to add their own data to the cache.
+ * The cache is rebuilt in the order the plugins are defined.
+ *
+ * Note that building the action/condition info cache triggers loading of all
+ * components, thus depends on entity-loading and so syncing entities in code
+ * to the database.
+ *
+ * @see rules_rules_plugin_info()
+ * @see entity_defaults_rebuild()
+ */
+function _rules_rebuild_cache(&$cache) {
+  foreach(array('data_info', 'plugin_info') as $hook) {
+    $cache[$hook] = rules_fetch_data($hook);
+  }
+  foreach ($cache['plugin_info'] as $name => &$info) {
+    // Let the items add something to the cache.
+    $item = new $info['class']();
+    $item->rebuildCache($info, $cache);
+  }
+  $cid_suffix = ':' . $GLOBALS['language']->language;
+  cache_set('data' . $cid_suffix, $cache, 'cache_rules');
+}
+
+/**
+ * Cache components to allow efficient usage via rules_invoke_component().
+ *
+ * @see rules_invoke_component()
+ * @see rules_get_cache()
+ */
+function _rules_rebuild_component_cache() {
+  $components = rules_get_components();
+
+  foreach ($components as $id => $component) {
+    // If a component is marked as dirty, check if this still applies.
+    if ($component->dirty) {
+      rules_config_update_dirty_flag($component);
+    }
+    if (!$component->dirty) {
+      // Clone the component to avoid modules getting the to be cached
+      // version from the static loading cache.
+      $component = clone $component;
+      $component->optimize();
+      // Allow modules to alter the cached component.
+      drupal_alter('rules_component', $component->plugin, $component);
+      rules_set_cache('comp_' . $component->name, $component);
+    }
+  }
+}
+
+/**
+ * Sets a rules cache item.
+ *
+ * In addition to calling cache_set(), this function makes sure the cache item
+ * is immediately available via rules_get_cache() by keeping all cache items
+ * in memory. That way we can guarantee rules_get_cache() is able to retrieve
+ * any cache item, even if all cache gets fail.
+ *
+ * @see rules_get_cache()
+ */
+function rules_set_cache($cid, $data) {
+  $cache = &drupal_static('rules_get_cache', array());
+  $cache[$cid] = $data;
+  cache_set($cid, $data, 'cache_rules');
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function rules_flush_caches() {
+  return array('cache_rules');
+}
+
+/**
+ * Clears the rule set cache
+ */
+function rules_clear_cache() {
+  cache_clear_all('*', 'cache_rules', TRUE);
+  variable_del('rules_event_whitelist');
+  drupal_static_reset('rules_get_cache');
+  drupal_static_reset('rules_fetch_data');
+  drupal_static_reset('rules_config_update_dirty_flag');
+  entity_get_controller('rules_config')->resetCache();
+}
+
+/**
+ * Imports the given export and returns the imported configuration.
+ *
+ * @param $export
+ *   A serialized string in JSON format as produced by the RulesPlugin::export()
+ *   method, or the PHP export as usual PHP array.
+ * @return RulesPlugin
+ */
+function rules_import($export, &$error_msg = '') {
+  return entity_get_controller('rules_config')->import($export, $error_msg);
+}
+
+
+/**
+ * Wraps the given data.
+ *
+ * @param $data
+ *   If available, the actual data, else NULL.
+ * @param $info
+ *   An array of info about this data.
+ * @param $force
+ *   Usually data is only wrapped if really needed. If set to TRUE, wrapping the
+ *   data is forced, so primitive data types are also wrapped.
+ * @return EntityMetadataWrapper
+ *   An EntityMetadataWrapper or the unwrapped data.
+ *
+ * @see hook_rules_data_info()
+ */
+function &rules_wrap_data($data = NULL, $info, $force = FALSE) {
+  // If the data is already wrapped, use the existing wrapper.
+  if ($data instanceof EntityMetadataWrapper) {
+    return $data;
+  }
+  $cache = rules_get_cache();
+  // Define the keys to be passed through to the metadata wrapper.
+  $wrapper_keys = array_flip(array('property info', 'property defaults'));
+  if (isset($cache['data_info'][$info['type']])) {
+    $info += array_intersect_key($cache['data_info'][$info['type']], $wrapper_keys);
+  }
+  // If a list is given, also add in the info of the item type.
+  $list_item_type = entity_property_list_extract_type($info['type']);
+  if ($list_item_type && isset($cache['data_info'][$list_item_type])) {
+    $info += array_intersect_key($cache['data_info'][$list_item_type], $wrapper_keys);
+  }
+  // By default we do not wrap the data, except for completely unknown types.
+  if (!empty($cache['data_info'][$info['type']]['wrap']) || $list_item_type || $force || empty($cache['data_info'][$info['type']])) {
+    unset($info['handler']);
+    // Allow data types to define custom wrapper classes.
+    if (!empty($cache['data_info'][$info['type']]['wrapper class'])) {
+      $class = $cache['data_info'][$info['type']]['wrapper class'];
+      $wrapper = new $class($info['type'], $data, $info);
+    }
+    else {
+      $wrapper = entity_metadata_wrapper($info['type'], $data, $info);
+    }
+    return $wrapper;
+  }
+  return $data;
+}
+
+/**
+ * Unwraps the given data, if it's wrapped.
+ *
+ * @param $data
+ *   An array of wrapped data.
+ * @param $info
+ *   Optionally an array of info about how to unwrap the data. Keyed as $data.
+ * @return
+ *   An array containing unwrapped or passed through data.
+ */
+function rules_unwrap_data(array $data, $info = array()) {
+  $cache = rules_get_cache();
+  foreach ($data as $key => $entry) {
+    // If it's a wrapper, unwrap unless specified otherwise.
+    if ($entry instanceof EntityMetadataWrapper) {
+      if (!isset($info[$key]['allow null'])) {
+        $info[$key]['allow null'] = FALSE;
+      }
+      if (!isset($info[$key]['wrapped'])) {
+        // By default, do not unwrap special data types that are always wrapped.
+        $info[$key]['wrapped'] = (isset($info[$key]['type']) && is_string($info[$key]['type']) && !empty($cache['data_info'][$info[$key]['type']]['is wrapped']));
+      }
+      // Activate the decode option by default if 'sanitize' is not enabled, so
+      // any text is either sanitized or decoded.
+      // @see EntityMetadataWrapper::value()
+      $options = $info[$key] + array('decode' => empty($info[$key]['sanitize']));
+
+      try {
+        if (!($info[$key]['allow null'] && $info[$key]['wrapped'])) {
+          $value = $entry->value($options);
+
+          if (!$info[$key]['wrapped']) {
+            $data[$key] = $value;
+          }
+          if (!$info[$key]['allow null'] && !isset($value)) {
+            throw new RulesEvaluationException('The variable or parameter %name is empty.', array('%name' => $key));
+          }
+        }
+      }
+      catch (EntityMetadataWrapperException $e) {
+        throw new RulesEvaluationException('Unable to get the data value for the variable or parameter %name. Error: !error', array('%name' => $key, '!error' => $e->getMessage()));
+      }
+    }
+  }
+  return $data;
+}
+
+/**
+ * Gets event info for a given event.
+ *
+ * @param string $event_name
+ *   A (configured) event name.
+ *
+ * @return array
+ *   An array of event info. If the event is unknown, a suiting info array is
+ *   generated and returned
+ */
+function rules_get_event_info($event_name) {
+  $base_event_name = rules_get_event_base_name($event_name);
+  $events = rules_fetch_data('event_info');
+  if (isset($events[$base_event_name])) {
+    return $events[$base_event_name] + array('name' => $base_event_name);
+  }
+  return array(
+    'label' => t('Unknown event "!event_name"', array('!event_name' => $base_event_name)),
+    'name' => $base_event_name,
+  );
+}
+
+/**
+ * Returns the base name of a configured event name.
+ *
+ * For a configured event name like node_view--article the base event name
+ * node_view is returned.
+ *
+ * @return string
+ *   The event base name.
+ */
+function rules_get_event_base_name($event_name) {
+  // Cut off any suffix from a configured event name.
+  if (strpos($event_name, '--') !== FALSE) {
+    $parts = explode('--', $event_name, 2);
+    return $parts[0];
+  }
+  return $event_name;
+}
+
+/**
+ * Returns the rule event handler for the given event.
+ *
+ * Events having no settings are handled via the class RulesEventSettingsNone.
+ *
+ * @param string $event_name
+ *   The event name (base or configured).
+ * @param array $settings
+ *   (optional) An array of event settings to set on the handler.
+ *
+ * @return RulesEventHandlerInterface
+ *   The event handler.
+ */
+function rules_get_event_handler($event_name, array $settings = NULL) {
+  $event_name = rules_get_event_base_name($event_name);
+  $event_info = rules_get_event_info($event_name);
+  $class = !empty($event_info['class']) ? $event_info['class'] : 'RulesEventDefaultHandler';
+  $handler = new $class($event_name, $event_info);
+  return isset($settings) ? $handler->setSettings($settings) : $handler;
+}
+
+/**
+ * Creates a new instance of a the given rules plugin.
+ *
+ * @return RulesPlugin
+ */
+function rules_plugin_factory($plugin_name, $arg1 = NULL, $arg2 = NULL) {
+  $cache = rules_get_cache();
+  if (isset($cache['plugin_info'][$plugin_name]['class'])) {
+    return new $cache['plugin_info'][$plugin_name]['class']($arg1, $arg2);
+  }
+}
+
+/**
+ * Implementation of hook_rules_plugin_info().
+ *
+ * Note that the cache is rebuilt in the order of the plugins. Therefore the
+ * condition and action plugins must be at the top, so that any components
+ * re-building their cache can create configurations including properly setup-ed
+ * actions and conditions.
+ */
+function rules_rules_plugin_info() {
+  return array(
+    'condition' => array(
+      'class' => 'RulesCondition',
+      'embeddable' => 'RulesConditionContainer',
+      'extenders' => array (
+        'RulesPluginImplInterface' => array(
+          'class' => 'RulesAbstractPluginDefaults',
+        ),
+        'RulesPluginFeaturesIntegrationInterace' => array(
+          'methods' => array(
+            'features_export' => 'rules_features_abstract_default_features_export',
+          ),
+        ),
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesAbstractPluginUI',
+        ),
+      ),
+    ),
+    'action' => array(
+      'class' => 'RulesAction',
+      'embeddable' => 'RulesActionContainer',
+      'extenders' => array (
+        'RulesPluginImplInterface' => array(
+          'class' => 'RulesAbstractPluginDefaults',
+        ),
+        'RulesPluginFeaturesIntegrationInterace' => array(
+          'methods' => array(
+            'features_export' => 'rules_features_abstract_default_features_export',
+          ),
+        ),
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesAbstractPluginUI',
+        ),
+      ),
+    ),
+    'or' => array(
+      'label' => t('Condition set (OR)'),
+      'class' => 'RulesOr',
+      'embeddable' => 'RulesConditionContainer',
+      'component' => TRUE,
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesConditionContainerUI',
+        ),
+      ),
+    ),
+    'and' => array(
+      'label' => t('Condition set (AND)'),
+      'class' => 'RulesAnd',
+      'embeddable' => 'RulesConditionContainer',
+      'component' => TRUE,
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesConditionContainerUI',
+        ),
+      ),
+    ),
+    'action set' => array(
+      'label' => t('Action set'),
+      'class' => 'RulesActionSet',
+      'embeddable' => FALSE,
+      'component' => TRUE,
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesActionContainerUI',
+        ),
+      ),
+    ),
+    'rule' => array(
+      'label' => t('Rule'),
+      'class' => 'Rule',
+      'embeddable' => 'RulesRuleSet',
+      'component' => TRUE,
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesRuleUI',
+        ),
+      ),
+    ),
+    'loop' => array(
+      'class' => 'RulesLoop',
+      'embeddable' => 'RulesActionContainer',
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesLoopUI',
+        ),
+      ),
+    ),
+    'reaction rule' => array(
+      'class' => 'RulesReactionRule',
+      'embeddable' => FALSE,
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesReactionRuleUI',
+        ),
+      ),
+    ),
+    'event set' => array(
+      'class' => 'RulesEventSet',
+      'embeddable' => FALSE,
+    ),
+    'rule set' => array(
+      'label' => t('Rule set'),
+      'class' => 'RulesRuleSet',
+      'component' => TRUE,
+      // Rule sets don't get embedded - we use a separate action to execute.
+      'embeddable' => FALSE,
+      'extenders' => array(
+        'RulesPluginUIInterface' => array(
+          'class' => 'RulesRuleSetUI',
+        ),
+      ),
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_entity_info().
+ */
+function rules_entity_info() {
+  return array(
+    'rules_config' => array(
+      'label' => t('Rules configuration'),
+      'controller class' => 'RulesEntityController',
+      'base table' => 'rules_config',
+      'fieldable' => TRUE,
+      'entity keys' => array(
+        'id' => 'id',
+        'name' => 'name',
+        'label' => 'label',
+      ),
+      'module' => 'rules',
+      'static cache' => TRUE,
+      'bundles' => array(),
+      'configuration' => TRUE,
+      'exportable' => TRUE,
+      'export' => array(
+        'default hook' => 'default_rules_configuration',
+      ),
+      'access callback' => 'rules_config_access',
+      'features controller class' => 'RulesFeaturesController',
+    ),
+  );
+}
+
+/**
+ * Implementation of hook_hook_info().
+ */
+function rules_hook_info() {
+  foreach(array('plugin_info', 'rules_directory', 'data_info', 'condition_info', 'action_info', 'event_info', 'file_info', 'evaluator_info', 'data_processor_info') as $hook) {
+    $hooks['rules_' . $hook] = array(
+      'group' => 'rules',
+    );
+    $hooks['rules_' . $hook . '_alter'] = array(
+      'group' => 'rules',
+    );
+  }
+  $hooks['default_rules_configuration'] = array(
+    'group' => 'rules_defaults',
+  );
+  $hooks['default_rules_configuration_alter'] = array(
+    'group' => 'rules_defaults',
+  );
+  return $hooks;
+}
+
+/**
+ * Load rule configurations from the database.
+ *
+ * This function should be used whenever you need to load more than one entity
+ * from the database. The entities are loaded into memory and will not require
+ * database access if loaded again during the same page request.
+ *
+ * @see hook_entity_info()
+ * @see RulesEntityController
+ *
+ * @param $names
+ *   An array of rules configuration names or FALSE to load all.
+ * @param $conditions
+ *   An array of conditions in the form 'field' => $value.
+ *
+ * @return
+ *   An array of rule configurations indexed by their ids.
+ */
+function rules_config_load_multiple($names = array(), $conditions = array()) {
+  return entity_load_multiple_by_name('rules_config', $names, $conditions);
+}
+
+/**
+ * Loads a single rule configuration from the database.
+ *
+ * @see rules_config_load_multiple()
+ *
+ * @return RulesPlugin
+ */
+function rules_config_load($name) {
+  return entity_load_single('rules_config', $name);
+}
+
+/**
+ * Returns an array of configured components.
+ *
+ * For actually executing a component use rules_invoke_component(), as this
+ * retrieves the component from cache instead.
+ *
+ * @param $label
+ *   Whether to return only the label or the whole component object.
+ * @param $type
+ *   Optionally filter for 'action' or 'condition' components.
+ * @param $conditions
+ *   An array of additional conditions as required by rules_config_load().
+ *
+ * @return
+ *   An array keyed by component name containing either the label or the config.
+ */
+function rules_get_components($label = FALSE, $type = NULL, $conditions = array()) {
+  $cache = rules_get_cache();
+  $plugins = array_keys(rules_filter_array($cache['plugin_info'], 'component', TRUE));
+  $conditions = $conditions + array('plugin' => $plugins);
+  $faces = array(
+    'action' => 'RulesActionInterface',
+    'condition' => 'RulesConditionInterface',
+  );
+  $items = array();
+  foreach (rules_config_load_multiple(FALSE, $conditions) as $name => $config) {
+    if (!isset($type) || $config instanceof $faces[$type]) {
+      $items[$name] = $label ? $config->label() : $config;
+    }
+  }
+  return $items;
+}
+
+/**
+ * Delete rule configurations from database.
+ *
+ * @param $ids
+ *   An array of entity IDs.
+ */
+function rules_config_delete(array $ids) {
+  return entity_get_controller('rules_config')->delete($ids);
+}
+
+/**
+ * Ensures the configuration's 'dirty' flag is up to date by running an integrity check.
+ *
+ * @param $update
+ *   (optional) Whether the dirty flag is also updated in the database if
+ *   necessary. Defaults to TRUE.
+ */
+function rules_config_update_dirty_flag($rules_config, $update = TRUE) {
+  // Keep a log of already check configurations to avoid repetitive checks on
+  // oftent used components.
+  // @see rules_element_invoke_component_validate()
+  $checked = &drupal_static(__FUNCTION__, array());
+  if (!empty($checked[$rules_config->name])) {
+    return;
+  }
+  $checked[$rules_config->name] = TRUE;
+
+  $was_dirty = !empty($rules_config->dirty);
+  try {
+    // First set the rule to dirty, so any repetitive checks give green light
+    // for this configuration.
+    $rules_config->dirty = FALSE;
+    $rules_config->integrityCheck();
+    if ($was_dirty) {
+      $variables = array('%label' => $rules_config->label(), '%name' => $rules_config->name, '@plugin' => $rules_config->plugin());
+      watchdog('rules', 'The @plugin %label (%name) was marked dirty, but passes the integrity check now and is active again.', $variables, WATCHDOG_INFO);
+    }
+  }
+  catch (RulesIntegrityException $e) {
+    $rules_config->dirty = TRUE;
+    if (!$was_dirty) {
+      $variables = array('%label' => $rules_config->label(), '%name' => $rules_config->name, '!message' => $e->getMessage(), '@plugin' => $rules_config->plugin());
+      watchdog('rules', 'The @plugin %label (%name) fails the integrity check and cannot be executed. Error: !message', $variables, WATCHDOG_ERROR);
+    }
+  }
+  // Save the updated dirty flag to the database.
+  if ($was_dirty != $rules_config->dirty) {
+    db_update('rules_config')
+      ->fields(array('dirty' => (int) $rules_config->dirty))
+      ->condition('id', $rules_config->id)
+      ->execute();
+  }
+}
+
+/**
+ * Invokes a hook and the associated rules event.
+ *
+ * Calling this function does the same as calling module_invoke_all() and
+ * rules_invoke_event() separately, however merges both functions into one in
+ * order to ease usage and to work efficiently.
+ *
+ * @param $hook
+ *   The name of the hook / event to invoke.
+ * @param ...
+ *   Arguments to pass to the hook / event.
+ *
+ * @return
+ *   An array of return values of the hook implementations. If modules return
+ *   arrays from their implementations, those are merged into one array.
+ */
+function rules_invoke_all() {
+  // Copied code from module_invoke_all().
+  $args = func_get_args();
+  $hook = $args[0];
+  unset($args[0]);
+  $return = array();
+  foreach (module_implements($hook) as $module) {
+    $function = $module . '_' . $hook;
+    if (function_exists($function)) {
+      $result = call_user_func_array($function, $args);
+      if (isset($result) && is_array($result)) {
+        $return = array_merge_recursive($return, $result);
+      }
+      elseif (isset($result)) {
+        $return[] = $result;
+      }
+    }
+  }
+  // Invoke the event.
+  rules_invoke_event_by_args($hook, $args);
+
+  return $return;
+}
+
+/**
+ * Invokes configured rules for the given event.
+ *
+ * @param $event_name
+ *   The event's name.
+ * @param ...
+ *   Pass parameters for the variables provided by this event, as defined in
+ *   hook_rules_event_info(). Example given:
+ *   @code
+ *     rules_invoke_event('node_view', $node, $view_mode);
+ *   @endcode
+ *
+ * @see rules_invoke_event_by_args()
+ */
+function rules_invoke_event() {
+  global $conf;
+
+  $args = func_get_args();
+  $event_name = $args[0];
+  unset($args[0]);
+  // We maintain a whitelist of configured events to reduces the number of cache
+  // reads. We access it directly via the global $conf as this is fast without
+  // having to introduce another static cache. Then, if the whitelist is unset,
+  // we ignore it so cache rebuilding is triggered.
+  if (!defined('MAINTENANCE_MODE') && (!isset($conf['rules_event_whitelist']) || isset($conf['rules_event_whitelist'][$event_name])) && $event = rules_get_cache('event_' . $event_name)) {
+    $event->executeByArgs($args);
+  }
+}
+
+/**
+ * Invokes configured rules for the given event.
+ *
+ * @param $event_name
+ *   The event's name.
+ * @param $args
+ *   An array of parameters for the variables provided by the event, as defined
+ *   in hook_rules_event_info(). Either pass an array keyed by the variable
+ *   names or a numerically indexed array, in which case the ordering of the
+ *   passed parameters has to match the order of the specified variables.
+ *   Example given:
+ *   @code
+ *     rules_invoke_event_by_args('node_view', array('node' => $node, 'view_mode' => $view_mode));
+ *   @endcode
+ *
+ * @see rules_invoke_event()
+ */
+function rules_invoke_event_by_args($event_name, $args = array()) {
+  global $conf;
+
+  // We maintain a whitelist of configured events to reduces the number of cache
+  // reads. We access it directly via the global $conf as this is fast without
+  // having to introduce another static cache. Then, if the whitelist is unset,
+  // we ignore it so cache rebuilding is triggered.
+  if (!defined('MAINTENANCE_MODE') && (!isset($conf['rules_event_whitelist']) || isset($conf['rules_event_whitelist'][$event_name])) && $event = rules_get_cache('event_' . $event_name)) {
+    $event->executeByArgs($args);
+  }
+}
+
+/**
+ * Invokes a rule component, e.g. a rule set.
+ *
+ * @param $component_name
+ *   The component's name.
+ * @param $args
+ *   Pass further parameters as required for the invoked component.
+ *
+ * @return
+ *   An array of variables as provided by the component, or FALSE in case the
+ *   component could not be executed.
+ */
+function rules_invoke_component() {
+  $args = func_get_args();
+  $name = array_shift($args);
+  if ($component = rules_get_cache('comp_' . $name)) {
+    return $component->executeByArgs($args);
+  }
+  return FALSE;
+}
+
+/**
+ * Filters the given array of arrays by keeping only entries which have $key set
+ * to the value of $value.
+ *
+ * @param $array
+ *   The array of arrays to filter.
+ * @param $key
+ *   The key used for the comparison.
+ * @param $value
+ *   The value to compare the array's entry to.
+ *
+ * @return array
+ *   The filtered array.
+ */
+function rules_filter_array($array, $key, $value) {
+  $return = array();
+  foreach ($array as $i => $entry) {
+    $entry += array($key => NULL);
+    if ($entry[$key] == $value) {
+      $return[$i] = $entry;
+    }
+  }
+  return $return;
+}
+
+/**
+ * Merges the $update array into $array making sure no values of $array not
+ * appearing in $update are lost.
+ *
+ * @return
+ *   The updated array.
+ */
+function rules_update_array(array $array, array $update) {
+  foreach ($update as $key => $data) {
+    if (isset($array[$key]) && is_array($array[$key]) && is_array($data)) {
+      $array[$key] = rules_update_array($array[$key], $data);
+    }
+    else {
+      $array[$key] = $data;
+    }
+  }
+  return $array;
+}
+
+/**
+ * Extracts the property with the given name.
+ *
+ * @param $arrays
+ *   An array of arrays from which a property is to be extracted.
+ * @param $key
+ *   The name of the property to extract.
+ *
+ * @return An array of extracted properties, keyed as in $arrays-
+ */
+function rules_extract_property($arrays, $key) {
+  $data = array();
+  foreach ($arrays as $name => $item) {
+    $data[$name] = $item[$key];
+  }
+  return $data;
+}
+
+/**
+ * Returns the first key of the array.
+ */
+function rules_array_key($array) {
+  reset($array);
+  return key($array);
+}
+
+/**
+ * Clean replacements so they are URL friendly.
+ *
+ * Can be used as 'cleaning callback' for action or condition parameters.
+ *
+ * @param $replacements
+ *   An array of token replacements that need to be "cleaned" for use in the URL.
+ * @param $data
+ *   An array of objects used to generate the replacements.
+ * @param $options
+ *   An array of options used to generate the replacements.
+ *
+ * @see rules_path_action_info()
+ */
+function rules_path_clean_replacement_values(&$replacements, $data = array(), $options = array()) {
+  // Include path.eval.inc which contains path cleaning functions.
+  module_load_include('inc', 'rules', 'modules/path.eval');
+  foreach ($replacements as $token => $value) {
+    $replacements[$token] = rules_clean_path($value);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function rules_theme() {
+  return array(
+    'rules_elements' => array(
+      'render element' => 'element',
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_content_group' => array(
+      'render element' => 'element',
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_parameter_configuration' => array(
+      'render element' => 'element',
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_variable_view' => array(
+      'render element' => 'element',
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_data_selector_help' => array(
+      'variables' => array('parameter' => NULL, 'variables' => NULL),
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_ui_variable_form' => array(
+      'render element' => 'element',
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_log' => array(
+      'render element' => 'element',
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_autocomplete' => array(
+      'render element' => 'element',
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_debug_element' => array(
+      'render element' => 'element',
+      'file' => 'ui/ui.theme.inc',
+    ),
+    'rules_settings_help' => array(
+      'variables' => array('text' => '', 'heading' => ''),
+      'file' => 'ui/ui.theme.inc',
+    ),
+  );
+}
+
+/**
+ * Implements hook_permission().
+ */
+function rules_permission() {
+  $perms = array(
+    'administer rules' => array(
+      'title' => t('Administer rule configurations'),
+      'description' => t('Administer rule configurations including events, conditions and actions for which the user has sufficient access permissions.'),
+    ),
+    'bypass rules access' => array(
+      'title' => t('Bypass Rules access control'),
+      'description' => t('Control all configurations regardless of permission restrictions of events, conditions or actions.'),
+      'restrict access' => TRUE,
+    ),
+    'access rules debug' => array(
+      'title' => t('Access the Rules debug log'),
+    ),
+  );
+
+  // Fetch all components to generate the access keys.
+  $conditions['plugin'] = array_keys(rules_filter_array(rules_fetch_data('plugin_info'), 'component', TRUE));
+  $conditions['access_exposed'] = 1;
+  $components = entity_load('rules_config', FALSE, $conditions);
+  $perms += rules_permissions_by_component($components);
+
+  return $perms;
+}
+
+/**
+ * Helper function to get all the permissions for components that have access exposed.
+ */
+function rules_permissions_by_component(array $components = array()) {
+  $perms = array();
+  foreach ($components as $component) {
+    $perms += array(
+      "use Rules component $component->name" => array(
+        'title' => t('Use Rules component %component', array('%component' => $component->label())),
+        'description' => t('Controls access for using the component %component via the provided action or condition. <a href="@component-edit-url">Edit this component.</a>', array('%component' => $component->label(), '@component-edit-url' => url(RulesPluginUI::path($component->name)))),
+      ),
+    );
+  }
+  return $perms;
+}
+
+/**
+ * Menu callback for loading rules configuration elements.
+ * @see RulesUIController::config_menu()
+ */
+function rules_element_load($element_id, $config_name) {
+  $config = rules_config_load($config_name);
+  return $config->elementMap()->lookup($element_id);
+}
+
+/**
+ * Menu callback for getting the title as configured.
+ * @see RulesUIController::config_menu()
+ */
+function rules_get_title($text, $element) {
+  if ($element instanceof RulesPlugin) {
+    $cache = rules_get_cache();
+    $plugin = $element->plugin();
+    $plugin = isset($cache['plugin_info'][$plugin]['label']) ? $cache['plugin_info'][$plugin]['label'] : $plugin;
+    $plugin = drupal_strtolower(drupal_substr($plugin, 0, 1)) . drupal_substr($plugin, 1);
+    return t($text, array('!label' => $element->label(), '!plugin' => $plugin));
+  }
+  // As fallback treat $element as simple string.
+  return t($text, array('!plugin' => $element));
+}
+
+/**
+ * Menu callback for getting the title for the add element page.
+ *
+ * Uses a work-a-round for accessing the plugin name.
+ * @see RulesUIController::config_menu()
+ */
+function rules_menu_add_element_title($array) {
+  $plugin_name = arg($array[0]);
+  $cache = rules_get_cache();
+  if (isset($cache['plugin_info'][$plugin_name]['class'])) {
+    $info = $cache['plugin_info'][$plugin_name] + array('label' => $plugin_name);
+    $label = drupal_strtolower(drupal_substr($info['label'], 0, 1)) . drupal_substr($info['label'], 1);
+    return t('Add a new !plugin', array('!plugin' => $label));
+  }
+}
+
+/**
+ * Returns the current region for the debug log.
+ */
+function rules_debug_log_region() {
+  // If there is no setting for the current theme use the default theme setting.
+  global $theme_key;
+  $theme_default = variable_get('theme_default', 'bartik');
+  return variable_get('rules_debug_region_' . $theme_key, variable_get('rules_debug_region_' . $theme_default, 'help'));
+}
+
+/**
+ * Implements hook_page_build() to add the rules debug log to the page bottom.
+ */
+function rules_page_build(&$page) {
+  // Invoke a the page redirect, in case the action has been executed.
+  // @see rules_action_drupal_goto()
+  if (isset($GLOBALS['_rules_action_drupal_goto_do'])) {
+    list($url, $force) = $GLOBALS['_rules_action_drupal_goto_do'];
+    drupal_goto($url);
+  }
+
+  if (isset($_SESSION['rules_debug'])) {
+    $region = rules_debug_log_region();
+    foreach ($_SESSION['rules_debug'] as $log) {
+      $page[$region]['rules_debug'][] = array(
+        '#markup' => $log,
+      );
+      $page[$region]['rules_debug']['#theme_wrappers'] = array('rules_log');
+    }
+    unset($_SESSION['rules_debug']);
+  }
+
+  if (rules_show_debug_output()) {
+    $region = rules_debug_log_region();
+    $page[$region]['rules_debug']['#pre_render'] = array('rules_debug_log_pre_render');
+  }
+}
+
+/**
+ * Pre-render callback for the debug log, which renders and then clears it.
+ */
+function rules_debug_log_pre_render($elements) {
+  $logger = RulesLog::logger();
+  if ($log = $logger->render()) {
+    $logger = RulesLog::logger();
+    $logger->clear();
+    $elements[] = array('#markup' => $log);
+    $elements['#theme_wrappers'] = array('rules_log');
+    // Log the rules log to the system log if enabled.
+    if (variable_get('rules_debug_log', FALSE)) {
+      watchdog('rules', 'Rules debug information: !log', array('!log' => $log), WATCHDOG_NOTICE);
+    }
+  }
+  return $elements;
+}
+
+/**
+ * Implements hook_drupal_goto_alter().
+ *
+ * @see rules_action_drupal_goto()
+ */
+function rules_drupal_goto_alter(&$path, &$options, &$http_response_code) {
+  // Invoke a the page redirect, in case the action has been executed.
+  if (isset($GLOBALS['_rules_action_drupal_goto_do'])) {
+    list($url, $force) = $GLOBALS['_rules_action_drupal_goto_do'];
+
+    if ($force || !isset($_GET['destination'])) {
+      $url = drupal_parse_url($url);
+      $path = $url['path'];
+      $options['query'] = $url['query'];
+      $options['fragment'] = $url['fragment'];
+      $http_response_code = 302;
+    }
+  }
+}
+
+/**
+ * Returns whether the debug log should be shown.
+ */
+function rules_show_debug_output() {
+  if (variable_get('rules_debug', FALSE) == RulesLog::INFO && user_access('access rules debug')) {
+    return TRUE;
+  }
+  // For performance avoid unnecessary auto-loading of the RulesLog class.
+  return variable_get('rules_debug', FALSE) == RulesLog::WARN && user_access('access rules debug') && class_exists('RulesLog', FALSE) && RulesLog::logger()->hasErrors();
+}
+
+/**
+ * Implements hook_exit().
+ */
+function rules_exit() {
+  // Bail out if this is cached request and modules are not loaded.
+  if (!module_exists('rules') || !module_exists('user')) {
+    return;
+  }
+  if (rules_show_debug_output()) {
+    if ($log = RulesLog::logger()->render()) {
+      // Keep the log in the session so we can show it on the next page.
+      $_SESSION['rules_debug'][] = $log;
+    }
+  }
+  // Log the rules log to the system log if enabled.
+  if (variable_get('rules_debug_log', FALSE) && $log = RulesLog::logger()->render()) {
+    watchdog('rules', 'Rules debug information: !log', array('!log' => $log), WATCHDOG_NOTICE);
+  }
+}
+
+/**
+ * Implements hook_element_info().
+ */
+function rules_element_info() {
+  // A duration form element for rules. Needs ui.forms.inc included.
+  $types['rules_duration'] = array(
+    '#input' => TRUE,
+    '#tree' => TRUE,
+    '#default_value' => 0,
+    '#value_callback' => 'rules_ui_element_duration_value',
+    '#process' => array('rules_ui_element_duration_process', 'ajax_process_form'),
+    '#after_build' => array('rules_ui_element_duration_after_build'),
+    '#pre_render' => array('form_pre_render_conditional_form_element'),
+  );
+  $types['rules_data_selection'] = array(
+    '#input' => TRUE,
+    '#pre_render' => array('form_pre_render_conditional_form_element'),
+    '#process' => array('rules_data_selection_process', 'ajax_process_form'),
+    '#theme' => 'rules_autocomplete',
+  );
+  return $types;
+}
+
+/**
+ * Implements hook_modules_enabled().
+ */
+function rules_modules_enabled($modules) {
+  // Re-enable Rules configurations that are dirty, because they require one of
+  // the enabled the modules.
+  $query = db_select('rules_dependencies', 'rd');
+  $query->join('rules_config', 'rc', 'rd.id = rc.id');
+  $query->fields('rd', array('id'))
+        ->condition('rd.module', $modules, 'IN')
+        ->condition('rc.dirty', 1);
+  $ids = $query->execute()->fetchCol();
+
+  // If there are some configurations that might work again, re-check all dirty
+  // configurations as others might work again too, e.g. consider a rule that is
+  // dirty because it requires a dirty component.
+  if ($ids) {
+    $rules_configs = rules_config_load_multiple(FALSE, array('dirty' => 1));
+    foreach ($rules_configs as $rules_config) {
+      try {
+        $rules_config->integrityCheck();
+        // If no exceptions were thrown we can set the configuration back to OK.
+        db_update('rules_config')
+          ->fields(array('dirty' => 0))
+          ->condition('id', $rules_config->id)
+          ->execute();
+        if ($rules_config->active) {
+          drupal_set_message(t('All dependencies for the Rules configuration %config are met again, so it has been re-activated.', array('%config' => $rules_config->label())));
+        }
+      }
+      catch (RulesIntegrityException $e) {
+        // The rule is still dirty, so do nothing.
+      }
+    }
+  }
+  rules_clear_cache();
+}
+
+/**
+ * Implements hook_modules_disabled().
+ */
+function rules_modules_disabled($modules) {
+  // Disable Rules configurations that depend on one of the disabled modules.
+  $query = db_select('rules_dependencies', 'rd');
+  $query->join('rules_config', 'rc', 'rd.id = rc.id');
+  $query->fields('rd', array('id'))
+        ->distinct()
+        ->condition('rd.module', $modules, 'IN')
+        ->condition('rc.dirty', 0);
+  $ids = $query->execute()->fetchCol();
+
+  if (!empty($ids)) {
+    db_update('rules_config')
+      ->fields(array('dirty' => 1))
+      ->condition('id', $ids, 'IN')
+      ->execute();
+    // Tell the user about enabled rules that have been marked as dirty.
+    $count = db_select('rules_config', 'r')
+      ->fields('r')
+      ->condition('id', $ids, 'IN')
+      ->condition('active', 1)
+      ->execute()->rowCount();
+    if ($count > 0) {
+      $message = format_plural($count,
+        '1 Rules configuration requires some of the disabled modules to function and cannot be executed any more.',
+        '@count Rules configuration require some of the disabled modules to function and cannot be executed any more.'
+      );
+      drupal_set_message($message, 'warning');
+    }
+  }
+  rules_clear_cache();
+}
+
+/**
+ * Access callback for dealing with Rules configurations.
+ *
+ * @see entity_access()
+ */
+function rules_config_access($op, $rules_config = NULL, $account = NULL) {
+  if (user_access('bypass rules access', $account)) {
+    return TRUE;
+  }
+  // Allow modules to grant / deny access.
+  $access = module_invoke_all('rules_config_access', $op, $rules_config, $account);
+
+  // Only grant access if at least one module granted access and no one denied
+  // access.
+  if (in_array(FALSE, $access, TRUE)) {
+    return FALSE;
+  }
+  elseif (in_array(TRUE, $access, TRUE)) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Implements hook_rules_config_access().
+ */
+function rules_rules_config_access($op, $rules_config = NULL, $account = NULL) {
+  // Instead of returning FALSE return nothing, so others still can grant
+  // access.
+  if (!isset($rules_config) || (isset($account) && $account->uid != $GLOBALS['user']->uid)) {
+    return;
+  }
+  if (user_access('administer rules', $account) && ($op == 'view' || $rules_config->access())) {
+    return TRUE;
+  }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function rules_menu() {
+  $items['admin/config/workflow/rules/upgrade'] = array(
+    'title' => 'Upgrade',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_upgrade_form'),
+    'access arguments' => array('administer rules'),
+    'file' => 'includes/rules.upgrade.inc',
+    'file path' => drupal_get_path('module', 'rules'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/config/workflow/rules/upgrade/clear'] = array(
+    'title' => 'Clear',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_upgrade_confirm_clear_form'),
+    'access arguments' => array('administer rules'),
+    'file' => 'includes/rules.upgrade.inc',
+    'file path' => drupal_get_path('module', 'rules'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['admin/config/workflow/rules/autocomplete_tags'] = array(
+    'title' => 'Rules tags autocomplete',
+    'page callback' => 'rules_autocomplete_tags',
+    'page arguments' => array(5),
+    'access arguments' => array('administer rules'),
+    'file' => 'ui/ui.forms.inc',
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Helper function to keep track of external documentation pages for Rules.
+ *
+ * @param $topic
+ *   The topic key for used for identifying help pages.
+ *
+ * @return
+ *   Either a URL for the given page, or the full list of external help pages.
+ */
+function rules_external_help($topic = NULL) {
+  $help = array(
+    'rules' =>                'http://drupal.org/node/298480',
+    'terminology' =>          'http://drupal.org/node/1299990',
+    'condition-components' => 'http://drupal.org/node/1300034',
+    'data-selection' =>       'http://drupal.org/node/1300042',
+    'chained-tokens' =>       'http://drupal.org/node/1300042',
+    'loops' =>                'http://drupal.org/node/1300058',
+    'components' =>           'http://drupal.org/node/1300024',
+    'component-types' =>      'http://drupal.org/node/1300024',
+    'variables' =>            'http://drupal.org/node/1300024',
+    'scheduler' =>            'http://drupal.org/node/1300068',
+    'coding' =>               'http://drupal.org/node/878720',
+  );
+
+  if (isset($topic)) {
+    return isset($help[$topic]) ? $help[$topic] : FALSE;
+  }
+  return $help;
+}
+
+/**
+ * Implements hook_help().
+ */
+function rules_help($path, $arg) {
+  // Only enable the help if the admin module is active.
+  if ($path == 'admin/help#rules' && module_exists('rules_admin')) {
+
+    $output['header'] = array(
+      '#markup' => t('Rules documentation is kept online. Please use the links below for more information about Rules. Feel free to contribute to improving the online documentation!'),
+    );
+    // Build a list of essential Rules help pages, formatted as a bullet list.
+    $link_list['rules'] = l(t('Rules introduction'), rules_external_help('rules'));
+    $link_list['terminology'] = l(t('Rules terminology'), rules_external_help('terminology'));
+    $link_list['scheduler'] = l(t('Rules Scheduler'), rules_external_help('scheduler'));
+    $link_list['coding'] = l(t('Coding for Rules'), rules_external_help('coding'));
+
+    $output['topic-list'] = array(
+      '#markup' => theme('item_list', array('items' => $link_list)),
+    );
+    return render($output);
+  }
+}
+
+/**
+ * Implements hook_token_info().
+ */
+function rules_token_info() {
+  $cache = rules_get_cache();
+  $data_info = $cache['data_info'];
+
+  $types = array('text', 'integer', 'uri', 'token', 'decimal', 'date', 'duration');
+
+  foreach ($types as $type) {
+    $token_type = $data_info[$type]['token type'];
+
+    $token_info['types'][$token_type] = array(
+      'name' => $data_info[$type]['label'],
+      'description' => t('Tokens related to %label Rules variables.', array('%label' => $data_info[$type]['label'])),
+      'needs-data' => $token_type,
+    );
+    $token_info['tokens'][$token_type]['value'] = array(
+      'name' => t("Value"),
+      'description' => t('The value of the variable.'),
+    );
+  }
+  return $token_info;
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function rules_tokens($type, $tokens, $data, $options = array()) {
+  // Handle replacements of primitive variable types.
+  if (substr($type, 0, 6) == 'rules_' && !empty($data[$type])) {
+    // Leverage entity tokens token processor by passing on as struct.
+    $info['property info']['value'] = array(
+      'type' => substr($type, 6),
+      'label' => '',
+    );
+    // Entity tokens uses metadata wrappers as values for 'struct' types.
+    $wrapper = entity_metadata_wrapper('struct', array('value' => $data[$type]), $info);
+    return entity_token_tokens('struct', $tokens, array('struct' => $wrapper), $options);
+  }
+}
+
+/**
+ * Helper function that retrieves a metadata wrapper with all properties.
+ *
+ * Note that without this helper, bundle-specific properties aren't added.
+ */
+function rules_get_entity_metadata_wrapper_all_properties(RulesAbstractPlugin $element) {
+  return entity_metadata_wrapper($element->settings['type'], NULL, array(
+    'property info alter' => 'rules_entity_metadata_wrapper_all_properties_callback',
+  ));
+}
+
+/**
+ * Callback that returns a metadata wrapper with all properties.
+ */
+function rules_entity_metadata_wrapper_all_properties_callback(EntityMetadataWrapper $wrapper, $property_info) {
+  $info = $wrapper->info();
+  $properties = entity_get_all_property_info($info['type']);
+  $property_info['properties'] += $properties;
+  return $property_info;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file Includes any rules integration provided by the module.
+ */
+
+/**
+ * Load all module includes as soon as this file gets included, which is done
+ * automatically by module_implements().
+ */
+foreach (rules_core_modules() as $module) {
+  module_load_include('inc', 'rules', "modules/$module.rules");
+  module_load_include('inc', 'rules', 'modules/events');
+}
+
+/**
+ * Defines a list of core module on whose behalf we provide module integration.
+ *
+ * We also add a pseudo 'data' module, which will be used for providing generic
+ * rules data integration, 'entity' for entity-related integration and 'rules'
+ * for providing some general stuff.
+ */
+function rules_core_modules() {
+  $return = array('data', 'entity', 'node', 'system', 'user', 'rules_core');
+  foreach (array('comment', 'taxonomy', 'php', 'path') as $module) {
+    if (module_exists($module)) {
+      $return[] = $module;
+    }
+  }
+  return $return;
+}
+
+/**
+ * Returns all items for a hook applying the right module defaults.
+ */
+function _rules_rules_collect_items($hook) {
+  $items = array();
+  foreach (rules_core_modules() as $module) {
+    if (function_exists($function = "rules_{$module}_{$hook}")) {
+      $items += (array) $function();
+    }
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_rules_file_info().
+ */
+function rules_rules_file_info() {
+  $items = array();
+  foreach (rules_core_modules() as $module) {
+    if (function_exists($function = "rules_{$module}_file_info")) {
+      $items = array_merge($items, (array)$function());
+      // Automatically add "$module.rules.inc" for each module.
+      $items[] = 'modules/' . $module . '.rules';
+    }
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_rules_category_info().
+ */
+function rules_rules_category_info() {
+  return _rules_rules_collect_items('category_info');
+}
+
+/**
+ * Implements hook_rules_action_info().
+ */
+function rules_rules_action_info() {
+  return _rules_rules_collect_items('action_info');
+}
+
+/**
+ * Implements hook_rules_condition_info().
+ */
+function rules_rules_condition_info() {
+  return _rules_rules_collect_items('condition_info');
+}
+
+/**
+ * Implements hook_rules_event_info().
+ */
+function rules_rules_event_info() {
+  return _rules_rules_collect_items('event_info');
+}
+
+/**
+ * Implements hook_rules_data_info().
+ */
+function rules_rules_data_info() {
+  return _rules_rules_collect_items('data_info');
+}
+
+/**
+ * Implements hook_rules_data_info_alter().
+ */
+function rules_rules_data_info_alter(&$items) {
+  // For now just invoke the rules core implementation manually.
+  rules_rules_core_data_info_alter($items);
+}
+
+/**
+ * Implements hook_rules_evaluator_info().
+ */
+function rules_rules_evaluator_info() {
+  return _rules_rules_collect_items('evaluator_info');
+}
+
+/**
+ * Implements hook_rules_data_processor_info().
+ */
+function rules_rules_data_processor_info() {
+  return _rules_rules_collect_items('data_processor_info');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_admin/rules_admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,436 @@
+<?php
+
+/**
+ * @file Rules Admin UI
+ *   Implements rule management and configuration screens.
+ */
+
+/**
+ * Reaction rules overview.
+ */
+function rules_admin_reaction_overview($form, &$form_state, $base_path) {
+  RulesPluginUI::formDefaults($form, $form_state);
+
+  $conditions = array('plugin' => 'reaction rule', 'active' => TRUE);
+  $collapsed = TRUE;
+  if (empty($_GET['tag'])) {
+    $tag = 0;
+  }
+  else {
+    $tag = $_GET['tag'];
+    $conditions['tags'] = array($tag);
+    $collapsed = FALSE;
+  }
+  if (empty($_GET['event'])) {
+    $event = 0;
+  }
+  else {
+    $event = $_GET['event'];
+    // Filter using a wildcard suffix so configured event names with suffixes
+    // are found also.
+    $conditions['event'] = $event . '%';
+    $collapsed = FALSE;
+  }
+  $form['help'] = array(
+    '#type' => 'markup',
+    '#markup' => t('Reaction rules, listed below, react on selected events on the site. Each reaction rule may fire any number of <em>actions</em>, and may have any number of <em>conditions</em> that must be met for the actions to be executed. You can also set up <a href="@url1">components</a> – stand-alone sets of Rules configuration that can be used in Rules and other parts of your site. See <a href="@url2">the online documentation</a> for an introduction on how to use Rules.',
+      array('@url1' => url('admin/config/workflow/rules/components'),
+            '@url2' => rules_external_help('rules'))),
+  );
+
+  $form['filter'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Filter'),
+    '#collapsible' => TRUE,
+  );
+  $form['filter']['#id'] = 'rules-filter-form';
+  $form['filter']['#attached']['css'][] = drupal_get_path('module', 'rules') . '/ui/rules.ui.css';
+  $form['filter']['event'] = array(
+    '#type' => 'select',
+    '#title' => t('Filter by event'),
+    '#options' => array(0 => t('<All>')) + RulesPluginUI::getOptions('event'),
+    '#default_value' => $event,
+  );
+  $form['filter']['tag'] = array(
+    '#type' => 'select',
+    '#title' => t('Filter by tag'),
+    '#options' => array(0 => t('<All>')) + RulesPluginUI::getTags(),
+    '#default_value' => $tag,
+  );
+  $form['filter']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Filter'),
+    '#name' => '', // prevent from showing up in $_GET.
+  );
+
+  $options = array('show plugin' => FALSE, 'base path' => $base_path);
+  $form['active'] = rules_ui()->overviewTable($conditions, $options);
+  $form['active']['#caption'] = t('Active rules');
+  $form['active']['#empty'] = t('There are no active rules. <a href="!url">Add new rule</a>.', array('!url' => url('admin/config/workflow/rules/reaction/add')));
+
+  $conditions['active'] = FALSE;
+  $form['inactive'] = rules_ui()->overviewTable($conditions, $options);
+  $form['inactive']['#caption'] = t('Inactive rules');
+  $form['inactive']['#empty'] = t('There are no inactive rules.');
+
+  $form['filter']['#collapsed'] = $collapsed;
+  $form['#submit'][] = 'rules_form_submit_rebuild';
+  $form['#method'] = 'get';
+  return $form;
+}
+
+/**
+ * Components overview.
+ */
+function rules_admin_components_overview($form, &$form_state, $base_path) {
+  RulesPluginUI::formDefaults($form, $form_state);
+
+  $collapsed = TRUE;
+  if (empty($_GET['tag'])) {
+    $tag = 0;
+  }
+  else {
+    $tag = $_GET['tag'];
+    $conditions['tags'] = array($tag);
+    $collapsed = FALSE;
+  }
+  if (empty($_GET['plugin'])) {
+    // Get the plugin name usable as component.
+    $conditions['plugin'] = array_keys(rules_filter_array(rules_fetch_data('plugin_info'), 'component', TRUE));
+    $plugin = 0;
+  }
+  else {
+    $plugin = $_GET['plugin'];
+    $conditions['plugin'] = $plugin;
+    $collapsed = FALSE;
+  }
+  $form['help'] = array(
+    '#type' => 'markup',
+    '#markup' => t('Components are stand-alone sets of Rules configuration that can be used by Rules and other modules on your site. Components are for example useful if you want to use the same conditions, actions or rules in multiple places, or call them from your custom module. You may also export each component separately. See <a href="@url">the online documentation</a> for more information about how to use components.',
+      array('@url' => rules_external_help('components'))),
+  );
+  $form['filter'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Filter'),
+    '#collapsible' => TRUE,
+  );
+  $form['filter']['#id'] = 'rules-filter-form';
+  $form['filter']['#attached']['css'][] = drupal_get_path('module', 'rules') . '/ui/rules.ui.css';
+  $form['filter']['plugin'] = array(
+    '#type' => 'select',
+    '#title' => t('Filter by plugin'),
+    '#options' => array(0 => t('<All>')) + rules_admin_component_options(),
+    '#default_value' => $plugin,
+  );
+  $form['filter']['tag'] = array(
+    '#type' => 'select',
+    '#title' => t('Filter by tag'),
+    '#options' => array(0 => '<All>') + RulesPluginUI::getTags(),
+    '#default_value' => $tag,
+  );
+  $form['filter']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Filter'),
+    '#name' => '', // prevent from showing up in $_GET.
+  );
+
+  $form['table'] = RulesPluginUI::overviewTable($conditions, array('hide status op' => TRUE));
+  $form['table']['#empty'] = t('There are no rule components.');
+
+  $form['filter']['#collapsed'] = $collapsed;
+  $form['#submit'][] = 'rules_form_submit_rebuild';
+  $form['#method'] = 'get';
+  return $form;
+}
+
+/**
+ * Rules settings form.
+ */
+function rules_admin_settings($form, &$form_state) {
+
+  if (module_exists('path')) {
+    // Present a list of available path cleaning callbacks.
+    // @see rules_clean_path()
+    $options = array(
+      'rules_path_default_cleaning_method' => t('Rules (built in)'),
+    );
+    if (module_exists('ctools')) {
+      $options['rules_path_clean_ctools'] = t('CTools');
+    }
+    if (module_exists('pathauto')) {
+      $options['rules_path_clean_pathauto'] = t('Pathauto');
+      $pathauto_help = t("Note that Pathauto's URL path cleaning method can be configured at <a href='!url'>admin/config/search/path/settings</a>.", array('!url' => url('admin/config/search/path/settings')));
+    }
+    else {
+      $pathauto_help = t('Install the <a href="http://drupal.org/project/pathauto">Pathauto module</a> in order to get a configurable URL path cleaning method.');
+    }
+
+    $form['path']['rules_path_cleaning_callback'] = array(
+      '#type' => 'select',
+      '#title' => t('URL path cleaning method'),
+      '#description' => t('Choose the path cleaning method to be applied when generating URL path aliases.') . ' ' . $pathauto_help,
+      '#default_value' => variable_get('rules_path_cleaning_callback', 'rules_path_default_cleaning_method'),
+      '#options' => $options,
+    );
+  }
+
+  $form['rules_log_errors'] = array(
+    '#type' => 'radios',
+    '#title' => t('Logging of Rules evaluation errors'),
+    '#options' => array(
+      RulesLog::WARN => t('Log all warnings and errors'),
+      RulesLog::ERROR => t('Log errors only'),
+    ),
+    '#default_value' => variable_get('rules_log_errors', RulesLog::WARN),
+    '#description' => t('Evaluations errors are logged to the system log.'),
+  );
+
+  $form['debug'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Debugging'),
+  );
+  $form['debug']['rules_debug_log'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Log debug information to the system log'),
+    '#default_value' => variable_get('rules_debug_log', 0),
+  );
+  $form['debug']['rules_debug'] = array(
+    '#type' => 'radios',
+    '#title' => t('Show debug information'),
+    '#default_value' => variable_get('rules_debug', 0),
+    '#options' => array(
+      0 => t('Never'),
+      RulesLog::WARN => t('In case of errors'),
+      RulesLog::INFO => t('Always'),
+    ),
+    '#description' => t('Debug information is only shown when rules are evaluated and is visible for users having the permission <a href="!url">%link</a>.', array('%link' => t('Access the Rules debug log'), '!url' => url('admin/people/permissions', array('fragment' => 'module-rules')))),
+  );
+
+  $form['debug']['regions'] = array(
+    '#type' => 'container',
+    '#states' => array(
+      // Hide the regions settings when the debug log is disabled.
+      'invisible' => array(
+        'input[name="rules_debug"]' => array('value' => '0'),
+      ),
+    ),
+  );
+
+  $theme_default = variable_get('theme_default', 'bartik');
+  $admin_theme = variable_get('admin_theme', 'seven');
+
+  $form['debug']['regions']['rules_debug_region_' . $theme_default] = array(
+    '#type' => 'select',
+    '#title' => t('Default theme region'),
+    '#description' => t("The region, where the debug log should be displayed on the default theme %theme. For other themes, Rules will try to display the log on the same region, or hide it in case it doesn't exist.", array('%theme' => $theme_default)),
+    '#options' => system_region_list($theme_default, REGIONS_VISIBLE),
+    '#default_value' => variable_get('rules_debug_region_' . $theme_default, 'help'),
+  );
+
+  $form['debug']['regions']['rules_debug_region_' . $admin_theme] = array(
+    '#type' => 'select',
+    '#title' => t('Admin theme region'),
+    '#description' => t('The region, where the debug log should be displayed on the admin theme %theme.', array('%theme' => $admin_theme)),
+    '#options' => system_region_list($admin_theme, REGIONS_VISIBLE),
+    '#default_value' => variable_get('rules_debug_region_' . $admin_theme, 'help'),
+  );
+  if (db_table_exists('rules_rules')) {
+    drupal_set_message(t('There are left over rule configurations from a previous Rules 1.x installation. Proceed to the <a href="!url">upgrade page</a> to convert them and consult the README.txt for more details.', array('!url' => url('admin/config/workflow/rules/upgrade'))), 'warning');
+  }
+
+  return system_settings_form($form);
+}
+
+/**
+ * Advanced settings form.
+ */
+function rules_admin_settings_advanced($form, &$form_state) {
+
+  $form['integrity'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Integrity'),
+    '#description' => t('Rules checks the integrity of your configurations to discover and exclude broken configurations from evaluation.'),
+  );
+  $form['integrity']['start_integrity_check'] = array(
+    '#type' => 'submit',
+    '#value' => t('Recheck integrity'),
+    '#submit' => array('rules_admin_settings_integrity_check_submit'),
+  );
+  $form['cache'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Cache'),
+    '#description' => t('Rules caches information about available actions, conditions and data types. Additionally all components and reaction rules are cached for efficient evaluation.'),
+  );
+  $form['cache']['rebuild_rules_cache'] = array(
+    '#type' => 'submit',
+    '#value' => t("Rebuild Rules' cache"),
+    '#weight' => 2,
+    '#submit' => array('rules_admin_settings_cache_rebuild_submit'),
+  );
+  return $form;
+}
+
+/**
+ * Form submit callback to check the integrity of all configurations.
+ */
+function rules_admin_settings_integrity_check_submit($form, &$form_state) {
+  $start = microtime(TRUE);
+  $count = 0;
+  $rules_configs = rules_config_load_multiple(FALSE);
+  foreach ($rules_configs as $rules_config) {
+    rules_config_update_dirty_flag($rules_config, TRUE, TRUE);
+    if ($rules_config->dirty) {
+      $count++;
+      $variables = array('%label' => $rules_config->label(), '%name' => $rules_config->name, '@plugin' => $rules_config->plugin(), '!uri'=> url(RulesPluginUI::path($rules_config->name)));
+      drupal_set_message(t('The @plugin <a href="!uri">%label (%name)</a> fails the integrity check and cannot be executed.', $variables), 'error');
+    }
+
+  }
+  drupal_set_message(t('Integrity of %count configurations checked in %duration seconds. %count_failed broken configurations found.', array(
+    '%count' => count($rules_configs),
+    '%count_failed' => $count,
+    '%duration' => round(microtime(TRUE) - $start, 2),
+  )));
+}
+
+/**
+ * Form submit callback: Rebuild the Rules' cache.
+ */
+function rules_admin_settings_cache_rebuild_submit($form, &$form_state) {
+  $start = microtime(TRUE);
+  rules_clear_cache();
+  // Manually trigger cache rebuilding of all caches.
+  rules_get_cache();
+  _rules_rebuild_component_cache();
+  RulesEventSet::rebuildEventCache();
+  drupal_set_message(t('Rules cache rebuilt in %duration seconds.', array(
+    '%duration' => round(microtime(TRUE) - $start, 2),
+  )));
+}
+
+/**
+ * Add reaction rules form.
+ */
+function rules_admin_add_reaction_rule($form, &$form_state, $base_path) {
+  RulesPluginUI::formDefaults($form, $form_state);
+
+  $rules_config = isset($form_state['rules_config']) ? $form_state['rules_config'] : rules_reaction_rule();
+  $rules_config->form($form, $form_state, array('show settings' => TRUE, 'button' => TRUE));
+
+  $form['settings']['#collapsible'] = FALSE;
+  $form['settings']['#type'] = 'container';
+  $form['settings']['label']['#default_value'] = '';
+
+  // Hide the rule elements stuff for now.
+  foreach (array('elements', 'conditions', 'add', 'events') as $key) {
+    $form[$key]['#access'] = FALSE;
+  }
+  foreach (array('active', 'weight') as $key) {
+    $form['settings'][$key]['#access'] = FALSE;
+  }
+  // Incorporate the form to add the first event.
+  $form['settings'] += rules_ui_add_event(array(), $form_state, $rules_config, $base_path);
+  $form['settings']['event']['#tree'] = FALSE;
+  $form['settings']['event_settings']['#tree'] = FALSE;
+  unset($form['settings']['help']);
+
+  unset($form['settings']['submit']);
+  $form['submit']['#value'] = t('Save');
+
+  $form_state += array('rules_config' => $rules_config);
+  $form['#validate'][] = 'rules_ui_add_reaction_rule_validate';
+  $form['#validate'][] = 'rules_ui_edit_element_validate';
+  $form['#submit'][] = 'rules_ui_add_reaction_rule_submit';
+  return $form;
+}
+
+/**
+ * Form validation callback.
+ */
+function rules_ui_add_reaction_rule_validate(&$form, &$form_state) {
+  rules_ui_add_event_validate($form['settings'], $form_state);
+}
+
+/**
+ * Form submit callback.
+ */
+function rules_ui_add_reaction_rule_submit(&$form, &$form_state) {
+  rules_ui_add_event_apply($form['settings'], $form_state);
+  rules_ui_edit_element_submit($form, $form_state);
+}
+
+/**
+ * Add component form.
+ */
+function rules_admin_add_component($form, &$form_state, $base_path) {
+  RulesPluginUI::$basePath = $base_path;
+  RulesPluginUI::formDefaults($form, $form_state);
+
+  $form['plugin_name'] = array(
+    '#type' => 'select',
+    '#title' => t('Component plugin'),
+    '#options' => rules_admin_component_options(),
+    '#description' => t('Choose which kind of component to create. Each component type is described in <a href="@url">the online documentation</a>.',
+      array('@url' => rules_external_help('component-types'))),
+    '#weight' => -2,
+    '#default_value' => isset($form_state['values']['plugin_name']) ? $form_state['values']['plugin_name'] : '',
+  );
+
+  if (!isset($form_state['rules_config'])) {
+    $form['continue'] = array(
+      '#type' => 'submit',
+      '#name' => 'continue',
+      '#submit' => array('rules_admin_add_component_create_submit'),
+      '#value' => t('Continue'),
+    );
+  }
+  else {
+    $form['plugin_name']['#disabled'] = TRUE;
+    $form_state['rules_config']->form($form, $form_state, array('show settings' => TRUE, 'button' => TRUE, 'init' => TRUE));
+    $form['settings']['#collapsible'] = FALSE;
+    $form['settings']['#type'] = 'container';
+    $form['settings']['label']['#default_value'] = '';
+    $form['settings']['#weight'] = -1;
+
+    // Hide the rule elements stuff for now.
+    foreach (array('elements', 'negate') as $key) {
+      $form[$key]['#access'] = FALSE;
+    }
+    foreach (array('active', 'weight') as $key) {
+      $form['settings'][$key]['#access'] = FALSE;
+    }
+  }
+  return $form;
+}
+
+function rules_admin_component_options() {
+  $cache = rules_get_cache();
+  return rules_extract_property(rules_filter_array($cache['plugin_info'], 'component', TRUE), 'label');
+}
+
+/**
+ * Submit callback that creates the new component object initially.
+ */
+function rules_admin_add_component_create_submit($form, &$form_state) {
+  $form_state['rules_config'] = rules_plugin_factory($form_state['values']['plugin_name']);
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Validation callback for adding a component.
+ */
+function rules_admin_add_component_validate($form, &$form_state) {
+  if (isset($form_state['rules_config'])) {
+    $form_state['rules_config']->form_validate($form, $form_state);
+  }
+}
+
+/**
+ * Final submit callback for adding a component.
+ */
+function rules_admin_add_component_submit($form, &$form_state) {
+  $rules_config = $form_state['rules_config'];
+  $rules_config->form_submit($form, $form_state);
+  drupal_set_message(t('Your changes have been saved.'));
+  $form_state['redirect'] = RulesPluginUI::path($rules_config->name);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_admin/rules_admin.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Rules UI
+description = Administrative interface for managing rules.
+package = Rules
+core = 7.x
+files[] = rules_admin.module
+files[] = rules_admin.inc
+dependencies[] = rules
+
+; Information added by drupal.org packaging script on 2013-09-16
+version = "7.x-2.4"
+core = "7.x"
+project = "rules"
+datestamp = "1379354606"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_admin/rules_admin.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * @file Rules Admin UI
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function rules_admin_menu() {
+  // Reaction rules UI menu entries.
+  $reaction_path = 'admin/config/workflow/rules/reaction';
+  $items = rules_ui()->config_menu($reaction_path);
+
+  $items[$reaction_path] = array(
+    'title' => 'Rules',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -1,
+  );
+  $items[$reaction_path . '/add'] = array(
+    'title' => 'Add new rule',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_admin_add_reaction_rule', $reaction_path),
+    'access arguments' => array('administer rules'),
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'rules_admin.inc',
+    'weight' => 0,
+  );
+  $items[$reaction_path . '/import'] = array(
+    'title' => 'Import rule',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_ui_import_form', $reaction_path),
+    'access arguments' => array('administer rules'),
+    'file' => 'ui/ui.forms.inc',
+    'file path' => drupal_get_path('module', 'rules'),
+    'type' => MENU_LOCAL_ACTION,
+  );
+
+  // Components UI menu entries.
+  $component_path = 'admin/config/workflow/rules/components';
+  $items += rules_ui()->config_menu($component_path);
+  $items[$component_path] = array(
+    'title' => 'Components',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_admin_components_overview', $component_path),
+    'access arguments' => array('administer rules'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'rules_admin.inc',
+    'weight' => 0,
+  );
+  $items[$component_path . '/add'] = array(
+    'title' => 'Add new component',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_admin_add_component', $component_path),
+    'access arguments' => array('administer rules'),
+    'type' => MENU_LOCAL_ACTION,
+    'file' => 'rules_admin.inc',
+    'weight' => 0,
+  );
+  $items[$component_path . '/import'] = array(
+    'title' => 'Import component',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_ui_import_form', $component_path),
+    'access arguments' => array('administer rules'),
+    'file' => 'ui/ui.forms.inc',
+    'file path' => drupal_get_path('module', 'rules'),
+    'type' => MENU_LOCAL_ACTION,
+  );
+
+  // Some general rules admin menu items.
+  $items['admin/config/workflow/rules'] = array(
+    'title' => 'Rules',
+    'position' => 'right',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_admin_reaction_overview', $reaction_path),
+    'description' => 'Manage reaction rules and rule components.',
+    'access arguments' => array('administer rules'),
+    'file' => 'rules_admin.inc',
+  );
+  $items['admin/config/workflow/rules/settings'] = array(
+    'title' => 'Settings',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_admin_settings'),
+    'access arguments' => array('administer rules'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => 'rules_admin.inc',
+    'weight' => 1,
+  );
+  $items['admin/config/workflow/rules/settings/basic'] = array(
+    'title' => 'Basic',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/config/workflow/rules/settings/advanced'] = array(
+    'title' => 'Advanced',
+    'type' => MENU_LOCAL_TASK,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_admin_settings_advanced'),
+    'access arguments' => array('administer rules'),
+    'file' => 'rules_admin.inc',
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_form_alter().
+ *
+ * Since the overview forms are GET forms, we don't want them to send a wide
+ * variety of information. We need to use hook_form_alter() because the
+ * properties are added after form creation.
+ */
+function rules_admin_form_alter(&$form, &$form_state, $form_id) {
+  if ($form_id == 'rules_admin_reaction_overview' || $form_id == 'rules_admin_components_overview') {
+    $form['form_build_id']['#access'] = FALSE;
+    $form['form_token']['#access'] = FALSE;
+    $form['form_id']['#access'] = FALSE;
+  }
+}
+
+/**
+ * Implements hook_system_info_alter().
+ *
+ * Adds configuration links for Rules and Rules Scheduler in the modules list.
+ * (This is done by the Rules UI module, without which there would be no
+ * configuration pages to visit.)
+ */
+function rules_admin_system_info_alter(&$info, $file, $type) {
+  if ($file->name == 'rules') {
+    $info['configure'] = 'admin/config/workflow/rules';
+  }
+  if ($file->name == 'rules_scheduler') {
+    $info['configure'] = 'admin/config/workflow/rules/schedule';
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_i18n/rules_i18n.i18n.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * @file
+ * Internationalization integration based upon the entity API i18n stuff.
+ */
+
+/**
+ * Rules i18n integration controller.
+ */
+class RulesI18nStringController extends EntityDefaultI18nStringController {
+
+  /**
+   * Overriden to customize i18n object info.
+   *
+   * @see EntityDefaultI18nStringController::hook_object_info()
+   */
+  public function hook_object_info() {
+    $info = parent::hook_object_info();
+    $info['rules_config']['class'] = 'RulesI18nStringObjectWrapper';
+    return $info;
+  }
+
+  /**
+   * Overriden to customize the used menu wildcard.
+   */
+  protected function menuWildcard() {
+    return '%rules_config';
+  }
+
+  /**
+   * Provide the menu base path. We can provide only one though.
+   */
+  protected function menuBasePath() {
+    return 'admin/config/workflow/rules/reaction';
+  }
+}
+
+/**
+ * Custom I18n String object wrapper, which register custom properties per config.
+ */
+class RulesI18nStringObjectWrapper extends i18n_string_object_wrapper {
+
+  /**
+   * Get translatable properties
+   */
+  protected function build_properties() {
+    $strings = parent::build_properties();
+    $properties = array();
+
+    // Also add in the configuration label, as the i18n String UI requires
+    // a String to be available always.
+    $properties['label'] = array(
+      'title' => t('Configuration name'),
+      'string' => $this->object->label,
+    );
+
+    $this->buildElementProperties($this->object, $properties);
+
+    // Add in translations for all elements.
+    foreach ($this->object->elements() as $element) {
+      $this->buildElementProperties($element, $properties);
+    }
+    $strings[$this->get_textgroup()]['rules_config'][$this->object->name] = $properties;
+    return $strings;
+  }
+
+  /**
+   * Adds in translatable properties of the given element.
+   */
+  protected function buildElementProperties($element, &$properties) {
+
+    foreach ($element->pluginParameterInfo() as $name => $info) {
+      // Add in all directly provided input variables.
+      if (!empty($info['translatable']) && isset($element->settings[$name])) {
+        // If its an array of textual values, translate each value on its own.
+        if (is_array($element->settings[$name])) {
+          foreach ($element->settings[$name] as $i => $value) {
+            $properties[$element->elementId() . ':' . $name . ':' . $i] = array(
+              'title' => t('@plugin "@label" (id @id), @parameter, Value @delta', array('@plugin' => drupal_ucfirst($element->plugin()), '@label' => $element->label(), '@id' => $element->elementId(), '@parameter' => $info['label'], '@delta' => $i + 1)),
+              'string' => $value,
+            );
+          }
+        }
+        else {
+          $properties[$element->elementId() . ':' . $name] = array(
+            'title' => t('@plugin "@label" (id @id), @parameter', array('@plugin' => drupal_ucfirst($element->plugin()), '@label' => $element->label(), '@id' => $element->elementId(), '@parameter' => $info['label'])),
+            'string' => $element->settings[$name],
+          );
+        }
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_i18n/rules_i18n.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+name = Rules translation
+description = Allows translating rules.
+dependencies[] = rules
+dependencies[] = i18n_string
+package = Multilingual - Internationalization
+core = 7.x
+files[] = rules_i18n.i18n.inc
+files[] = rules_i18n.rules.inc
+files[] = rules_i18n.test
+; Information added by drupal.org packaging script on 2013-09-16
+version = "7.x-2.4"
+core = "7.x"
+project = "rules"
+datestamp = "1379354606"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_i18n/rules_i18n.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * @file
+ * Rules i18n integration.
+ */
+
+
+/**
+ * Implements hook_menu().
+ */
+function rules_i18n_rules_ui_menu_alter(&$items, $base_path, $base_count) {
+
+  $items[$base_path . '/manage/%rules_config/edit'] = array(
+    'title' => 'Edit',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -100,
+  );
+
+  // For reaction-rules i18n generates the menu items, for the others we provide
+  // further i18n menu items for all other base paths.
+
+  if ($base_path != 'admin/config/workflow/rules/reaction') {
+
+    $items[$base_path . '/manage/%rules_config/translate'] = array(
+      'title' => 'Translate',
+      'page callback' => 'i18n_page_translate_localize',
+      'page arguments' => array('rules_config', $base_count + 1),
+      'access callback' => 'i18n_object_translate_access',
+      'access arguments' => array('rules_config', $base_count + 1),
+      'type' => MENU_LOCAL_TASK,
+      'file' => 'i18n.pages.inc',
+      'file path' => drupal_get_path('module', 'i18n'),
+      'weight' => 10,
+    );
+
+    $items[$base_path . '/manage/%rules_config/translate/%i18n_language'] = array(
+      'title' => 'Translate',
+      'page callback' => 'i18n_page_translate_localize',
+      'page arguments' => array('rules_config', $base_count + 1, $base_count + 3),
+      'access callback' => 'i18n_object_translate_access',
+      'access arguments' => array('rules_config', $base_count),
+      'type' => MENU_CALLBACK,
+      'file' => 'i18n.pages.inc',
+      'file path' => drupal_get_path('module', 'i18n'),
+      'weight' => 10,
+    );
+  }
+}
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function rules_i18n_entity_info_alter(&$info) {
+  // Enable i18n support via the entity API.
+  $info['rules_config']['i18n controller class'] = 'RulesI18nStringController';
+}
+
+/**
+ * Implements hook_rules_config_insert().
+ */
+function rules_i18n_rules_config_insert($rules_config) {
+  // Do nothing when rebuilding defaults to avoid multiple cache rebuilds.
+  // @see rules_i18n_rules_config_defaults_rebuild()
+  if (!empty($rules_config->is_rebuild)) {
+    return;
+  }
+
+  i18n_string_object_update('rules_config', $rules_config);
+}
+
+/**
+ * Implements hook_rules_config_update().
+ */
+function rules_i18n_rules_config_update($rules_config, $original = NULL) {
+  // Do nothing when rebuilding defaults to avoid multiple cache rebuilds.
+  // @see rules_i18n_rules_config_defaults_rebuild()
+  if (!empty($rules_config->is_rebuild)) {
+    return;
+  }
+  $original = $original ? $original : $rules_config->original;
+
+  // Account for name changes.
+  if ($original->name != $rules_config->name) {
+    i18n_string_update_context("rules:rules_config:{$original->name}:*", "rules:rules_config:{$rules_config->name}:*");
+  }
+
+  // We need to remove the strings of any disappeared properties, i.e. strings
+  // from translatable parameters of deleted actions.
+
+  // i18n_object() uses a static cache per config, so bypass it to wrap the
+  // original entity.
+  $object_key = i18n_object_key('rules_config', $original);
+  $old_i18n_object = new RulesI18nStringObjectWrapper('rules_config', $object_key, $original);
+  $old_strings = $old_i18n_object->get_strings(array('empty' => TRUE));
+
+  // Note: For the strings to have updated values, the updated entity needs to
+  // be handled last due to i18n's cache.
+  $strings = i18n_object('rules_config', $rules_config)->get_strings(array('empty' => TRUE));
+
+  foreach (array_diff_key($old_strings, $strings) as $name => $string) {
+    $string->remove(array('empty' => TRUE));
+  }
+  // Now update the remaining strings.
+  foreach ($strings as $string) {
+    $string->update(array('empty' => TRUE, 'update' => TRUE));
+  }
+}
+
+/**
+ * Implements hook_rules_config_delete().
+ */
+function rules_i18n_rules_config_delete($rules_config) {
+  i18n_string_object_remove('rules_config', $rules_config);
+}
+
+/**
+ * Implements hook_rules_config_defaults_rebuild().
+ */
+function rules_i18n_rules_config_defaults_rebuild($rules_configs, $originals) {
+  // Once all defaults have been rebuilt, update all i18n strings at once. That
+  // way we build the rules cache once the rebuild is complete and avoid
+  // rebuilding caches for each updated rule.
+  foreach ($rules_configs as $name => $rule_config) {
+    if (empty($originals[$name])) {
+      rules_i18n_rules_config_insert($rule_config);
+    }
+    else {
+      rules_i18n_rules_config_update($rule_config, $originals[$name]);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_i18n/rules_i18n.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,196 @@
+<?php
+
+/**
+ * @file
+ * Internationalization rules integration.
+ */
+
+/**
+ * Implements hook_rules_action_info().
+ */
+function rules_i18n_rules_action_info() {
+  $items['rules_i18n_t'] = array(
+    'label' => t('Translate a text'),
+    'group' => t('Translation'),
+    'parameter' => array(
+      'text' => array(
+        'type' => 'text',
+        'label' => t('Text'),
+        'description' => t('The text to translate.'),
+        'translatable' => TRUE,
+      ),
+      'language' => array(
+        'type' => 'token',
+        'label' => t('Language'),
+        'description' => t('The language to translate the text into.'),
+        'options list' => 'entity_metadata_language_list',
+        'default mode' => 'select',
+      ),
+    ),
+    'provides' => array(
+      'text' => array('type' => 'text', 'label' => t('The translated text')),
+    ),
+    'base' => 'rules_i18n_action_t',
+    'access callback' => 'rules_i18n_rules_integration_access',
+  );
+  $items['rules_i18n_select'] = array(
+    'label' => t('Select a translated value'),
+    'group' => t('Translation'),
+    'parameter' => array(
+      'data' => array(
+        'type' => '*',
+        'label' => t('Data'),
+        'description' => t('Select a translated value, e.g. a translatable field. If the selected data is not translatable, the language neutral value will be selected.'),
+        'translatable' => TRUE,
+        'restrict' => 'select',
+      ),
+      'language' => array(
+        'type' => 'token',
+        'label' => t('Language'),
+        'description' => t('The language to translate the value into.'),
+        'options list' => 'entity_metadata_language_list',
+      ),
+    ),
+    'provides' => array(
+      'data_translated' => array('type' => '*', 'label' => t('The translated value')),
+    ),
+    'base' => 'rules_i18n_action_select',
+    'access callback' => 'rules_i18n_rules_integration_access',
+  );
+  return $items;
+}
+
+/**
+ * Access callback for the rules i18n integration.
+ */
+function rules_i18n_rules_integration_access() {
+  return user_access('translate interface');
+}
+
+/**
+ * Action callback: Translate a text.
+ */
+function rules_i18n_action_t($text) {
+  // Nothing to do, as our input evaluator has already translated it.
+  // @see RulesI18nStringEvaluator
+  return array('text' => $text);
+}
+
+/**
+ * Implements the form_alter callback for the "Translate a text" action to set a default selector.
+ */
+function rules_i18n_action_t_form_alter(&$form, &$form_state, $options, $element) {
+  if (isset($form['parameter']['language']['settings']['language:select']) && empty($element->settings['language:select'])) {
+    $form['parameter']['language']['settings']['language:select']['#default_value'] = 'site:current-page:language';
+  }
+}
+
+/**
+ * Action callback: Select a translated value.
+ */
+function rules_i18n_action_select($data) {
+  // Nothing to do, as Rules applies the language to the data selector for us.
+  return array('data_translated' => $data);
+}
+
+/**
+ * Action "Select a translated value" info_alter callback.
+ */
+function rules_i18n_action_select_info_alter(&$element_info, $element) {
+  $element->settings += array('data:select' => NULL);
+  if ($wrapper = $element->applyDataSelector($element->settings['data:select'])) {
+    $info = $wrapper->info();
+    // Pass through the data type of the selected data.
+    $element_info['provides']['data_translated']['type'] = $wrapper->type();
+  }
+}
+
+/**
+ * Implements hook_rules_evaluator_info().
+ */
+function rules_i18n_rules_evaluator_info() {
+  return array(
+    'i18n' => array(
+      'class' => 'RulesI18nStringEvaluator',
+      'type' => array('text', 'list<text>', 'token', 'list<token>'),
+      // Be sure to translate after doing PHP evaluation.
+      'weight' => -8,
+     ),
+  );
+}
+
+/**
+ * A class implementing a rules input evaluator processing tokens.
+ */
+class RulesI18nStringEvaluator extends RulesDataInputEvaluator {
+
+  public static function access() {
+    return user_access('translate admin strings');
+  }
+
+  public function prepare($text, $var_info, $param_info = NULL) {
+    if (!empty($param_info['translatable'])) {
+      $this->setting = TRUE;
+    }
+    else {
+      // Else, skip this evaluator.
+      $this->setting = NULL;
+    }
+  }
+
+  /**
+   * Prepare the i18n-context string.
+   *
+   * We have to use process() here instead of evaluate() because we need more
+   * context than evaluate() provides.
+   */
+  public function process($value, $info, RulesState $state, RulesPlugin $element, $options = NULL) {
+    $options = isset($options) ? $options : $this->getEvaluatorOptions($info, $state, $element);
+    $value = isset($this->processor) ? $this->processor->process($value, $info, $state, $element, $options) : $value;
+    if (isset($element->root()->name)) {
+      $config_name = $element->root()->name;
+      $id = $element->elementId();
+      $name = $info['#name'];
+      $options['i18n context'] = "rules:rules_config:$config_name:$id:$name";
+      return $this->evaluate($value, $options, $state);
+    }
+    return $value;
+  }
+
+  /**
+   * Translate the value.
+   *
+   * If the element provides a language parameter, we are using this target
+   * language provided via $options['language']. Sanitizing is handled by Rules,
+   * so disable that for i18n.
+   */
+  public function evaluate($value, $options, RulesState $state) {
+    $langcode = isset($options['language']) ? $options['language']->language : NULL;
+    if (is_array($value)) {
+      foreach ($value as $key => $text) {
+        $value[$key] = i18n_string($options['i18n context'] . ':' . $key, $text, array('langcode' => $langcode, 'sanitize' => FALSE));
+      }
+    }
+    else {
+      $value = i18n_string($options['i18n context'], $value, array('langcode' => $langcode, 'sanitize' => FALSE));
+    }
+    return $value;
+  }
+
+  public static function help($var_info, $param_info = array()) {
+    if (!empty($param_info['translatable'])) {
+      if ($param_info['custom translation language']) {
+        $text = t('Translations can be provided at the %translate tab. The argument value is translated to the configured language.', array('%translate' => t('Translate')));
+      }
+      else {
+        $text = t('Translations can be provided at the %translate tab. The argument value is translated to the current interface language.', array('%translate' => t('Translate')));
+      }
+      $render = array(
+        '#theme' => 'rules_settings_help',
+        '#text' => $text,
+        '#heading' => t('Translation'),
+      );
+      return $render;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_i18n/rules_i18n.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,183 @@
+<?php
+
+/**
+ * @file
+ * Rules i18n tests.
+ */
+
+/**
+ * Test the i18n integration.
+ */
+class RulesI18nTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Rules I18n',
+      'description' => 'Tests translating Rules configs.',
+      'group' => 'Rules',
+      'dependencies' => array('i18n_string'),
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('rules_i18n');
+    $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages'));
+    $this->drupalLogin($this->admin_user);
+    $this->addLanguage('de');
+  }
+
+  /**
+   * Copied from i18n module (class Drupali18nTestCase).
+   *
+   * We cannot extend from Drupali18nTestCase as else the test-bot would die.
+   */
+  public function addLanguage($language_code) {
+    // Check to make sure that language has not already been installed.
+    $this->drupalGet('admin/config/regional/language');
+
+    if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
+      // Doesn't have language installed so add it.
+      $edit = array();
+      $edit['langcode'] = $language_code;
+      $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+      // Make sure we are not using a stale list.
+      drupal_static_reset('language_list');
+      $languages = language_list('language');
+      $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
+
+      if (array_key_exists($language_code, $languages)) {
+        $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
+      }
+    }
+    elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $language_code . ']'))) {
+      // It's installed and enabled. No need to do anything.
+      $this->assertTrue(true, 'Language [' . $language_code . '] already installed and enabled.');
+    }
+    else {
+      // It's installed but not enabled. Enable it.
+      $this->assertTrue(true, 'Language [' . $language_code . '] already installed.');
+      $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
+      $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
+    }
+  }
+
+  /**
+   * Tests translating rules configs.
+   */
+  public function testRulesConfigTranslation() {
+    // Create a rule and translate it.
+    $rule = rule();
+    $rule->label = 'label-en';
+    $rule->action('drupal_message', array('message' => 'English message for [site:current-user].'));
+    $rule->save();
+
+    $actions = $rule->actions();
+    $id = $actions[0]->elementId();
+
+    // Add a translation.
+    i18n_string_textgroup('rules')->update_translation("rules_config:{$rule->name}:label", 'de', 'label-de');
+    i18n_string_textgroup('rules')->update_translation("rules_config:{$rule->name}:$id:message", 'de', 'German message für [site:current-user].');
+
+    // Execute the Rule and make sure the translated message has been output.
+    // To do so, set the global language to German.
+    $languages = language_list();
+    $GLOBALS['language'] = $languages['de'];
+
+    // Clear messages and execute the rule.
+    i18n_string_textgroup('rules')->cache_reset();
+    drupal_get_messages();
+    $rule->execute();
+
+    $messages = drupal_get_messages();
+    $this->assertEqual($messages['status'][0], 'German message für ' . $GLOBALS['user']->name . '.', 'Translated message has been output.');
+
+    // Test re-naming the rule.
+    $rule->name = 'rules_i18n_name_2';
+    $rule->save();
+    $translation = entity_i18n_string("rules:rules_config:{$rule->name}:label", $rule->label, 'de');
+    $this->assertEqual($translation, 'label-de', 'Translation survives a name change.');
+
+    // Test updating and make sure the translation stays.
+    $rule->label = 'Label new';
+    $rule->save();
+    $translation = entity_i18n_string("rules:rules_config:{$rule->name}:label", $rule->label, 'de');
+    $this->assertEqual($translation, 'label-de', 'Translation survives an update.');
+
+    // Test deleting the action and make sure the string is deleted too.
+    $actions[0]->delete();
+    $rule->save();
+    $translation = entity_i18n_string("rules_config:{$rule->name}:$id:message", 'English message for [site:current-user].', 'de');
+    $this->assertEqual($translation, 'English message for [site:current-user].', 'Translation of deleted action has been deleted.');
+
+    // Now delete the whole config and make sure all translations are deleted.
+    $rule->delete();
+    $translation = entity_i18n_string("rules_config:{$rule->name}:label", 'label-en', 'de');
+    $this->assertEqual($translation, 'label-en', 'Translation of deleted config has been deleted.');
+  }
+
+  /**
+   * Tests the "Translate a text" action.
+   */
+  public function testI18nActionT() {
+    $set = rules_action_set(array());
+    $set->action('rules_i18n_t', array(
+      'text' => 'untranslated',
+      'language' => 'de',
+    ));
+    $set->action('drupal_message', array('message:select' => 'text'));
+    $set->save('rules_i18n_test');
+
+    // Add a translation.
+    $actions = $set->getIterator();
+    $id = $actions[0]->elementId();
+    i18n_string_textgroup('rules')->update_translation("rules_config:{$set->name}:$id:text", 'de', 'text-de');
+
+    // Clear messages and execute it.
+    drupal_get_messages();
+    $set->execute();
+    $messages = drupal_get_messages();
+    $this->assertEqual($messages['status'][0], 'text-de', 'Text has been successfully translated.');
+
+    // Enable the PHP module and make sure PHP in translations is not evaluted.
+    module_enable(array('php'));
+    i18n_string_textgroup('rules')->update_translation("rules_config:{$set->name}:$id:text", 'de', 'text <?php echo "eval";?>');
+
+    // Clear messages and execute it.
+    drupal_get_messages();
+    $set->execute();
+    $messages = drupal_get_messages();
+    $this->assertEqual($messages['status'][0], check_plain('text <?php echo "eval";?>'), 'PHP in translated text is not executed.');
+  }
+
+  /**
+   * Tests the "Select a translated value" action.
+   */
+  public function testI18nActionSelect() {
+    // Make the body field and the node type 'page' translatable.
+    $field = field_info_field('body');
+    $field['translatable'] = TRUE;
+    field_update_field($field);
+    variable_set('language_content_type_page', 1);
+
+    $set = rules_action_set(array('node' => array('type' => 'node')));
+    $set->action('rules_i18n_select', array(
+        'data:select' => 'node:body:value',
+        'language' => 'de',
+        'data_translated:var' => 'body',
+    ));
+    $set->action('drupal_message', array('message:select' => 'body'));
+    $set->save();
+
+    $body['en'][0] = array('value' => 'English body.');
+    $body['de'][0] = array('value' => 'German body.');
+    $node = $this->drupalCreateNode(array('language' => 'en', 'body' => $body));
+
+    // Clear messages and execute it.
+    drupal_get_messages();
+    $set->execute($node);
+
+    $messages = drupal_get_messages();
+    $this->assertEqual($messages['status'][0], "German body.\n", 'Translated text has been selected.');
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/includes/rules_scheduler.handler.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * Default scheduled task handler.
+ */
+class RulesSchedulerDefaultTaskHandler implements RulesSchedulerTaskHandlerInterface {
+
+  /**
+   * The task array.
+   *
+   * @var array
+   */
+  protected $task;
+
+  /**
+   * Constructs a repetitive task handler object.
+   */
+  public function __construct(array $task) {
+    $this->task = $task;
+  }
+
+  /**
+   * Implements RulesSchedulerTaskHandlerInterface::runTask().
+   */
+  public function runTask() {
+    if ($component = rules_get_cache('comp_' . $this->task['config'])) {
+      $replacements = array('%label' => $component->label(), '%plugin' => $component->plugin());
+      $replacements['%identifier'] = $this->task['identifier'] ? $this->task['identifier'] : t('without identifier');
+      rules_log('Scheduled evaluation of %plugin %label, task %identifier.', $replacements, RulesLog::INFO, $component, TRUE);
+      $state = unserialize($this->task['data']);
+      $state->restoreBlocks();
+      // Block the config to prevent any future recursion.
+      $state->block($component);
+      // Finally evaluate the component with the given state.
+      $component->evaluate($state);
+      $state->unblock($component);
+      rules_log('Finished evaluation of %plugin %label, task %identifier.', $replacements, RulesLog::INFO, $component, FALSE);
+      $state->cleanUp();
+    }
+  }
+
+  /**
+   * Implements RulesSchedulerTaskHandlerInterface::afterTaskQueued().
+   */
+  public function afterTaskQueued() {
+    // Delete the task from the task list.
+    db_delete('rules_scheduler')
+      ->condition('tid', $this->task['tid'])
+      ->execute();
+  }
+
+  /**
+   * Implements RulesSchedulerTaskHandlerInterface::getTask().
+   */
+  public function getTask() {
+    return $this->task;
+  }
+
+}
+
+/**
+ * Interface for scheduled task handlers.
+ *
+ * Task handlers control the behavior of a task when it's queued or executed.
+ * Unless specified otherwise, the RulesSchedulerDefaultTaskHandler task handler
+ * is used.
+ *
+ * @see rules_scheduler_run_task()
+ * @see rules_scheduler_cron()
+ * @see RulesSchedulerDefaultTaskHandler
+ */
+interface RulesSchedulerTaskHandlerInterface {
+
+  /**
+   * Processes a queue item.
+   *
+   * @throws RulesEvaluationException
+   *   If there are any problems executing the task.
+   *
+   * @see rules_scheduler_run_task()
+   */
+  public function runTask();
+
+  /**
+   * Processes a task after it has been queued.
+   *
+   * @see rules_scheduler_cron()
+   */
+  public function afterTaskQueued();
+
+  /**
+   * Returns the task associated with the task handler.
+   *
+   * @return array
+   *   The task (queue item) array.
+   */
+  public function getTask();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/includes/rules_scheduler.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Views integration for the rules scheduler module.
+ */
+
+/**
+ * Implements hook_views_data(). Specifies the list of future scheduled
+ * tasks displayed on the schedule page.
+ */
+function rules_scheduler_views_data() {
+  $table = array(
+    'rules_scheduler' => array(
+      'table' => array(
+        'group' => 'Rules scheduler',
+        'base' => array(
+          'field' => 'tid',
+          'title' => t('Scheduled Rules components'),
+          'help' => t("Scheduled Rules components that are executed based on time and cron"),
+          'weight' => -10,
+        ),
+      ),
+      'tid' => array(
+        'title' => t('Tid'),
+        'help' => t('The internal ID of the scheduled component'),
+        'field' => array(
+          'click sortable' => TRUE,
+        ),
+        'filter' => array(
+          'handler' => 'views_handler_filter_numeric',
+        ),
+        'sort' => array(
+          'handler' => 'views_handler_sort',
+        ),
+      ),
+      'config' => array(
+        'title' => t('Component name'),
+        'help' => t('The name of the component'),
+        'field' => array(
+          'click sortable' => TRUE,
+        ),
+        'filter' => array(
+          'handler' => 'rules_scheduler_views_filter',
+        ),
+        'argument' => array(
+          'handler' => 'views_handler_argument_string',
+        ),
+        'sort' => array(
+          'handler' => 'views_handler_sort',
+        ),
+      ),
+      'date' => array(
+        'title' => t('Scheduled date'),
+        'help' => t('Scheduled date and time stamp'),
+        'field' => array(
+          'handler' => 'views_handler_field_date',
+          'click sortable' => TRUE,
+        ),
+        'filter' => array(
+          'handler' => 'views_handler_filter',
+        ),
+        'sort' => array(
+          'handler' => 'views_handler_sort',
+        ),
+      ),
+      'identifier' => array(
+        'title' => t('User provided identifier'),
+        'help' => t('ID to recognize this specific scheduled task'),
+        'field' => array(
+          'click sortable' => TRUE,
+        ),
+        'filter' => array(
+          'handler' => 'views_handler_filter_string',
+        ),
+        'sort' => array(
+          'handler' => 'views_handler_sort',
+        ),
+      ),
+    ),
+  );
+  return $table;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/includes/rules_scheduler.views_default.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,180 @@
+<?php
+
+/**
+ * @file
+ * Views integration for the rules scheduler module.
+ */
+
+/**
+ * Implements hook_views_default_views().
+ */
+function rules_scheduler_views_default_views() {
+  $view = new view;
+  $view->name = 'rules_scheduler';
+  $view->description = 'Scheduled Rules components';
+  $view->tag = '';
+  $view->base_table = 'rules_scheduler';
+  $view->api_version = '3.0-alpha1';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Defaults */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['access']['perm'] = 'administer rules';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '30';
+  $handler->display->display_options['pager']['options']['offset'] = '0';
+  $handler->display->display_options['pager']['options']['id'] = '0';
+  $handler->display->display_options['style_plugin'] = 'table';
+  $handler->display->display_options['style_options']['columns'] = array(
+    'tid' => 'tid',
+    'config' => 'config',
+    'date' => 'date',
+    'identifier' => 'identifier',
+    'nothing' => 'nothing',
+  );
+  $handler->display->display_options['style_options']['default'] = 'date';
+  $handler->display->display_options['style_options']['info'] = array(
+    'tid' => array(
+      'sortable' => 0,
+      'default_sort_order' => 'asc',
+      'align' => '',
+      'separator' => '',
+    ),
+    'config' => array(
+      'sortable' => 1,
+      'default_sort_order' => 'asc',
+      'align' => '',
+      'separator' => '',
+    ),
+    'date' => array(
+      'sortable' => 1,
+      'default_sort_order' => 'asc',
+      'align' => '',
+      'separator' => '',
+    ),
+    'identifier' => array(
+      'sortable' => 1,
+      'default_sort_order' => 'asc',
+      'align' => '',
+      'separator' => '',
+    ),
+    'nothing' => array(
+      'align' => '',
+      'separator' => '',
+    ),
+  );
+  $handler->display->display_options['style_options']['override'] = 1;
+  $handler->display->display_options['style_options']['sticky'] = 0;
+  /* Empty text: Global: Text area */
+  $handler->display->display_options['empty']['area']['id'] = 'area';
+  $handler->display->display_options['empty']['area']['table'] = 'views';
+  $handler->display->display_options['empty']['area']['field'] = 'area';
+  $handler->display->display_options['empty']['area']['empty'] = FALSE;
+  $handler->display->display_options['empty']['area']['content'] = 'No tasks have been scheduled.';
+  $handler->display->display_options['empty']['area']['format'] = 'plain_text';
+  /* Field: Rules scheduler: Tid */
+  $handler->display->display_options['fields']['tid']['id'] = 'tid';
+  $handler->display->display_options['fields']['tid']['table'] = 'rules_scheduler';
+  $handler->display->display_options['fields']['tid']['field'] = 'tid';
+  /* Field: Rules scheduler: Component name */
+  $handler->display->display_options['fields']['config']['id'] = 'config';
+  $handler->display->display_options['fields']['config']['table'] = 'rules_scheduler';
+  $handler->display->display_options['fields']['config']['field'] = 'config';
+  $handler->display->display_options['fields']['config']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['config']['alter']['make_link'] = 1;
+  $handler->display->display_options['fields']['config']['alter']['path'] = 'admin/config/workflow/rules/config/[config]';
+  $handler->display->display_options['fields']['config']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['config']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['config']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['config']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['config']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['config']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['config']['element_label_colon'] = 1;
+  $handler->display->display_options['fields']['config']['element_default_classes'] = 1;
+  $handler->display->display_options['fields']['config']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['config']['empty_zero'] = 0;
+  /* Field: Rules scheduler: Scheduled date */
+  $handler->display->display_options['fields']['date']['id'] = 'date';
+  $handler->display->display_options['fields']['date']['table'] = 'rules_scheduler';
+  $handler->display->display_options['fields']['date']['field'] = 'date';
+  /* Field: Rules scheduler: User provided identifier */
+  $handler->display->display_options['fields']['identifier']['id'] = 'identifier';
+  $handler->display->display_options['fields']['identifier']['table'] = 'rules_scheduler';
+  $handler->display->display_options['fields']['identifier']['field'] = 'identifier';
+  /* Field: Global: Custom text */
+  $handler->display->display_options['fields']['nothing']['id'] = 'nothing';
+  $handler->display->display_options['fields']['nothing']['table'] = 'views';
+  $handler->display->display_options['fields']['nothing']['field'] = 'nothing';
+  $handler->display->display_options['fields']['nothing']['label'] = 'Operations';
+  $handler->display->display_options['fields']['nothing']['alter']['text'] = 'delete';
+  $handler->display->display_options['fields']['nothing']['alter']['make_link'] = 1;
+  $handler->display->display_options['fields']['nothing']['alter']['path'] = 'admin/config/workflow/rules/schedule/[tid]/delete';
+  $handler->display->display_options['fields']['nothing']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['nothing']['alter']['alt'] = 'Delete this scheduled task';
+  $handler->display->display_options['fields']['nothing']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['nothing']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['nothing']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['nothing']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['nothing']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['nothing']['element_label_colon'] = 1;
+  $handler->display->display_options['fields']['nothing']['element_default_classes'] = 1;
+  $handler->display->display_options['fields']['nothing']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['nothing']['empty_zero'] = 0;
+  /* Sort criterion: Rules scheduler: Scheduled date */
+  $handler->display->display_options['sorts']['date']['id'] = 'date';
+  $handler->display->display_options['sorts']['date']['table'] = 'rules_scheduler';
+  $handler->display->display_options['sorts']['date']['field'] = 'date';
+  /* Argument: Rules scheduler: Component name */
+  $handler->display->display_options['arguments']['config']['id'] = 'config';
+  $handler->display->display_options['arguments']['config']['table'] = 'rules_scheduler';
+  $handler->display->display_options['arguments']['config']['field'] = 'config';
+  $handler->display->display_options['arguments']['config']['style_plugin'] = 'default_summary';
+  $handler->display->display_options['arguments']['config']['wildcard'] = '0';
+  $handler->display->display_options['arguments']['config']['default_argument_type'] = 'fixed';
+  $handler->display->display_options['arguments']['config']['glossary'] = 0;
+  $handler->display->display_options['arguments']['config']['limit'] = '0';
+  $handler->display->display_options['arguments']['config']['transform_dash'] = 0;
+  /* Filter: Rules scheduler: Component name */
+  $handler->display->display_options['filters']['config']['id'] = 'config';
+  $handler->display->display_options['filters']['config']['table'] = 'rules_scheduler';
+  $handler->display->display_options['filters']['config']['field'] = 'config';
+  $handler->display->display_options['filters']['config']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['config']['expose']['operator'] = 'config_op';
+  $handler->display->display_options['filters']['config']['expose']['label'] = 'Component filter';
+  $handler->display->display_options['filters']['config']['expose']['identifier'] = 'config';
+  $handler->display->display_options['filters']['config']['expose']['remember'] = 1;
+  $handler->display->display_options['filters']['config']['expose']['use_operator'] = 0;
+  $handler->display->display_options['filters']['config']['expose']['reduce'] = 0;
+  $translatables['rules_scheduler'] = array(
+    t('Defaults'),
+    t('more'),
+    t('Apply'),
+    t('Reset'),
+    t('Sort By'),
+    t('Asc'),
+    t('Desc'),
+    t('Items per page'),
+    t('- All -'),
+    t('Offset'),
+    t('No tasks have been scheduled.'),
+    t('Tid'),
+    t('Component name'),
+    t('admin/config/workflow/rules/config/[config]'),
+    t('Scheduled date'),
+    t('User provided identifier'),
+    t('Operations'),
+    t('delete'),
+    t('admin/config/workflow/rules/schedule/[tid]/delete'),
+    t('Delete this scheduled task'),
+    t('All'),
+    t('Component filter'),
+  );
+
+  $views = array();
+  $views[$view->name] = $view;
+  return $views;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/includes/rules_scheduler_views_filter.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * An extended subclass for component filtering.
+ */
+class rules_scheduler_views_filter extends views_handler_filter_in_operator {
+  function get_value_options() {
+    if (!isset($this->value_options)) {
+      $this->value_title = t('Component');
+      $result = db_select('rules_scheduler', 'r')
+        ->fields('r', array('config'))
+        ->distinct()
+        ->execute();
+      $config_names = array();
+      foreach ($result as $record) {
+        $config_names[$record->config] = $record->config;
+      }
+      $this->value_options = $config_names;
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/rules_scheduler.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,140 @@
+<?php
+
+/**
+ * @file
+ * Admin forms for scheduling.
+ */
+
+/**
+ * Schedule page with a view for the scheduled tasks.
+ */
+function rules_scheduler_schedule_page() {
+  // Display view for all scheduled tasks
+  if (module_exists('views')) {
+    // We cannot use views_embed_view() here as we need to set the path for the
+    // component filter form.
+    $view = views_get_view('rules_scheduler');
+    $view->override_path = RULES_SCHEDULER_PATH;
+    $task_list = $view->preview();
+  }
+  else {
+    $task_list = t('To display scheduled tasks you have to install the <a href="http://drupal.org/project/views">Views</a> module.');
+  }
+  $page['task_view'] = array(
+    '#markup' => $task_list,
+  );
+  $form = drupal_get_form('rules_scheduler_form');
+  $page['delete'] = array(
+    '#markup' => drupal_render($form),
+  );
+  return $page;
+}
+
+/**
+ * Form for deletion of tasks by component.
+ */
+function rules_scheduler_form($form, &$form_state) {
+  $result = db_select('rules_scheduler', 'r')
+    ->fields('r', array('config'))
+    ->distinct()
+    ->execute();
+  $config_options = array_intersect_key(rules_get_components(TRUE), $result->fetchAllAssoc('config'));
+
+  // Fieldset for canceling by component name.
+  $form['delete_by_config'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Delete tasks by component name'),
+    '#disabled' => empty($config_options)
+  );
+  $form['delete_by_config']['config'] = array(
+    '#title' => t('Component'),
+    '#type' => 'select',
+    '#options' => $config_options,
+    '#description' => t('Select the component for which to delete all scheduled tasks.'),
+    '#required' => TRUE,
+  );
+  $form['delete_by_config']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Delete tasks'),
+    '#submit' => array('rules_scheduler_form_delete_by_config_submit'),
+    );
+  return $form;
+}
+
+/**
+ * Submit handler for deleting future scheduled tasks.
+ */
+function rules_scheduler_form_delete_by_config_submit($form, &$form_state) {
+  $config = rules_config_load($form_state['values']['config']);
+  rules_action('schedule_delete')->execute($config->name);
+  drupal_set_message(t('All scheduled tasks associated with %config have been deleted.', array('%config' => $config->label())));
+  $form_state['redirect'] = RULES_SCHEDULER_PATH;
+}
+
+/**
+ * Confirmation form for deleting single tasks.
+ */
+function rules_scheduler_delete_task($form, &$form_state, $task) {
+  $form_state['task'] = $task;
+  $config = rules_config_load($task['config']);
+  $path['path'] = isset($_GET['destination']) ? $_GET['destination'] : RULES_SCHEDULER_PATH;
+
+  $title = t('Are you sure you want to delete the scheduled task %id?', array('%id' => $task['tid']));
+  if (!empty($task['identifier'])) {
+    $msg = t('This task with the custom identifier %id executes component %label on %date. The action cannot be undone.', array(
+      '%label' => $config->label(),
+      '%id' => $task['identifier'],
+      '%date' => format_date($task['date']),
+    ));
+  }
+  else {
+    $msg = t('This task executes component %label and will be executed on %date. The action cannot be undone.', array(
+      '%label' => $config->label(),
+      '%id' => $task['identifier'],
+      '%date' => format_date($task['date']),
+    ));
+  }
+  return confirm_form($form, $title, $path, $msg, t('Delete'), t('Cancel'));
+}
+
+/**
+ * Submit handler for deleting single tasks.
+ */
+function rules_scheduler_delete_task_submit($form, &$form_state) {
+  rules_scheduler_task_delete($form_state['task']['tid']);
+  drupal_set_message(t('Task %tid has been deleted.', array('%tid' => $form_state['task']['tid'])));
+  $form_state['redirect'] = RULES_SCHEDULER_PATH;
+}
+
+/**
+ * Configuration form to manually schedule a rules component.
+ */
+function rules_scheduler_schedule_form($form, &$form_state, $rules_config, $base_path) {
+  // Only components can be scheduled.
+  if (!($rules_config instanceof RulesTriggerableInterface)) {
+    RulesPluginUI::$basePath = $base_path;
+    $form_state['component'] = $rules_config->name;
+    $action = rules_action('schedule', array('component' => $rules_config->name));
+    $action->form($form, $form_state);
+    // The component should be fixed, so hide the paramter for it.
+    $form['parameter']['component']['#access'] = FALSE;
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Schedule'),
+    );
+    $form['#validate'] = array('rules_ui_form_rules_config_validate');
+    return $form;
+  }
+  drupal_not_found();
+  exit;
+}
+
+/**
+ * Submit callback to execute the scheduling action.
+ */
+function rules_scheduler_schedule_form_submit($form, &$form_state) {
+  $action = $form_state['rules_element'];
+  $action->execute();
+  drupal_set_message(t('Component %label has been scheduled.', array('%label' => rules_config_load($form_state['component'])->label())));
+  $form_state['redirect'] = RULES_SCHEDULER_PATH;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/rules_scheduler.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,21 @@
+name = Rules Scheduler
+description = Schedule the execution of Rules components using actions.
+dependencies[] = rules
+package = Rules
+core = 7.x
+files[] = rules_scheduler.admin.inc
+files[] = rules_scheduler.module
+files[] = rules_scheduler.install
+files[] = rules_scheduler.rules.inc
+files[] = rules_scheduler.test
+files[] = includes/rules_scheduler.handler.inc
+files[] = includes/rules_scheduler.views_default.inc
+files[] = includes/rules_scheduler.views.inc
+files[] = includes/rules_scheduler_views_filter.inc
+
+; Information added by drupal.org packaging script on 2013-09-16
+version = "7.x-2.4"
+core = "7.x"
+project = "rules"
+datestamp = "1379354606"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/rules_scheduler.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,189 @@
+<?php
+
+/**
+ * @file
+ * Rules Scheduler - Installation file.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function rules_scheduler_schema() {
+  $schema['rules_scheduler'] = array(
+    'description' => 'Stores scheduled tasks.',
+    'fields' => array(
+      'tid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => "The scheduled task's id.",
+      ),
+      'config' => array(
+        'type' => 'varchar',
+        'length' => '64',
+        'default' => '',
+        'not null' => TRUE,
+        'description' => "The scheduled configuration's name.",
+      ),
+      'date' => array(
+        'description' => 'The Unix timestamp of when the task is to be scheduled.',
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'data' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'serialize' => TRUE,
+        'description' => 'The whole, serialized evaluation data.',
+      ),
+      'identifier' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'default' => '',
+        'not null' => FALSE,
+        'description' => 'The user defined string identifying this task.',
+      ),
+      'handler' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+        'description' => 'The fully qualified class name of a the queue item handler.',
+      ),
+    ),
+    'primary key' => array('tid'),
+    'indexes' => array(
+      'date' => array('date'),
+    ),
+    'unique key' => array(
+      'id' => array('config', 'identifier'),
+    ),
+  );
+  return $schema;
+}
+
+/**
+ * Upgrade from Rules scheduler 6.x-1.x to 7.x.
+ */
+function rules_scheduler_update_7200() {
+  // Rename the old table so we can keep its content and start over with a
+  // fresh one.
+  db_rename_table('rules_scheduler', 'rules_scheduler_d6');
+  // Create the d7 table.
+  $schema['rules_scheduler'] = array(
+    'description' => 'Stores scheduled tasks.',
+    'fields' => array(
+      'tid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => "The scheduled task's id.",
+      ),
+      'config' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'default' => '',
+        'not null' => TRUE,
+        'description' => "The scheduled configuration's name.",
+      ),
+      'date' => array(
+        'description' => 'The Unix timestamp of when the task is to be scheduled.',
+        'type' => 'int',
+        'not null' => TRUE,
+      ),
+      'data' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'serialize' => TRUE,
+        'description' => 'The whole, serialized evaluation data.',
+      ),
+      'identifier' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'default' => '',
+        'not null' => FALSE,
+        'description' => 'The user defined string identifying this task.',
+      ),
+    ),
+    'primary key' => array('tid'),
+    'indexes' => array('date' => array('date')),
+  );
+  db_create_table('rules_scheduler', $schema['rules_scheduler']);
+}
+
+/**
+ * Fix the length of the rules_scheduler.name column.
+ */
+function rules_scheduler_update_7202() {
+  // Note that update 7201 (add the 'id' unique key') has been removed as it is
+  // incorporated by 7202. For anyone that has already run the previous update
+  // 7201, we have to first drop the unique key.
+  db_drop_unique_key('rules_scheduler', 'id');
+  db_change_field('rules_scheduler', 'config', 'config', array(
+    'type' => 'varchar',
+    'length' => '64',
+    'default' => '',
+    'not null' => TRUE,
+    'description' => "The scheduled configuration's name.",
+  ));
+  db_add_unique_key('rules_scheduler', 'id', array('config', 'identifier'));
+}
+
+/**
+ * Add a database column for specifying a queue item handler.
+ */
+function rules_scheduler_update_7203() {
+  db_add_field('rules_scheduler', 'handler', array(
+    'type' => 'varchar',
+    'length' => '255',
+    'not null' => FALSE,
+    'description' => 'The fully qualified class name of a the queue item handler.',
+  ));
+}
+
+/**
+ * Rename rules_scheduler.state into rules_scheduler.data.
+ */
+function rules_scheduler_update_7204() {
+  db_change_field('rules_scheduler', 'state', 'data', array(
+    'type' => 'text',
+    'not null' => FALSE,
+    'serialize' => TRUE,
+    'description' => 'The whole, serialized evaluation data.',
+  ));
+}
+
+/**
+ * Rules upgrade callback for mapping the action name.
+ */
+function rules_scheduler_action_upgrade_map_name($element) {
+  return 'schedule';
+}
+
+/**
+ * Rules upgrade callback.
+ */
+function rules_scheduler_action_upgrade($element, $target) {
+  $target->settings['component'] = $element['#info']['set'];
+  $target->settings['date'] = $element['#settings']['task_date'];
+  $target->settings['identifier'] = $element['#settings']['task_identifier'];
+
+  unset($element['#info']['arguments']['task_date'], $element['#info']['arguments']['task_identifier']);
+  foreach ($element['#info']['arguments'] as $name => $info) {
+    rules_upgrade_element_parameter_settings($element, $target, $name, $info, 'param_' . $name);
+  }
+}
+
+/**
+ * Rules upgrade callback for mapping the action name.
+ */
+function rules_action_delete_scheduled_set_upgrade_map_name($element) {
+  return 'schedule_delete';
+}
+
+/**
+ * Rules upgrade callback.
+ */
+function rules_action_delete_scheduled_set_upgrade($element, $target) {
+  $target->settings['component'] = $element['#settings']['ruleset'];
+  $target->settings['task'] = $element['#settings']['task_identifier'];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/rules_scheduler.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,196 @@
+<?php
+
+/**
+ * @file
+ * Rules scheduler module.
+ */
+
+define('RULES_SCHEDULER_PATH', 'admin/config/workflow/rules/schedule');
+
+/**
+ * Implements hook_cron().
+ */
+function rules_scheduler_cron() {
+  // Limit adding tasks to 1000 per cron run.
+  $result = db_select('rules_scheduler', 'r', array('fetch' => PDO::FETCH_ASSOC))
+    ->fields('r')
+    ->condition('date', time(), '<=')
+    ->orderBy('date')
+    ->range(0, 1000)
+    ->execute();
+
+  $queue = DrupalQueue::get('rules_scheduler_tasks');
+  foreach ($result as $task) {
+    // Add the task to the queue and remove the entry afterwards.
+    if ($queue->createItem($task)) {
+      $task_created = TRUE;
+      rules_scheduler_task_handler($task)->afterTaskQueued();
+    }
+  }
+
+  if (!empty($task_created)) {
+    // hook_exit() is not invoked for cron runs, so register it as shutdown
+    // callback for logging the rules log to the watchdog.
+    drupal_register_shutdown_function('rules_exit');
+    // Clear the log before running tasks via the queue to avoid logging
+    // unrelated logs from previous cron-operations.
+    RulesLog::logger()->clear();
+  }
+}
+
+/**
+ * Implements hook_cron_queue_info().
+ */
+function rules_scheduler_cron_queue_info() {
+  $queues['rules_scheduler_tasks'] = array(
+    'worker callback' => 'rules_scheduler_run_task',
+    'time' => 15,
+  );
+  return $queues;
+}
+
+/**
+ * Queue worker callback for running a single task.
+ *
+ * @param array $task
+ *   The task to process.
+ */
+function rules_scheduler_run_task(array $task) {
+  try {
+    rules_scheduler_task_handler($task)->runTask();
+  }
+  catch (RulesEvaluationException $e) {
+    rules_log($e->msg, $e->args, $e->severity);
+    rules_log('Unable to execute task with identifier %id scheduled on date %date.', array('%id' => $task['identifier'], '%date' => format_date($task['date'])), RulesLog::ERROR);
+  }
+}
+
+/**
+ * Returns the task handler for a given task.
+ *
+ * @param array $task
+ *   A task (queue item) array.
+ *
+ * @throws RulesEvaluationException
+ *   If the task handler class is missing.
+ *
+ * @return RulesSchedulerTaskHandlerInterface
+ *   The task handler.
+ */
+function rules_scheduler_task_handler(array $task) {
+  $class = !empty($task['handler']) ? $task['handler'] : 'RulesSchedulerDefaultTaskHandler';
+  if (!class_exists($class)) {
+    throw new RulesEvaluationException('Missing task handler implementation %class.', array('%class' => $class), NULL, RulesLog::ERROR);
+  }
+  return new $class($task);
+}
+
+/**
+ * Implements hook_rules_ui_menu_alter().
+ *
+ * Adds a menu item for the 'schedule' operation.
+ */
+function rules_scheduler_rules_ui_menu_alter(&$items, $base_path, $base_count) {
+  $items[$base_path . '/manage/%rules_config/schedule'] = array(
+    'title callback' => 'rules_get_title',
+    'title arguments' => array('Schedule !plugin "!label"', $base_count + 1),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_scheduler_schedule_form', $base_count + 1, $base_path),
+    'access callback' => 'rules_config_access',
+    'access arguments' => array('update', $base_count + 1),
+    'file' => 'rules_scheduler.admin.inc',
+    'file path' => drupal_get_path('module', 'rules_scheduler'),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function rules_scheduler_menu() {
+  $items = array();
+  $items[RULES_SCHEDULER_PATH] = array(
+    'title' => 'Schedule',
+    'type' => MENU_LOCAL_TASK,
+    'page callback' => 'rules_scheduler_schedule_page',
+    'access arguments' => array('administer rules'),
+    'file' => 'rules_scheduler.admin.inc',
+  );
+  $items[RULES_SCHEDULER_PATH .'/%rules_scheduler_task/delete'] = array(
+    'title' => 'Delete a scheduled task',
+    'type' => MENU_CALLBACK,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('rules_scheduler_delete_task', 5),
+    'access arguments' => array('administer rules'),
+    'file' => 'rules_scheduler.admin.inc',
+  );
+  return $items;
+}
+
+/**
+ * Load a task by a given task ID.
+ */
+function rules_scheduler_task_load($tid) {
+  $result = db_select('rules_scheduler', 'r')
+    ->fields('r')
+    ->condition('tid', (int) $tid)
+    ->execute();
+  return $result->fetchAssoc();
+}
+
+/**
+ * Delete a task by a given task ID.
+ */
+function rules_scheduler_task_delete($tid) {
+  db_delete('rules_scheduler')
+    ->condition('tid', $tid)
+    ->execute();
+}
+
+/**
+ * Schedule a task to be executed later on.
+ *
+ * @param $task
+ *   An array representing the task with the following keys:
+ *   - config: The machine readable name of the to be scheduled component.
+ *   - date: Timestamp when the component should be executed.
+ *   - state: (deprecated) Rules evaluation state to use for scheduling.
+ *   - data: Any additional data to store with the task.
+ *   - handler: The name of the task handler class.
+ *   - identifier: User provided string to identify the task per scheduled
+ *   configuration.
+ */
+function rules_scheduler_schedule_task($task) {
+  // Map the deprecated 'state' property into 'data'.
+  if (isset($task['state'])) {
+    $task['data'] = $task['state'];
+    unset($task['state']);
+  }
+  if (!empty($task['identifier'])) {
+    // If there is a task with the same identifier and component, we replace it.
+    db_delete('rules_scheduler')
+      ->condition('config', $task['config'])
+      ->condition('identifier', $task['identifier'])
+      ->execute();
+  }
+  drupal_write_record('rules_scheduler', $task);
+}
+
+/**
+ * Implements hook_rules_config_delete().
+ */
+function rules_scheduler_rules_config_delete($rules_config) {
+  // Delete all tasks scheduled for this config.
+  db_delete('rules_scheduler')
+    ->condition('config', $rules_config->name)
+    ->execute();
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function rules_scheduler_views_api() {
+  return array(
+    'api' => '3.0-alpha1',
+    'path' => drupal_get_path('module', 'rules_scheduler') .'/includes',
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/rules_scheduler.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,214 @@
+<?php
+
+/**
+ * @file
+ * Rules integration for the rules scheduler module.
+ *
+ * @addtogroup rules
+ * @{
+ */
+
+/**
+ * Implements hook_rules_action_info().
+ */
+function rules_scheduler_rules_action_info() {
+  $items['schedule'] = array(
+    'label' => t('Schedule component evaluation'),
+    'group' => t('Rules scheduler'),
+    'base' => 'rules_scheduler_action_schedule',
+    'named parameter' => TRUE,
+    'parameter' => array(
+      'component' => array(
+        'type' => 'text',
+        'label' => t('Component'),
+        'options list' => 'rules_scheduler_component_options_list',
+        'restriction' => 'input',
+        'description' => 'Select the component to schedule. Only components containing actions are available – no condition sets.',
+      ),
+      'date' => array(
+        'type' => 'date',
+        'label' => t('Scheduled evaluation date'),
+      ),
+      'identifier' => array(
+        'type' => 'text',
+        'label' => t('Identifier'),
+        'description' => t('A string used for identifying this task. Any existing tasks for this component with the same identifier will be replaced.'),
+        'optional' => TRUE,
+      ),
+      // Further needed parameter by the component are added during processing.
+    ),
+  );
+  // Add action to delete scheduled tasks.
+  $items['schedule_delete'] = array(
+    'label' => t('Delete scheduled tasks'),
+    'group' => t('Rules scheduler'),
+    'base' => 'rules_scheduler_action_delete',
+    'parameter' => array(
+      'component' => array(
+        'type' => 'text',
+        'label' => t('Component'),
+        'options list' => 'rules_scheduler_component_options_list',
+        'description' => t('The component for which scheduled tasks will be deleted.'),
+        'optional' => TRUE,
+      ),
+      'task' => array(
+        'type' => 'text',
+        'label' => t('Task identifier'),
+        'description' => t('All tasks that are annotated with the given identifier will be deleted.'),
+        'optional' => TRUE,
+      ),
+    ),
+  );
+  return $items;
+}
+
+/**
+ * Options list callback returning a list of action components.
+ */
+function rules_scheduler_component_options_list() {
+  return rules_get_components(TRUE, 'action');
+}
+
+/**
+ * Base action implementation for scheduling components.
+ */
+function rules_scheduler_action_schedule($args, $element) {
+  $state = $args['state'];
+  if ($component = rules_get_cache('comp_' . $args['component'])) {
+    // Manually create a new evaluation state for scheduling the evaluation.
+    $new_state = new RulesState();
+
+    // Register all parameters as variables.
+    foreach ($element->pluginParameterInfo() as $name => $info) {
+      if (strpos($name, 'param_') === 0) {
+        // Remove the parameter name prefix 'param_'.
+        $var_name = substr($name, 6);
+        $new_state->addVariable($var_name, $state->currentArguments[$name], $info);
+      }
+    }
+    rules_scheduler_schedule_task(array(
+      'date' => $args['date'],
+      'config' => $args['component'],
+      'data' => $new_state,
+      'identifier' => $args['identifier'],
+    ));
+  }
+  else {
+    throw new RulesEvaluationException('Unable to get the component %name', array('%name' => $args['component']), $element, RulesLog::ERROR);
+  }
+}
+
+/**
+ * Info alteration callback for the schedule action.
+ */
+function rules_scheduler_action_schedule_info_alter(&$element_info, RulesPlugin $element) {
+  if (isset($element->settings['component'])) {
+    // If run during a cache rebuild the cache might not be instantiated yet,
+    // so fail back to loading the component from database.
+    if (($component = rules_get_cache('comp_' . $element->settings['component'])) || $component = rules_config_load($element->settings['component'])) {
+      // Add in the needed parameters.
+      foreach ($component->parameterInfo() as $name => $info) {
+        $element_info['parameter']['param_' . $name] = $info;
+      }
+    }
+  }
+}
+
+/**
+ * Validate callback for the schedule action to make sure the component exists and is not dirty.
+ *
+ * @see rules_element_invoke_component_validate()
+ */
+function rules_scheduler_action_schedule_validate(RulesPlugin $element) {
+  $info = $element->info();
+  $component = rules_config_load($element->settings['component']);
+  if (!$component) {
+    throw new RulesIntegrityException(t('The component %config does not exist.', array('%config' => $element->settings['component'])), $element);
+  }
+  // Check if the component is marked as dirty.
+  rules_config_update_dirty_flag($component);
+  if (!empty($component->dirty)) {
+    throw new RulesIntegrityException(t('The utilized component %config fails the integrity check.', array('%config' => $element->settings['component'])), $element);
+  }
+}
+
+/**
+ * Help for the schedule action.
+ */
+function rules_scheduler_action_schedule_help() {
+  return t("Note that component evaluation is triggered by <em>cron</em> – make sure cron is configured correctly by checking your site's !status. The scheduling time accuracy depends on your configured cron interval. See <a href='@url'>the online documentation</a> for more information on how to schedule evaluation of components.",
+    array('!status' => l('Status report', 'admin/reports/status'),
+          '@url' => rules_external_help('scheduler')));
+}
+
+/**
+ * Form alter callback for the schedule action.
+ */
+function rules_scheduler_action_schedule_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+  $first_step = empty($element->settings['component']);
+  $form['reload'] = array(
+    '#weight' => 5,
+    '#type' => 'submit',
+    '#name' => 'reload',
+    '#value' => $first_step ? t('Continue') : t('Reload form'),
+    '#limit_validation_errors' => array(array('parameter', 'component')),
+    '#submit' => array('rules_action_type_form_submit_rebuild'),
+    '#ajax' => rules_ui_form_default_ajax(),
+  );
+  // Use ajax and trigger as the reload button.
+  $form['parameter']['component']['settings']['type']['#ajax'] = $form['reload']['#ajax'] + array(
+    'event' => 'change',
+    'trigger_as' => array('name' => 'reload'),
+  );
+
+  if ($first_step) {
+    // In the first step show only the component select.
+    foreach (element_children($form['parameter']) as $key) {
+      if ($key != 'component') {
+        unset($form['parameter'][$key]);
+      }
+    }
+    unset($form['submit']);
+    unset($form['provides']);
+  }
+  else {
+    // Hide the reload button in case js is enabled and it's not the first step.
+    $form['reload']['#attributes'] = array('class' => array('rules-hide-js'));
+  }
+}
+
+/**
+ * Action: Delete scheduled tasks.
+ */
+function rules_scheduler_action_delete($component_name = NULL, $task_identifier = NULL) {
+  $query = db_delete('rules_scheduler');
+  if (!empty($component_name)) {
+    $query->condition('config', $component_name);
+  }
+  if (!empty($task_identifier)) {
+    $query->condition('identifier', $task_identifier);
+  }
+  $query->execute();
+}
+
+/**
+ * Cancel scheduled task action validation callback.
+ */
+function rules_scheduler_action_delete_validate($element) {
+  if (empty($element->settings['task']) && empty($element->settings['task:select']) &&
+      empty($element->settings['component']) && empty($element->settings['component:select'])) {
+
+    throw new RulesIntegrityException(t('You have to specify at least either a component or a task identifier.'), $element);
+  }
+}
+
+/**
+ * Help for the cancel action.
+ */
+function rules_scheduler_action_delete_help() {
+  return t('This action allows you to delete scheduled tasks that are waiting for future execution.') .' '. t('They can be addressed by an identifier or by the component name, whereas if both are specified only tasks fulfilling both requirements will be deleted.');
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/rules_scheduler.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * @file
+ * Rules Scheduler tests.
+ */
+
+class RulesSchedulerTestCase extends DrupalWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Rules Scheduler tests',
+      'description' => 'Test scheduling components.',
+      'group' => 'Rules',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rules_scheduler', 'rules_scheduler_test');
+    RulesLog::logger()->clear();
+    variable_set('rules_debug_log', 1);
+  }
+
+  /**
+   * Tests scheduling components from the action.
+   *
+   * Note that this also makes sure Rules properly handles timezones, else this
+   * test could fail due to a wrong 'now' timestamp.
+   */
+  function testComponentSchedule() {
+    $set = rules_rule_set(array(
+      'node1' => array('type' => 'node', 'label' => 'node'),
+    ));
+    $set->rule(rule()->condition('node_is_published', array('node:select' => 'node1'))
+                     ->action('node_unpublish', array('node:select' => 'node1'))
+               );
+    $set->integrityCheck()->save('rules_test_set_2');
+
+    // Use different names for the variables to ensure they are properly mapped.
+    $rule = rule(array(
+      'node2' => array('type' => 'node', 'label' => 'node'),
+    ));
+    $rule->action('schedule', array(
+      'component' => 'rules_test_set_2',
+      'identifier' => 'node_[node2:nid]',
+      'date' => 'now',
+      'param_node1:select' => 'node2',
+    ));
+
+    $node = $this->drupalCreateNode(array('title' => 'The title.', 'status' => 1));
+    $rule->execute($node);
+
+    // Run cron to let the rules scheduler do its work.
+    drupal_cron_run();
+
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertFalse($node->status, 'The component has been properly scheduled.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Make sure recurion prevention is working fine for scheduled rule sets.
+   */
+  function testRecursionPrevention() {
+    $set = rules_rule_set(array(
+      'node1' => array('type' => 'node', 'label' => 'node'),
+    ));
+    $set->rule(rule()->condition('node_is_published', array('node:select' => 'node1'))
+                     ->action('node_unpublish', array('node:select' => 'node1'))
+               );
+    $set->integrityCheck()->save('rules_test_set_2');
+
+    // Add an reaction rule that is triggered upon a node save. The scheduled
+    // component changes the node, thus it would be scheduled again and run in
+    // an endless loop.
+    $rule = rules_reaction_rule();
+    $rule->event('node_insert');
+    $rule->event('node_update');
+    $rule->action('schedule', array(
+      'component' => 'rules_test_set_2',
+      'identifier' => '',
+      'date' => 'now',
+      'param_node1:select' => 'node',
+    ));
+    $rule->save();
+
+    // Create a node, what triggers the rule.
+    $node = $this->drupalCreateNode(array('title' => 'The title.', 'status' => 1));
+    // Run cron to let the rules scheduler do its work.
+    drupal_cron_run();
+
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertFalse($node->status, 'The component has been properly scheduled.');
+    $text1 = RulesLog::logger()->render();
+    $text2 = RulesTestCase::t('Not evaluating reaction rule %unlabeled to prevent recursion.', array('unlabeled' => $rule->name));
+    $this->assertTrue((strpos($text1, $text2) !== FALSE), "Scheduled recursion prevented.");
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Tests that custom task handlers are properly invoked.
+   */
+  public function testCustomTaskHandler() {
+    // Set up a scheduled task that will simply write a variable when executed.
+    $variable = 'rules_schedule_task_handler_variable';
+    rules_scheduler_schedule_task(array(
+      'date' => REQUEST_TIME,
+      'identifier' => '',
+      'config' => '',
+      'data' => array('variable' => $variable),
+      'handler' => 'RulesTestTaskHandler',
+    ));
+
+    // Run cron to let the rules scheduler do its work.
+    drupal_cron_run();
+
+    // The task handler should have set the variable to TRUE now.
+    $this->assertTrue(variable_get($variable));
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/tests/rules_scheduler_test.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Include file for Rules Scheduler tests.
+ */
+
+/**
+ * Test task handler class.
+ */
+class RulesTestTaskHandler extends RulesSchedulerDefaultTaskHandler {
+
+  /**
+   * Overrides RulesSchedulerDefaultTaskHandler::runTask().
+   */
+  public function runTask() {
+    $task = $this->getTask();
+    $data = unserialize($task['data']);
+
+    // Set the variable defined in the test to TRUE.
+    variable_set($data['variable'], TRUE);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/tests/rules_scheduler_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = "Rules Scheduler Tests"
+description = "Support module for the Rules Scheduler tests."
+package = Testing
+core = 7.x
+files[] = rules_scheduler_test.inc
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2013-09-16
+version = "7.x-2.4"
+core = "7.x"
+project = "rules"
+datestamp = "1379354606"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/rules_scheduler/tests/rules_scheduler_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * Rules Scheduler test module.
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/tests/rules.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,2101 @@
+<?php
+
+/**
+ * @file
+ * Rules tests.
+ */
+
+class RulesTestCase extends DrupalWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Rules Engine tests',
+      'description' => 'Test using the rules API to create and evaluate rules.',
+      'group' => 'Rules',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rules', 'rules_test');
+    RulesLog::logger()->clear();
+    variable_set('rules_debug_log', 1);
+  }
+
+  /**
+   * Calculates the output of t() given an array of placeholders to replace.
+   */
+  static function t($text, $strings) {
+    $placeholders = array();
+    foreach ($strings as $key => $string) {
+      $key = !is_numeric($key) ? $key : $string;
+      $placeholders['%' . $key] = drupal_placeholder($string);
+    }
+    return strtr($text, $placeholders);
+  }
+
+  protected function createTestRule() {
+    $rule = rule();
+    $rule->condition('rules_test_condition_true')
+         ->condition('rules_test_condition_true')
+         ->condition(rules_or()
+           ->condition(rules_condition('rules_test_condition_true')->negate())
+           ->condition('rules_test_condition_false')
+           ->condition(rules_and()
+             ->condition('rules_test_condition_false')
+             ->condition('rules_test_condition_true')
+             ->negate()
+           )
+         );
+    $rule->action('rules_test_action');
+    return $rule;
+  }
+
+  /**
+   * Tests creating a rule and iterating over the rule elements.
+   */
+  function testRuleCreation() {
+    $rule = $this->createTestRule();
+    $rule->integrityCheck();
+    $rule->execute();
+    $log = RulesLog::logger()->get();
+    $last = array_pop($log);
+    $last = array_pop($log);
+    $last = array_pop($log);
+    $this->assertEqual($last[0], 'action called', 'Action called');
+    RulesLog::logger()->checkLog();
+
+    // Make sure condition and action iterators are working.
+    $it = new RecursiveIteratorIterator($rule->conditions(), RecursiveIteratorIterator::SELF_FIRST);
+    $this->assertEqual(iterator_count($it), 8, 'Iterated over all conditions and condition containers');
+    $it = new RecursiveIteratorIterator($rule->conditions());
+    $this->assertEqual(iterator_count($it), 6, 'Iterated over all conditions');
+    $this->assertEqual(iterator_count($rule->actions()), 1, 'Iterated over all actions');
+    $this->assertEqual(iterator_count($rule->elements()), 10, 'Iterated over all rule elements.');
+
+    // Test getting dependencies and the integrity check.
+    $rule->integrityCheck();
+    $this->assertTrue($rule->dependencies() === array('rules_test'), 'Dependencies correctly returned.');
+  }
+
+  /**
+   * Test handling dependencies.
+   */
+  function testdependencies() {
+    $action = rules_action('rules_node_publish_action');
+    $this->assertEqual($action->dependencies(), array('rules_test'), 'Providing module is returned as dependency.');
+
+    $container = new RulesTestContainer();
+    $this->assertEqual($container->dependencies(), array('rules_test'), 'Providing module for container plugin is returned as dependency.');
+
+    // Test handling unmet dependencies.
+    $rule = rules_config_load('rules_export_test');
+    $this->assertTrue(in_array('comment', $rule->dependencies) && !$rule->dirty, 'Dependencies have been imported.');
+
+    // Remove the required comment module and make sure the rule is dirty then.
+    module_disable(array('comment'));
+    rules_clear_cache();
+    $rule = rules_config_load('rules_export_test');
+    $this->assertTrue($rule->dirty, 'Rule has been marked as dirty');
+
+    // Now try re-enabling.
+    module_enable(array('comment'));
+    rules_clear_cache();
+    $rule = rules_config_load('rules_export_test');
+    $this->assertTrue(!$rule->dirty, 'Rule has been marked as not dirty again.');
+
+    // Test it with components.
+    module_enable(array('path'));
+    $action_set = rules_action_set(array('node' => array('type' => 'node')));
+    $action_set->action('node_path_alias');
+    $action_set->save('rules_test_alias');
+
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->action('component_rules_test_alias');
+    $rule->integrityCheck();
+    $rule->save('rules_test_rule');
+
+    $rule = rules_config_load('rules_test_rule');
+    $component = rules_config_load('rules_test_alias');
+    $this->assertTrue(in_array('path', $component->dependencies) && !$rule->dirty && !$component->dirty, 'Component has path module dependency.');
+
+    // Now disable path module and make sure both configs are marked as dirty.
+    module_disable(array('path'));
+    rules_clear_cache();
+    $rule = rules_config_load('rules_test_rule');
+    $component = rules_config_load('rules_test_alias');
+
+    $this->assertTrue($component->dirty, 'Component has been marked as dirty');
+    $node = $this->drupalCreateNode();
+    $result = rules_invoke_component('rules_test_alias', $node);
+    $this->assertTrue($result === FALSE, 'Unable to execute a dirty component.');
+
+    // When the rule is evaluated, the broken component is detected and the
+    // rule should be marked as dirty too.
+    $rule->execute($node);
+    $this->assertTrue($rule->dirty, 'Rule has been marked as dirty');
+
+    module_enable(array('path'));
+    rules_clear_cache();
+
+    // Trigger rebuilding the cache, so configs are checked again.
+    rules_get_cache();
+
+    $rule = rules_config_load('rules_test_rule');
+    $component = rules_config_load('rules_test_alias');
+    $this->assertTrue(!$component->dirty, 'Component has been marked as not dirty again.');
+    $this->assertTrue(!$rule->dirty, 'Rule has been marked as not dirty again.');
+  }
+
+  /**
+   * Test setting up an action with some action_info and serializing and
+   * executing it.
+   */
+  function testActionSetup() {
+    $action = rules_action('rules_node_publish_action');
+
+    $s = serialize($action);
+    $action2 = unserialize($s);
+    $node = (object) array('status' => 0, 'type' => 'page');
+    $node->title = 'test';
+
+    $action2->execute($node);
+    $this->assertEqual($node->status, 1, 'Action executed correctly');
+
+    $this->assertTrue(in_array('node', array_keys($action2->parameterInfo())), 'Parameter info returned.');
+
+    $node->status = 0;
+    $action2->integrityCheck();
+    $action2->executeByArgs(array('node' => $node));
+    $this->assertEqual($node->status, 1, 'Action executed correctly');
+
+    // Test calling an extended + overriden method.
+    $this->assertEqual($action2->help(), 'custom', 'Using custom help callback.');
+
+    // Inspect the cache
+    //$this->pass(serialize(rules_get_cache()));
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test executing with wrong arguments.
+   */
+  function testActionExecutionFails() {
+    $action = rules_action('rules_node_publish_action');
+    try {
+      $action->execute();
+      $this->fail("Execution hasn't created an exception.");
+    }
+    catch (RulesEvaluationException $e) {
+      $this->pass("RulesEvaluationException was thrown: ". $e);
+    }
+  }
+
+  /**
+   * Test setting up a rule and mapping variables.
+   */
+  function testVariableMapping() {
+    $rule = rule(array(
+      'node' => array('type' => 'node'),
+      'node_unchanged' => array('type' => 'node'),
+    ));
+    $rule->condition(rules_condition('rules_condition_content_is_published')->negate())
+         ->condition('rules_condition_content_is_type', array('type' => array('page', 'story')))
+         ->action('rules_node_publish_action', array('node:select' => 'node_unchanged'));
+
+    $node1 = $this->drupalCreateNode(array('status' => 0, 'type' => 'page'));
+    $node2 = $this->drupalCreateNode(array('status' => 0, 'type' => 'page'));
+    $rule->integrityCheck();
+    $rule->execute($node1, $node2);
+    $this->assertEqual($node2->status, 1, 'Action executed correctly on node2.');
+    $this->assertEqual($node1->status, 0, 'Action not executed on node1.');
+
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Tests making use of class based actions.
+   */
+  function testClassBasedActions() {
+    $cache = rules_get_cache();
+    $this->assertTrue(!empty($cache['action_info']['rules_test_class_action']), 'Action has been discovered.');
+    $action = rules_action('rules_test_class_action');
+
+    $parameters = $action->parameterInfo();
+    $this->assertTrue($parameters['node'], 'Action parameter needs a value.');
+
+    $node = $this->drupalCreateNode();
+    $action->execute($node);
+    $log = RulesLog::logger()->get();
+    $last = array_pop($log);
+    $last = array_pop($log);
+    $this->assertEqual($last[0], 'Action called with node ' . $node->nid, 'Action called');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Tests CRUD functionality.
+   */
+  function testRulesCRUD() {
+    $rule = $this->createTestRule();
+    $rule->integrityCheck()->save('test');
+
+    $this->assertEqual(TRUE, $rule->active, 'Rule is active.');
+    $this->assertEqual(0, $rule->weight, 'Rule weight is zero.');
+
+    $results = entity_load('rules_config', array('test'));
+    $rule2 = array_pop($results);
+    $this->assertEqual($rule->id, $rule2->id, 'Rule created and loaded');
+    $this->assertEqual(get_class($rule2), get_class($rule), 'Class properly instantiated.');
+    $rule2->execute();
+    // Update.
+    $rule2->save();
+
+    // Make sure all rule elements are still here.
+    $it = new RecursiveIteratorIterator($rule2->conditions(), RecursiveIteratorIterator::SELF_FIRST);
+    $this->assertEqual(iterator_count($it), 8, 'Iterated over all conditions and condition containers');
+    $it = new RecursiveIteratorIterator($rule2->conditions());
+    $this->assertEqual(iterator_count($it), 6, 'Iterated over all conditions');
+    $this->assertEqual(iterator_count($rule2->actions()), 1, 'Iterated over all actions');
+
+    // Delete.
+    $rule2->delete();
+    $this->assertEqual(entity_load('rules_config', FALSE, array('id' => $rule->id)), array(), 'Deleted.');
+
+    // Tests CRUD for tags - making sure the tags are stored properly..
+    $rule = $this->createTestRule();
+    $tag = $this->randomString();
+    $rule->tags = array($tag);
+    $rule->save();
+    $result = db_select('rules_tags')
+      ->fields('rules_tags', array('tag'))
+      ->condition('id', $rule->id)
+      ->execute();
+    $this->assertEqual($result->fetchField(), $tag, 'Associated tag has been saved.');
+    // Try updating.
+    $rule->tags = array($this->randomName(), $this->randomName());
+    $rule->integrityCheck()->save();
+    $result = db_select('rules_tags')
+      ->fields('rules_tags', array('tag'))
+      ->condition('id', $rule->id)
+      ->execute()
+      ->fetchCol();
+    $this->assertTrue(in_array($rule->tags[0], $result) && in_array($rule->tags[1], $result), 'Updated associated tags.');
+    // Try loading multiple rules by tags.
+    $rule2 = $this->createTestRule();
+    $rule2->tags = array($this->randomName());
+    $rule2->save();
+    $loaded = entity_load('rules_config', FALSE, array('tags' => array($rule->tags[0], $rule2->tags[0])));
+    $this->assertTrue($loaded[$rule->id]->id == $rule->id && $loaded[$rule2->id]->id == $rule2->id, 'Loading configs by tags');
+    // Try deleting.
+    $rule->delete();
+    $result = db_select('rules_tags')
+      ->fields('rules_tags', array('tag'))
+      ->condition('id', $rule->id)
+      ->execute();
+    $this->assertEqual($result->fetchField(), FALSE, 'Deleted associated tags.');
+  }
+
+  /**
+   * Test automatic saving of variables.
+   */
+  function testActionSaving() {
+    // Test saving a parameter.
+    $action = rules_action('rules_node_publish_action_save');
+    $node = $this->drupalCreateNode(array('status' => 0, 'type' => 'page'));
+    $action->executeByArgs(array('node' => $node));
+
+    $this->assertEqual($node->status, 1, 'Action executed correctly on node.');
+    // Sync node_load cache with node_save
+    entity_get_controller('node')->resetCache();
+
+    $node = node_load($node->nid);
+    $this->assertEqual($node->status, 1, 'Node has been saved.');
+
+    // Now test saving a provided variable, which is renamed and modified before
+    // it is saved.
+    $title = $this->randomName();
+    $rule = rule();
+    $rule->action('entity_create', array(
+      'type' => 'node',
+      'param_type' => 'article',
+      'param_author:select' => 'site:current-user',
+      'param_title' => $title,
+      'entity_created:var' => 'node',
+    ));
+    $rule->action('data_set', array(
+      'data:select' => 'node:body',
+      'value' => array('value' => 'body'),
+    ));
+    $rule->integrityCheck();
+    $rule->execute();
+
+    $node = $this->drupalGetNodeByTitle($title);
+    $this->assertTrue(!empty($node) && $node->body[LANGUAGE_NONE][0]['value'] == 'body', 'Saved a provided variable');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test adding a variable and optional parameters.
+   */
+  function testVariableAdding() {
+    $node = $this->drupalCreateNode();
+    $rule = rule(array('nid' => array('type' => 'integer')));
+    $rule->condition('rules_test_condition_true')
+         ->action('rules_action_load_node')
+         ->action('rules_action_delete_node', array('node:select' => 'node_loaded'))
+         ->execute($node->nid);
+
+    $this->assertEqual(FALSE, node_load($node->nid), 'Variable added and skipped optional parameter.');
+    RulesLog::logger()->checkLog();
+
+    $vars = $rule->conditions()->offsetGet(0)->availableVariables();
+    $this->assertEqual(!isset($vars['node_loaded']), 'Loaded variable is not available to conditions.');
+
+
+    // Test adding a variable with a custom variable name.
+    $node = $this->drupalCreateNode();
+    $rule = rule(array('nid' => array('type' => 'integer')));
+    $rule->action('rules_action_load_node', array('node_loaded:var' => 'node'))
+         ->action('rules_action_delete_node')
+         ->execute($node->nid);
+
+    $this->assertEqual(FALSE, node_load($node->nid), 'Variable with custom name added.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test custom access for using component actions/conditions.
+   */
+  function testRuleComponentAccess() {
+    // Create a normal user.
+    $normal_user = $this->drupalCreateUser();
+    // Create a role for granting access to the rule component.
+    $this->normal_role = $this->drupalCreateRole(array(), 'test_role');
+    $normal_user->roles[$this->normal_role] = 'test_role';
+    user_save($normal_user, array('roles' => $normal_user->roles));
+    // Create an 'action set' rule component making use of a permission.
+    $action_set = rules_action_set(array('node' => array('type' => 'node')));
+    $action_set->access_exposed = TRUE;
+    $action_set->save('rules_test_roles');
+
+    // Set the global user to be the current one as access is checked for the
+    // global user.
+    global $user;
+    $user = user_load($normal_user->uid);
+    $this->assertFalse(rules_action('component_rules_test_roles')->access(), 'Authenticated user without the correct role can\'t use the rule component.');
+
+    // Assign the role that will have permissions for the rule component.
+    user_role_change_permissions($this->normal_role, array('use Rules component rules_test_roles' => TRUE));
+    $this->assertTrue(rules_action('component_rules_test_roles')->access(), 'Authenticated user with the correct role can use the rule component.');
+
+    // Reset global user to anonyous.
+    $user = user_load(0);
+    $this->assertFalse(rules_action('component_rules_test_roles')->access(), 'Anonymous user can\'t use the rule component.');
+  }
+
+  /**
+   * Test passing arguments by reference to an action.
+   */
+  function testPassingByReference() {
+    // Keeping references of variables is unsupported, though the
+    // EntityMetadataArrayObject may be used to achieve that.
+    $array = array('foo' => 'bar');
+    $data = new EntityMetadataArrayObject($array);
+    rules_action('rules_action_test_reference')->execute($data);
+    $this->assertTrue($data['changed'], 'Parameter has been passed by reference');
+  }
+
+  /**
+   * Test sorting rule elements.
+   */
+  function testSorting() {
+    $rule = $this->createTestRule();
+    $conditions = $rule->conditions();
+    $conditions[0]->weight = 10;
+    $conditions[2]->weight = 10;
+    $id[0] = $conditions[0]->elementId();
+    $id[1] = $conditions[1]->elementId();
+    $id[2] = $conditions[2]->elementId();
+    // For testing use a deep sort, even if not necessary here.
+    $rule->sortChildren(TRUE);
+    $conditions = $rule->conditions();
+    $this->assertEqual($conditions[0]->elementId(), $id[1], 'Condition sorted correctly.');
+    $this->assertEqual($conditions[1]->elementId(), $id[0], 'Condition sorted correctly.');
+    $this->assertEqual($conditions[2]->elementId(), $id[2], 'Condition sorted correctly.');
+  }
+
+  /**
+   * Tests using data selectors.
+   */
+  function testDataSelectors() {
+    $body[LANGUAGE_NONE][0] = array('value' => '<b>The body & nothing.</b>');
+    $node = $this->drupalCreateNode(array('body' => $body, 'type' => 'page', 'summary' => ''));
+
+    $rule = rule(array('nid' => array('type' => 'integer')));
+    $rule->action('rules_action_load_node')
+         ->action('drupal_message', array('message:select' => 'node_loaded:body:value'))
+         ->execute($node->nid);
+
+    RulesLog::logger()->checkLog();
+    $msg = drupal_get_messages('status');
+    $last_msg = array_pop($msg['status']);
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $this->assertEqual($last_msg, $wrapper->body->value->value(array('sanitize' => TRUE)), 'Data selector for getting parameter applied.');
+
+    // Get a "reference" on the same object as returned by node_load().
+    $node = node_load($node->nid);
+    $rule = rule(array('nid' => array('type' => 'integer')));
+    $rule->action('rules_action_load_node')
+         ->action('data_set', array('data:select' => 'node_loaded:title', 'value' => 'Test title'))
+         // Use two actions and make sure the node get saved only once.
+         ->action('data_set', array('data:select' => 'node_loaded:title', 'value' => 'Test title2'))
+         ->execute($node->nid);
+
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $this->assertEqual('Test title2', $wrapper->title->value(), 'Data has been modified and saved.');
+
+    RulesLog::logger()->checkLog();
+    $text = RulesLog::logger()->render();
+    $msg = RulesTestCase::t('Saved %node_loaded of type %node.', array('node_loaded', 'node'));
+    if ($pos1 = strpos($text, $msg)) {
+      $pos2 = strpos($text, $msg, $pos1 + 1);
+    }
+    $this->assertTrue($pos1 && $pos2 === FALSE, 'Data has been saved only once.');
+
+    // Test validation.
+    try {
+      rules_action('data_set', array('data' => 'no-selector', 'value' => ''))->integrityCheck();
+      $this->fail("Validation hasn't created an exception.");
+    }
+    catch (RulesIntegrityException $e) {
+      $this->pass("Validation error correctly detected: ". $e);
+    }
+
+    // Test auto creation of nested data structures, like the node body field.
+    // I.e. if $node->body is not set, it is automatically initialized to an
+    // empty array, so that the nested value can be set and the wrappers do not
+    // complain about missing parent data structures.
+    $rule = rule();
+    $rule->action('entity_create', array(
+      'type' => 'node',
+      'param_type' => 'page',
+      'param_title' => 'foo',
+      'param_author' => $GLOBALS['user'],
+    ));
+    $rule->action('data_set', array('data:select' => 'entity_created:body:value', 'value' => 'test content'))
+         ->execute();
+    try {
+      RulesLog::logger()->checkLog();
+      $this->pass('Auto creation of nested data structures.');
+    }
+    catch (Exception $e) {
+      $this->fail('Auto creation of nested data structures.');
+    }
+
+    // Make sure variables that are passed wrapped work.
+    $result = rules_condition('rules_test_condition_node_wrapped')->execute($node->nid);
+    $this->assertTrue($result, 'Condition receiving wrapped parameter.');
+
+    // Make sure wrapped parameters are checked for containing NULL values.
+    $rule = rule(array('node' => array('type' => 'node', 'optional' => TRUE)));
+    $rule->condition('rules_test_condition_node_wrapped', array('node:select' => 'node'));
+    $rule->execute(entity_metadata_wrapper('node'));
+    $text = RulesLog::logger()->render();
+    $msg = RulesTestCase::t('The variable or parameter %node is empty.', array('node'));
+    $this->assertTrue(strpos($text, $msg) !== FALSE, 'Evaluation aborted due to an empty argument value.');
+  }
+
+  /**
+   * Tests making use of rule sets.
+   */
+  function testRuleSets() {
+    $set = rules_rule_set(array(
+      'node' => array('type' => 'node', 'label' => 'node'),
+    ));
+    $set->rule(rule()->action('drupal_message', array('message:select' => 'node:title')))
+        ->rule(rule()->condition('rules_condition_content_is_published')
+                     ->action('drupal_message', array('message' => 'Node is published.'))
+               );
+    $set->integrityCheck()->save('rules_test_set_1');
+
+    $node = $this->drupalCreateNode(array('title' => 'The title.', 'status' => 1));
+    // Execute.
+    rules_invoke_component('rules_test_set_1', $node);
+
+    $msg = drupal_get_messages();
+    $this->assertEqual($msg['status'][0], 'The title.', 'First rule evaluated.');
+    $this->assertEqual($msg['status'][1], 'Node is published.', 'Second rule evaluated.');
+
+    // Test a condition set.
+    $set = rules_or(array(
+      'node' => array('type' => 'node', 'label' => 'node'),
+    ));
+    $set->condition('data_is', array('data:select' => 'node:author:name', 'value' => 'notthename'))
+        ->condition('data_is', array('data:select' => 'node:nid', 'value' => $node->nid))
+        ->integrityCheck()
+        ->save('test', 'rules_test');
+    // Load and execute condition set.
+    $set = rules_config_load('test');
+    $this->assertTrue($set->execute($node), 'Set has been correctly evaluated.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Tests invoking components from the action.
+   */
+  function testComponentInvocations() {
+    $set = rules_rule_set(array(
+      'node1' => array('type' => 'node', 'label' => 'node'),
+    ));
+    $set->rule(rule()->condition('node_is_published', array('node:select' => 'node1'))
+                     ->action('node_unpublish', array('node:select' => 'node1'))
+               );
+    $set->integrityCheck()->save('rules_test_set_2');
+
+    // Use different names for the variables to ensure they are properly mapped
+    // when taking over the variables to be saved.
+    $rule = rule(array(
+      'node2' => array('type' => 'node', 'label' => 'node'),
+    ));
+    $rule->action('component_rules_test_set_2', array('node1:select' => 'node2'));
+    $rule->action('node_make_sticky', array('node:select' => 'node2'));
+
+    $node = $this->drupalCreateNode(array('title' => 'The title.', 'status' => 1, 'sticky' => 0));
+    $rule->execute($node);
+
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertFalse($node->status, 'The component changes have been saved correctly.');
+    $this->assertTrue($node->sticky, 'The action changes have been saved correctly.');
+
+    // Check that we have saved the changes only once.
+    $text = RulesLog::logger()->render();
+    // Make sure both saves are handled in one save operation.
+    $this->assertEqual(substr_count($text, 'Saved'), 1, 'Changes have been saved in one save operation.');
+    RulesLog::logger()->checkLog();
+
+    // Test recursion prevention on components by invoking the component from
+    // itself, what should be prevented.
+    $set->action('component_rules_test_set_2', array('node1:select' => 'node1'))
+        ->save();
+
+    $rule->execute($node);
+    $text1 = RulesLog::logger()->render();
+    $text2 = RulesTestCase::t('Not evaluating rule set %rules_test_set_2 to prevent recursion.', array('rules_test_set_2'));
+    $this->assertTrue((strpos($text1, $text2) !== FALSE), "Recursion of component invocation prevented.");
+
+    // Test executing the component provided in code via the action. This makes
+    // sure the component in code has been properly picked up.
+    $node->status = 0;
+    node_save($node);
+    rules_action('component_rules_test_action_set')->execute($node);
+    $this->assertTrue($node->status == 1, 'Component provided in code has been executed.');
+  }
+
+
+  /**
+   * Test asserting metadata, customizing action info and make sure integrity
+   * is checked.
+   */
+  function testMetadataAssertion() {
+    $action = rules_action('rules_node_make_sticky_action');
+
+    // Test failing integrity check.
+    try {
+      $rule = rule(array('node' => array('type' => 'entity')));
+      $rule->action($action);
+      // Fails due to the 'node' variable not matching the node type.
+      $rule->integrityCheck();
+      $this->fail('Integrity check has not thrown an exception.');
+    }
+    catch (RulesIntegrityException $e) {
+      $this->pass('Integrity check has thrown exception: ' . $e->getMessage());
+    }
+
+    // Test asserting additional metadata.
+    $rule = rule(array('node' => array('type' => 'node')));
+    // Customize action info using the settings.
+    $rule->condition('data_is', array('data:select'   => 'node:type', 'value' => 'page'))
+         // Configure an condition using the body. As the body is a field,
+         // tis requires the bundle to be correctly asserted.
+         ->condition(rules_condition('data_is', array('data:select' => 'node:body:value', 'value' => 'foo'))->negate())
+         // The action also requires the page bundle in order to work.
+         ->action($action);
+    // Make sure the integrity check doesn't throw an exception.
+    $rule->integrityCheck();
+    // Test the rule.
+    $node = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0));
+    $rule->execute($node);
+    $this->assertTrue($node->sticky, 'Rule with asserted metadata executed.');
+
+
+    // Test asserting metadata on a derived property, i.e. not a variable.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('entity_is_of_type', array('entity:select' => 'node:reference', 'type' => 'node'))
+         ->condition('data_is', array('data:select' => 'node:reference:type', 'value' => 'page'))
+         ->action('rules_node_page_make_sticky_action', array('node:select' => 'node:reference'));
+    $rule->integrityCheck();
+    $rule->execute($node);
+
+    // Test asserting an entity field.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('entity_has_field', array('entity:select' => 'node:reference', 'field' => 'field_tags'))
+         ->action('data_set', array('data:select' => 'node:reference:field-tags', 'value' => array()));
+    $rule->integrityCheck();
+    $rule->execute($node);
+
+    // Make sure an asserted bundle can be used as argument.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('entity_is_of_type', array('entity:select' => 'node:reference', 'type' => 'node'))
+         ->condition('node_is_of_type', array('node:select' => 'node:reference', 'type' => array('page')))
+         ->action('rules_node_page_make_sticky_action', array('node:select' => 'node:reference'));
+    $rule->integrityCheck();
+    $rule->execute($node);
+
+    // Test asserting metadata on a derived property being a list item.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('node_is_of_type', array('node:select' => 'node:ref-nodes:0', 'type' => array('article')))
+         ->action('data_set', array('data:select' => 'node:ref-nodes:0:field-tags', 'value' => array()));
+    $rule->integrityCheck();
+    $rule->execute($node);
+
+    // Give green lights if there were no exceptions and check rules-log errors.
+    $this->pass('Rules asserting metadata on a derived property pass integrity checks.');
+    RulesLog::logger()->checkLog();
+
+    // Make sure assertions of a one list item are not valid for another item.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('node_is_of_type', array('node:select' => 'node:ref-nodes:0', 'type' => array('article')))
+         ->action('data_set', array('data:select' => 'node:ref-nodes:1:field-tags', 'value' => array()));
+    try {
+      $rule->integrityCheck();
+      $this->fail('Assertion of a list item is not valid for another item.');
+    }
+    catch (RulesException $e) {
+      $this->pass('Assertion of a list item is not valid for another item.');
+    }
+  }
+
+  /**
+   * Test using loops.
+   */
+  function testLoops() {
+    // Test passing the list parameter as argument to ensure that is working
+    // generally for plugin container too.
+    drupal_get_messages(NULL, TRUE);
+    $loop = rules_loop();
+    $loop->action('drupal_message', array('message' => 'test'));
+    $arg_info = $loop->parameterInfo();
+    $this->assert($arg_info['list']['type'] == 'list', 'Argument info contains list.');
+    $loop->execute(array(1, 2));
+
+    // Ensure the action has been executed twice, once for each list item.
+    $msg = drupal_get_messages();
+    $this->assert($msg['status'][0] == 'test' && $msg['status'][1], 'Loop has been properly executed');
+
+    // Now test looping over nodes.
+    $node1 = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0));
+    $node2 = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0));
+    $node3 = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0));
+
+    $rule = rule(array(
+      'list' => array(
+        'type' => 'list<node>',
+        'label' => 'A list of nodes',
+      )
+    ));
+    $loop = rules_loop(array('list:select' => 'list', 'item:var' => 'node'));
+    $loop->action('data_set', array('data:select' => 'node:sticky', 'value' => TRUE));
+    $rule->action($loop);
+    // Test using a list with data selectors, just output the last nodes type.
+    $rule->action('drupal_message', array('message:select' => 'list:2:type'));
+
+    $rule->execute(array($node1->nid, $node2->nid, $node3->nid));
+    $text = RulesLog::logger()->render();
+    $save_msg = RulesTestCase::t('Saved %node of type %node.', array('node', 'node'));
+    $this->assertTrue(substr_count($text, $save_msg) == 3, 'List item variables have been saved.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test access checks.
+   */
+  function testAccessCheck() {
+    $rule = rule();
+    // Try to set a property which is provided by the test module and is not
+    // accessible, so the access check has to return FALSE.
+    $rule->action('data_set', array('data:select' => 'site:no-access-user', 'value' => 'foo'));
+    $this->assertTrue($rule->access() === FALSE, 'Access check is working.');
+  }
+
+  /**
+   * Test returning provided variables.
+   */
+  function testReturningVariables() {
+    $node = $this->drupalCreateNode();
+    $action = rules_action('entity_fetch', array('type' => 'node', 'id' => $node->nid));
+    list($node2) = $action->execute();
+    $this->assertTrue($node2->nid == $node->nid, 'Action returned a variable.');
+
+    // Create a simple set that just passed through the given node.
+    $set = rules_rule_set(array('node' => array('type' => 'node')), array('node'));
+    $set->integrityCheck()->save('rules_test_set_1');
+
+    $provides = $set->providesVariables();
+    $this->assertTrue($provides['node']['type'] == 'node', 'Rule set correctly passed through the node.');
+
+    list($node2) = $set->execute($node);
+    $this->assertTrue($node2->nid == $node->nid, 'Rule set returned a variable.');
+
+    // Create an action set returning a variable that is no parameter.
+    $set = rules_action_set(array(
+      'node' => array(
+        'type' => 'node',
+        'parameter' => FALSE,
+      )), array('node'));
+    $set->action('entity_fetch', array('type' => 'node', 'id' => $node->nid))
+        ->action('data_set', array('data:select' => 'node', 'value:select' => 'entity_fetched'));
+    $set->integrityCheck();
+    list($node3) = $set->execute();
+    $this->assertTrue($node3->nid == $node->nid, 'Action set returned a variable that has not been passed as parameter.');
+
+    // Test the same again with a variable holding a not wrapped data type.
+    $set = rules_action_set(array(
+      'number' => array(
+        'type' => 'integer',
+        'parameter' => FALSE,
+      )), array('number'));
+    $set->action('data_set', array('data:select' => 'number', 'value' => 3));
+    $set->integrityCheck();
+    list($number) = $set->execute();
+    $this->assertTrue($number == 3, 'Actions set returned a number.');
+  }
+
+  /**
+   * Tests using input evaluators.
+   */
+  function testInputEvaluators() {
+    $node = $this->drupalCreateNode(array('title' => '<b>The body & nothing.</b>', 'type' => 'page'));
+
+    $rule = rule(array('nid' => array('type' => 'integer')));
+    $rule->action('rules_action_load_node')
+         ->action('drupal_message', array('message' => 'Title: [node_loaded:title]'))
+         ->execute($node->nid);
+
+    RulesLog::logger()->checkLog();
+    $msg = drupal_get_messages();
+    $this->assertEqual(array_pop($msg['status']), 'Title: ' . check_plain('<b>The body & nothing.</b>'), 'Token input evaluator applied.');
+
+    // Test token replacements on a list of text values.
+    $component = rules_action_set(array('var' => array('type' => 'list<text>', 'label' => 'var')), array('var'));
+    $component->save('rules_test_input');
+
+    $action = rules_action('component_rules_test_input', array('var' => array('uid: [site:current-user:uid]')));
+    list($var) = $action->execute();
+    $uid = $GLOBALS['user']->uid;
+    $this->assertEqual(array("uid: $uid"), $var, 'Token replacements on a list of values applied.');
+  }
+
+  /**
+   * Test importing and exporting a rule.
+   */
+  function testRuleImportExport() {
+    $rule = rule(array('nid' => array('type' => 'integer')));
+    $rule->name = "rules_export_test";
+    $rule->action('rules_action_load_node')
+         ->action('drupal_message', array('message' => 'Title: [node_loaded:title]'));
+
+    $export =
+'{ "rules_export_test" : {
+    "PLUGIN" : "rule",
+    "REQUIRES" : [ "rules_test", "rules" ],
+    "USES VARIABLES" : { "nid" : { "type" : "integer" } },
+    "DO" : [
+      { "rules_action_load_node" : { "PROVIDE" : { "node_loaded" : { "node_loaded" : "Loaded content" } } } },
+      { "drupal_message" : { "message" : "Title: [node_loaded:title]" } }
+    ]
+  }
+}';
+    $this->assertEqual($export, $rule->export(), 'Rule has been exported correctly.');
+
+    // Test importing a rule which makes use of almost all features.
+    $export = _rules_export_get_test_export();
+    $rule = rules_import($export);
+    $this->assertTrue(!empty($rule) && $rule->integrityCheck(), 'Rule has been imported.');
+
+    // Test loading the same export provided as default rule.
+    $rule = rules_config_load('rules_export_test');
+    $this->assertTrue(!empty($rule) && $rule->integrityCheck(), 'Export has been provided in code.');
+
+    // Export it and make sure the same export is generated again.
+    $this->assertEqual($export, $rule->export(), 'Export of imported rule equals original export.');
+
+    // Now try importing a rule set.
+    $export =
+'{ "rules_test_set" : {
+    "LABEL" : "Test set",
+    "PLUGIN" : "rule set",
+    "REQUIRES" : [ "rules" ],
+    "USES VARIABLES" : { "node" : { "label" : "Test node", "type" : "node" } },
+    "RULES" : [
+      { "RULE" : {
+          "IF" : [ { "NOT data_is" : { "data" : [ "node:title" ], "value" : "test" } } ],
+          "DO" : [ { "data_set" : { "data" : [ "node:title" ], "value" : "test" } } ],
+          "LABEL" : "Test Rule"
+        }
+      },
+      { "RULE" : {
+          "DO" : [ { "drupal_message" : { "message" : "hi" } } ],
+          "LABEL" : "Test Rule 2"
+        }
+      }
+    ]
+  }
+}';
+    $set = rules_import($export);
+    $this->assertTrue(!empty($set) && $set->integrityCheck(), 'Rule set has been imported.');
+    // Export it and make sure the same export is generated again.
+    $this->assertEqual($export, $set->export(), 'Export of imported rule set equals original export.');
+
+    // Try executing the imported rule set.
+    $node = $this->drupalCreateNode();
+    $set->execute($node);
+    $this->assertEqual($node->title, 'test', 'Imported rule set has been executed.');
+    RulesLog::logger()->checkLog();
+
+    // Try import / export for a rule component providing a variable.
+    $rule = rule(array(
+      'number' => array(
+        'type' => 'integer',
+        'label' => 'Number',
+        'parameter' => FALSE,
+      )), array('number'));
+    $rule->action('data_set', array('data:select' => 'number', 'value' => 3));
+    $rule->name = 'rules_test_provides';
+
+    $export = '{ "rules_test_provides" : {
+    "PLUGIN" : "rule",
+    "REQUIRES" : [ "rules" ],
+    "USES VARIABLES" : { "number" : { "type" : "integer", "label" : "Number", "parameter" : false } },
+    "DO" : [ { "data_set" : { "data" : [ "number" ], "value" : 3 } } ],
+    "PROVIDES VARIABLES" : [ "number" ]
+  }
+}';
+    $this->assertEqual($export, $rule->export(), 'Rule 2 has been exported correctly.');
+    $imported_rule = rules_import($rule->export());
+
+    $this->assertTrue(!empty($imported_rule) && $imported_rule->integrityCheck(), 'Rule 2 has been imported.');
+    $this->assertEqual($export, $imported_rule->export(), 'Export of imported rule 2 equals original export.');
+
+    // Test importing a negated condition component.
+    $export = '{ "rules_negated_component" : {
+    "LABEL" : "negated_component",
+    "PLUGIN" : "or",
+    "REQUIRES" : [ "rules" ],
+    "NOT OR" : [ { "data_is_empty" : { "data" : [ "site:slogan" ] } } ]
+  }
+}';
+    $or = rules_import($export);
+    $this->assertTrue($or->integrityCheck() && $or->isNegated(), 'Negated condition component imported.');
+  }
+
+  /**
+   * Test the named parameter mode.
+   */
+  function testNamedParameters() {
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->action('rules_action_node_set_title', array('title' => 'foo'));
+    $rule->integrityCheck();
+
+    // Test the rule.
+    $node = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0));
+    $rule->execute($node);
+    $this->assertTrue($node->title == 'foo', 'Action with named parameters has been correctly executed.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Make sure Rules aborts when NULL values are used.
+   */
+  function testAbortOnNULLValues() {
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->action('drupal_message', array('message:select' => 'node:log'));
+    $rule->integrityCheck();
+
+    // Test the rule.
+    $node = $this->drupalCreateNode();
+    $node->log = NULL;
+    $rule->execute($node);
+
+    $text = RulesLog::logger()->render();
+    $msg = RulesTestCase::t('The variable or parameter %message is empty.', array('message'));
+    $this->assertTrue(strpos($text, $msg) !== FALSE, 'Evaluation aborted due to an empty argument value.');
+  }
+}
+
+/**
+ * Test rules data wrappers.
+ */
+class RulesTestDataCase extends DrupalWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Rules Data tests',
+      'description' => 'Tests rules data saving and type matching.',
+      'group' => 'Rules',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rules', 'rules_test');
+    variable_set('rules_debug_log', 1);
+    // Make sure we don't ran over issues with the node_load static cache.
+    entity_get_controller('node')->resetCache();
+  }
+
+  /**
+   * Tests intelligently saving data.
+   */
+  function testDataSaving() {
+    $node = $this->drupalCreateNode();
+    $state = new RulesState(rule());
+    $state->addVariable('node', $node, array('type' => 'node'));
+    $wrapper = $state->get('node');
+    $node->title = 'test';
+    $wrapper->set($node);
+    $state->saveChanges('node', $wrapper, FALSE);
+
+    $this->assertFalse($this->drupalGetNodeByTitle('test'), 'Changes have not been saved.');
+    $state->saveChanges('node', $wrapper, TRUE);
+    $this->assertTrue($this->drupalGetNodeByTitle('test'), 'Changes have been saved.');
+
+    // Test skipping saving.
+    $state->addVariable('node2', $node, array(
+      'type' => 'node',
+      'skip save' => TRUE,
+    ));
+    $wrapper = $state->get('node2');
+    $node->title = 'test2';
+    $wrapper->set($node);
+    $state->saveChanges('node2', $wrapper, TRUE);
+    $this->assertFalse($this->drupalGetNodeByTitle('test2'), 'Changes have not been saved.');
+
+    // Try saving a non-entity wrapper, which should result in saving the
+    // parent entity containing the property.
+    $wrapper = $state->get('node');
+    $wrapper->title->set('test3');
+    $state->saveChanges('node:title', $wrapper, TRUE);
+    $this->assertTrue($this->drupalGetNodeByTitle('test3'), 'Parent entity has been saved.');
+  }
+
+  /**
+   * Test type matching
+   */
+  function testTypeMatching() {
+    $entity = array('type' => 'entity');
+    $node = array('type' => 'node');
+    $this->assertTrue(RulesData::typesMatch($node, $entity), 'Types match.');
+    $this->assertFalse(RulesData::typesMatch($entity, $node), 'Types don\'t match.');
+
+    $this->assertTrue(RulesData::typesMatch($node + array('bundle' => 'page'), $node), 'Types match.');
+    $this->assertTrue(RulesData::typesMatch($node + array('bundle' => 'page'), $entity), 'Types match.');
+    $this->assertTrue(RulesData::typesMatch(array('type' => 'list<node>'), array('type' => 'list')), 'Types match.');
+    $this->assertTrue(RulesData::typesMatch($node + array('bundle' => 'page'), $node + array('bundles' => array('page', 'story'))), 'Types match.');
+    $this->assertFalse(RulesData::typesMatch($node, $node + array('bundles' => array('page', 'story'))), 'Types don\'t match.');
+
+    // Test that a type matches its grand-parent type (text > decimal > integer)
+    $this->assertTrue(RulesData::typesMatch(array('type' => 'integer'), array('type' => 'text')), 'Types match.');
+    $this->assertFalse(RulesData::typesMatch(array('type' => 'text'), array('type' => 'integer')), 'Types don\'t match.');
+  }
+
+  /**
+   * Tests making use of custom wrapper classes.
+   */
+  function testCustomWrapperClasses() {
+    // Test loading a vocabulary by name, which is done by a custom wrapper.
+    $set = rules_action_set(array('vocab' => array('type' => 'taxonomy_vocabulary')), array('vocab'));
+    $set->action('drupal_message', array('message:select' => 'vocab:name'));
+    $set->integrityCheck();
+    list($vocab) = $set->execute('tags');
+    $this->assertTrue($vocab->machine_name == 'tags', 'Loaded vocabulary by name.');
+
+    // Now test wrapper creation for a direct input argument value.
+    $set = rules_action_set(array('term' => array('type' => 'taxonomy_term')));
+    $set->action('data_set', array('data:select' => 'term:vocabulary', 'value' => 'tags'));
+    $set->integrityCheck();
+
+    $vocab = entity_create('taxonomy_vocabulary', array(
+      'name' => 'foo',
+      'machine_name' => 'foo',
+    ));
+    entity_save('taxonomy_vocabulary', $vocab);
+    $term_wrapped = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => $vocab,
+    ))->save();
+    $set->execute($term_wrapped);
+    $this->assertEqual($term_wrapped->vocabulary->machine_name->value(), 'tags', 'Vocabulary name used as direct input value.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Makes sure the RulesIdentifiableDataWrapper is working correctly.
+   */
+  function testRulesIdentifiableDataWrapper() {
+    $node = $this->drupalCreateNode();
+    $wrapper = new RulesTestTypeWrapper('rules_test_type', $node);
+    $this->assertTrue($wrapper->value() == $node, 'Data correctly wrapped.');
+
+    // Test serializing and make sure only the id is stored.
+    $this->assertTrue(strpos(serialize($wrapper), $node->title) === FALSE, 'Data has been correctly serialized.');
+    $this->assertEqual(unserialize(serialize($wrapper))->value()->title, $node->title, 'Serializing works right.');
+
+    $wrapper2 = unserialize(serialize($wrapper));
+    // Test serializing the unloaded wrapper.
+    $this->assertEqual(unserialize(serialize($wrapper2))->value()->title, $node->title, 'Serializing works right.');
+
+    // Test loading a not more existing node.
+    $s = serialize($wrapper2);
+    node_delete($node->nid);
+    $this->assertFalse(node_load($node->nid), 'Node deleted.');
+    try {
+      unserialize($s)->value();
+      $this->fail("Loading hasn't created an exception.");
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass("Exception was thrown: ". $e->getMessage());
+    }
+
+    // Test saving a savable custom, identifiable wrapper.
+    $action = rules_action('test_type_save');
+    $node = $this->drupalCreateNode(array('status' => 0, 'type' => 'page'));
+    $node->status = 1;
+    $action->execute($node);
+
+    // Load the node fresh from the db.
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertEqual($node->status, 1, 'Savable non-entity has been saved.');
+  }
+}
+
+/**
+ * Test triggering rules.
+ */
+class RulesTriggerTestCase extends DrupalWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Reaction Rules',
+      'description' => 'Tests triggering reactive rules.',
+      'group' => 'Rules',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rules', 'rules_test');
+    RulesLog::logger()->clear();
+    variable_set('rules_debug_log', 1);
+  }
+
+  protected function createTestRule($action = TRUE, $event = 'node_presave') {
+    $rule = rules_reaction_rule();
+    $rule->event($event)
+         ->condition(rules_condition('data_is', array('data:select' => 'node:status', 'value' => TRUE))->negate())
+         ->condition('data_is', array('data:select' => 'node:type', 'value' => 'page'));
+    if ($action) {
+      $rule->action('rules_action_delete_node');
+    }
+    return $rule;
+  }
+
+  /**
+   * Tests CRUD for reaction rules - making sure the events are stored properly.
+   */
+  function testReactiveRuleCreation() {
+    $rule = $this->createTestRule();
+    $rule->save();
+    $result = db_query("SELECT event FROM {rules_trigger} WHERE id = :id", array(':id' => $rule->id));
+    $this->assertEqual($result->fetchField(), 'node_presave', 'Associated event has been saved.');
+    // Try updating.
+    $rule->removeEvent('node_presave');
+    $rule->event('node_insert');
+    $rule->event('node_update');
+    $rule->active = FALSE;
+    $rule->integrityCheck()->save();
+    $result = db_query("SELECT event FROM {rules_trigger} WHERE id = :id", array(':id' => $rule->id));
+    $this->assertEqual($result->fetchCol(), array_values($rule->events()), 'Updated associated events.');
+    // Try deleting.
+    $rule->delete();
+    $result = db_query("SELECT event FROM {rules_trigger} WHERE id = :id", array(':id' => $rule->id));
+    $this->assertEqual($result->fetchField(), FALSE, 'Deleted associated events.');
+  }
+
+  /**
+   * Tests creating and triggering a basic reaction rule.
+   */
+  function testBasicReactionRule() {
+    $node = $this->drupalCreateNode(array('type' => 'page'));
+    $rule = $this->createTestRule();
+    $rule->integrityCheck()->save();
+    // Test the basics of the event set work right.
+    $event = rules_get_cache('event_node_presave');
+    $this->assertEqual(array_keys($event->parameterInfo()), array('node'), 'EventSet returns correct argument info.');
+
+    // Trigger the rule by updating the node.
+    $nid = $node->nid;
+    $node->status = 0;
+    node_save($node);
+
+    RulesLog::logger()->checkLog();
+    $this->assertFalse(node_load($nid), 'Rule successfully triggered and executed');
+    //debug(RulesLog::logger()->render());
+  }
+
+  /**
+   * Test a rule using a handler to load a variable.
+   */
+  function testVariableHandler() {
+    $node = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0, 'status' => 0));
+    $rule = $this->createTestRule(FALSE, 'node_update');
+    $rule->action('rules_node_publish_action_save', array('node:select' => 'node_unchanged'));
+    // Test without recursion prevention to make sure recursive invocations
+    // work right too. This rule won't ran in an infinite loop anyway.
+    $rule->recursion = TRUE;
+    $rule->label = 'rule 1';
+    $rule->integrityCheck()->save();
+
+    $node->status = 0;
+    $node->sticky = 1;
+    node_save($node);
+
+    RulesLog::logger()->checkLog();
+    entity_get_controller('node')->resetCache();
+    $node = node_load($node->nid);
+
+    $this->assertFalse($node->sticky, 'Parameter has been loaded and saved.');
+    $this->assertTrue($node->status, 'Action has been executed.');
+
+    // Ensure the rule was evaluated a second time
+    $text = RulesLog::logger()->render();
+    $msg = RulesTestCase::t('Evaluating conditions of rule %rule 1', array('rule 1'));
+    $pos = strpos($text, $msg);
+    $pos = ($pos !== FALSE) ? strpos($text, $msg, $pos) : FALSE;
+    $this->assertTrue($pos !== FALSE, "Recursion prevented.");
+    //debug(RulesLog::logger()->render());
+  }
+
+  /**
+   * Test aborting silently when handlers are not able to load.
+   */
+  function testVariableHandlerFailing() {
+    $rule = $this->createTestRule(FALSE, 'node_presave');
+    $rule->action('rules_node_publish_action_save', array('node:select' => 'node_unchanged'));
+    $rule->integrityCheck()->save();
+
+    // On insert it's not possible to get the unchanged node during presave.
+    $node = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0, 'status' => 0));
+
+    //debug(RulesLog::logger()->render());
+    $text = RulesTestCase::t('Unable to load variable %node_unchanged, aborting.', array('node_unchanged'));
+    $this->assertTrue(strpos(RulesLog::logger()->render(), $text) !== FALSE, "Aborted evaluation.");
+  }
+
+  /**
+   * Tests preventing recursive rule invocations by creating a rule that reacts
+   * on node-update and generates a node update that would trigger it itself.
+   */
+  function testRecursionPrevention() {
+    $rule = $this->createTestRule(FALSE, 'node_update');
+    $rule->action('rules_node_make_sticky_action');
+    $rule->integrityCheck()->save();
+
+    // Now trigger the rule.
+    $node = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0, 'status' => 0));
+    node_save($node);
+
+    $text = RulesTestCase::t('Not evaluating reaction rule %label to prevent recursion.', array('label' => $rule->name));
+    //debug(RulesLog::logger()->render());
+    $this->assertTrue((strpos(RulesLog::logger()->render(), $text) !== FALSE), "Recursion prevented.");
+    //debug(RulesLog::logger()->render());
+  }
+
+  /**
+   * Ensure the recursion prevention still allows to let the rule trigger again
+   * during evaluation of the same event set, if the event isn't caused by the
+   * rule itself - thus we won't run in an infinte loop.
+   */
+  function testRecursionOnDifferentArguments() {
+    // Create rule1 - which might recurse.
+    $rule = $this->createTestRule(FALSE, 'node_update');
+    $rule->action('rules_node_make_sticky_action');
+    $rule->label = 'rule 1';
+    $rule->integrityCheck()->save();
+
+    // Create rule2 - which triggers rule1 on another node.
+    $node2 = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0, 'status' => 0));
+    $rule2 = $this->createTestRule(FALSE, 'node_update');
+    $rule2->action('rules_action_load_node', array('nid' => $node2->nid))
+          ->action('rules_node_make_sticky_action', array('node:select' => 'node_loaded'));
+    $rule2->label = 'rule 2';
+    $rule2->save();
+
+    // Now trigger both rules by generating the event.
+    $node = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0, 'status' => 0));
+    node_save($node);
+
+    //debug(RulesLog::logger()->render());
+    $text = RulesLog::logger()->render();
+    $pos = strpos($text, RulesTestCase::t('Evaluating conditions of rule %rule 1', array('rule 1')));
+    $pos = ($pos !== FALSE) ? strpos($text, RulesTestCase::t('Evaluating conditions of rule %rule 2', array('rule 2')), $pos) : FALSE;
+    $pos = ($pos !== FALSE) ? strpos($text, RulesTestCase::t('Saved %node_loaded of type %node.', array('node_loaded', 'node')), $pos) : FALSE;
+    $pos = ($pos !== FALSE) ? strpos($text, RulesTestCase::t('Evaluating conditions of rule %rule 1', array('rule 1')), $pos) : FALSE;
+    $pos = ($pos !== FALSE) ? strpos($text, RulesTestCase::t('Not evaluating reaction rule %rule 2 to prevent recursion', array('rule 2')), $pos) : FALSE;
+    $this->assertTrue($pos !== FALSE, 'Rule1 was triggered on the event caused by Rule2.');
+  }
+
+  /**
+   * Tests the provided default rule 'rules_test_default_1'.
+   */
+  function testDefaultRule() {
+    $rule = rules_config_load('rules_test_default_1');
+    $this->assertTrue($rule->status & ENTITY_IN_CODE && !($rule->status & ENTITY_IN_DB), 'Default rule can be loaded and has the right status.');
+    // Enable.
+    $rule->active = TRUE;
+    $rule->save();
+
+    // Create a node that triggers the rule.
+    $node = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0, 'status' => 0));
+    // Clear messages.
+    drupal_get_messages();
+    // Let event node_update occur.
+    node_save($node);
+
+    $msg = drupal_get_messages();
+    $this->assertEqual($msg['status'][0], 'A node has been updated.', 'Default rule has been triggered.');
+  }
+
+  /**
+   * Tests creating and triggering a reaction rule with event settings.
+   */
+  function testEventSettings() {
+    $rule = rules_reaction_rule();
+    $rule->event('node_presave', array('bundle' => 'article'))
+      ->condition('data_is_empty', array('data:select' => 'node:field-tags'))
+      ->action('node_publish', array('node:select' => 'node'));
+    $rule->integrityCheck()->save();
+
+    $node = $this->drupalCreateNode(array('type' => 'page', 'status' => 0));
+    $this->assertEqual($node->status, 0, 'Rule has not been triggered.');
+    $node = $this->drupalCreateNode(array('type' => 'article', 'status' => 0));
+    $this->assertEqual($node->status, 1, 'Rule has been triggered.');
+    RulesLog::logger()->checkLog();
+
+    // Make sure an invalid bundle raises integrity problems.
+    $rule->event('node_presave', array('bundle' => 'invalid'));
+    try {
+      $rule->integrityCheck();
+      $this->fail('Integrity check failed.');
+    }
+    catch (RulesIntegrityException $e) {
+      $this->pass('Integrity check failed: ' . $e);
+    }
+  }
+}
+
+/**
+ * Tests provided module integration.
+ */
+class RulesIntegrationTestCase extends DrupalWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Rules Core Integration',
+      'description' => 'Tests provided integration for drupal core.',
+      'group' => 'Rules',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rules', 'rules_test', 'php', 'path');
+    RulesLog::logger()->clear();
+    variable_set('rules_debug_log', 1);
+  }
+
+  /**
+   * Just make sure the access callback run without errors.
+   */
+  function testAccessCallbacks() {
+    $cache = rules_get_cache();
+    foreach (array('action', 'condition', 'event') as $type) {
+      foreach (rules_fetch_data($type . '_info') as $name => $info) {
+        if (isset($info['access callback'])) {
+          $info['access callback']($type, $name);
+        }
+      }
+    }
+  }
+
+  /**
+   * Test data integration.
+   */
+  function testDataIntegration() {
+    // Test data_create action.
+    $action = rules_action('data_create', array(
+      'type' => 'log_entry',
+      'param_type' => 'rules_test',
+      'param_message' => 'Rules test log message',
+      'param_severity' => WATCHDOG_WARNING,
+      'param_request_uri' => 'http://example.com',
+      'param_link' => '',
+    ));
+    $action->access();
+    $action->execute();
+    $text = RulesLog::logger()->render();
+    $pos = strpos($text, RulesTestCase::t('Added the provided variable %data_created of type %log_entry', array('data_created', 'log_entry')));
+    $this->assertTrue($pos !== FALSE, 'Data of type log entry has been created.');
+
+
+    // Test variable_add action.
+    $action = rules_action('variable_add', array(
+      'type' => 'text_formatted',
+      'value' => array(
+        'value' => 'test text',
+        'format' => 1,
+      )
+    ));
+    $action->access();
+    $action->execute();
+    $text = RulesLog::logger()->render();
+    $pos = strpos($text, RulesTestCase::t('Added the provided variable %variable_added of type %text_formatted', array('variable_added', 'text_formatted')));
+    $this->assertTrue($pos !== FALSE, 'Data of type text formatted has been created.');
+
+
+    // Test using the list actions.
+    $rule = rule(array(
+      'list' => array(
+        'type' => 'list<text>',
+        'label' => 'A list of text',
+      )
+    ));
+    $rule->action('list_add', array('list:select' => 'list', 'item' => 'bar2'));
+    $rule->action('list_add', array('list:select' => 'list', 'item' => 'bar', 'pos' => 'start'));
+    $rule->action('list_add', array('list:select' => 'list', 'item' => 'bar', 'unique' => TRUE));
+    $rule->action('list_remove', array('list:select' => 'list', 'item' => 'bar2'));
+    $list = entity_metadata_wrapper('list', array('foo', 'foo2'));
+    $rule->execute($list);
+    RulesLog::logger()->checkLog();
+    $this->assertEqual($list->value(), array('bar', 'foo', 'foo2'), 'List items removed and added.');
+    $this->assertFalse(rules_condition('list_contains')->execute($list, 'foo-bar'), 'Condition "List item contains" evaluates to FALSE');
+    $this->assertTrue(rules_condition('list_contains')->execute($list, 'foo'), 'Condition "List item contains" evaluates to TRUE');
+    //debug(RulesLog::logger()->render());
+
+    // Test data_is condition with IN operation.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('data_is', array('data:select' => 'node:title', 'op' => 'IN', 'value' => array('foo', 'bar')));
+    $rule->action('data_set', array('data:select' => 'node:title', 'value' => 'bar'));
+    $rule->integrityCheck();
+
+    $node = $this->drupalCreateNode(array('title' => 'foo'));
+    $rule->execute($node);
+    $this->assertEqual($node->title, 'bar', "Data comparision using IN operation evaluates to TRUE.");
+
+
+    // Test Condition: Data is empty.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('data_is_empty', array('data:select' => 'node:title'));
+    $rule->action('data_set', array('data:select' => 'node:title', 'value' => 'bar'));
+    $rule->integrityCheck();
+
+    // Data is empty condition evaluates to TRUE
+    // for node with empty title, action sets title to 'bar'.
+    $node = $this->drupalCreateNode(array('title' => '', 'type' => 'article'));
+    $rule->execute($node);
+    $this->assertEqual($node->title, 'bar', "Data is empty condition evaluates to TRUE for node with empty title, action sets title to 'bar'.");
+
+    // Data is empty condition evaluates to FALSE
+    // for node with title 'foo', action is not executed.
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article'));
+    $rule->execute($node);
+    $this->assertEqual($node->title, 'foo', "Data is empty condition evaluates to FALSE for node with title 'foo', action is not executed.");
+
+    // Data is empty condition evaluates to TRUE for the parent of a
+    // not existing term in the tags field of the node.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('node_is_of_type', array('type' => array('article')));
+    $rule->condition('data_is_empty', array('data:select' => 'node:field-tags:0:parent'));
+    $rule->action('data_set', array('data:select' => 'node:title', 'value' => 'bar'));
+    $rule->integrityCheck();
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article'));
+    $rule->execute($node);
+    $this->assertEqual($node->title, 'bar', "Data is empty condition evaluates to TRUE for not existing data structures");
+
+    // Test Action: Calculate a value.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->action('data_calc', array('input_1:select' => 'node:nid', 'op' => '*', 'input_2' => 2));
+    $rule->action('data_set', array('data:select' => 'node:title', 'value:select' => 'result'));
+    $rule->integrityCheck();
+    $rule->execute($node);
+    $this->assertEqual($node->title, $node->nid * 2, "Value has been calculated.");
+
+    // Test moving a date.
+    $action_set = rules_action_set(array('date' => array('type' => 'date')), array('date'));
+    $action_set->action('data_calc', array('input_1:select' => 'date', 'op' => '+', 'input_2' => 3600))
+               ->action('data_set', array('data:select' => 'date', 'value:select' => 'result'));
+    $action_set->integrityCheck();
+    list($result) = $action_set->execute(REQUEST_TIME);
+    $this->assertEqual($result, REQUEST_TIME + 3600, 'Used data calculation action to move a date by an hour.');
+
+    // Test data type conversion action.
+    $set = rules_action_set(array('result' => array('type' => 'text', 'parameter' => FALSE)), array('result'));
+    $set->action('data_convert', array('type' => 'text', 'value:select' => 'site:login-url'));
+    $set->action('data_set', array('data:select' => 'result', 'value:select' => 'conversion_result'));
+    list($result) = $set->execute();
+    $set->integrityCheck();
+    $this->assertEqual($result, url('user', array('absolute' => TRUE)), 'Converted URI to text.');
+
+    $set = rules_action_set(array(
+      'result' => array('type' => 'integer', 'parameter' => FALSE),
+      'source' => array('type' => 'text'),
+    ), array('result'));
+    $set->action('data_convert', array('type' => 'integer', 'value:select' => 'source'));
+    $set->action('data_set', array('data:select' => 'result', 'value:select' => 'conversion_result'));
+    list($result) = $set->execute('9.4');
+    $this->assertEqual($result, 9, 'Converted decimal to integer using rounding.');
+
+    $set = rules_action_set(array(
+      'result' => array('type' => 'integer', 'parameter' => FALSE),
+      'source' => array('type' => 'text'),
+    ), array('result'));
+    $set->action('data_convert', array('type' => 'integer', 'value:select' => 'source', 'rounding_behavior' => 'down'));
+    $set->action('data_set', array('data:select' => 'result', 'value:select' => 'conversion_result'));
+    list($result) = $set->execute('9.6');
+    $this->assertEqual($result, 9, 'Converted decimal to integer using roundin behavio down.');
+
+    $set = rules_action_set(array(
+      'result' => array('type' => 'integer', 'parameter' => FALSE),
+      'source' => array('type' => 'text'),
+    ), array('result'));
+    $set->action('data_convert', array('type' => 'integer', 'value:select' => 'source', 'rounding_behavior' => 'up'));
+    $set->action('data_set', array('data:select' => 'result', 'value:select' => 'conversion_result'));
+    list($result) = $set->execute('9.4');
+    $this->assertEqual($result, 10, 'Converted decimal to integer using rounding behavior up.');
+
+    // Test text matching condition.
+    $result = rules_condition('text_matches')->execute('my-text', 'text', 'contains');
+    $result2 = rules_condition('text_matches')->execute('my-text', 'tex2t', 'contains');
+    $this->assertTrue($result && !$result2, 'Text matching condition using operation contain evaluated.');
+
+    $result = rules_condition('text_matches')->execute('my-text', 'my', 'starts');
+    $result2 = rules_condition('text_matches')->execute('my-text', 'text', 'starts');
+    $this->assertTrue($result && !$result2, 'Text matching condition using operation starts evaluated.');
+
+    $result = rules_condition('text_matches')->execute('my-text', 'text', 'ends');
+    $result2 = rules_condition('text_matches')->execute('my-text', 'my', 'ends');
+    $this->assertTrue($result && !$result2, 'Text matching condition using operation ends evaluated.');
+
+    $result = rules_condition('text_matches')->execute('my-text', 'me?y-texx?t', 'regex');
+    $result2 = rules_condition('text_matches')->execute('my-text', 'me+y-texx?t', 'regex');
+    $this->assertTrue($result && !$result2, 'Text matching condition using operation regex evaluated.');
+  }
+
+  /**
+   * Tests entity related integration.
+   */
+  function testEntityIntegration() {
+    global $user;
+
+    $page = $this->drupalCreateNode(array('type' => 'page'));
+    $article = $this->drupalCreateNode(array('type' => 'article'));
+
+    $result = rules_condition('entity_field_access')
+      ->execute(entity_metadata_wrapper('node', $article), 'field_tags');
+    $this->assertTrue($result);
+
+    // Test entiy_is_of_bundle condition.
+    $result = rules_condition('entity_is_of_bundle', array(
+      'type' => 'node',
+      'bundle' => array('article'),
+    ))->execute(entity_metadata_wrapper('node', $page));
+    $this->assertFalse($result, 'Entity is of bundle condition has not been met.');
+    $result = rules_condition('entity_is_of_bundle', array(
+      'type' => 'node',
+      'bundle' => array('article'),
+    ))->execute(entity_metadata_wrapper('node', $article));
+    $this->assertTrue($result, 'Entity is of bundle condition has been met.');
+
+    // Also test a full rule so the integrity check must work.
+    $term_wrapped = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => 1,
+    ))->save();
+    $rule = rule(array(
+      'node' => array('type' => 'node'),
+    ));
+    $rule->condition('entity_is_of_bundle', array(
+      'entity:select' => 'node',
+      'bundle' => array('article'),
+    ));
+    $rule->action('data_set', array('data:select' => 'node:field_tags', 'value' => array($term_wrapped->getIdentifier())));
+    $rule->integrityCheck();
+    $rule->execute($article);
+    $this->assertEqual($term_wrapped->getIdentifier(), $article->field_tags[LANGUAGE_NONE][0]['tid'], 'Entity is of bundle condition has been met.');
+
+    // Test again using an entity variable.
+    $article = $this->drupalCreateNode(array('type' => 'article'));
+    $rule = rule(array(
+      'entity' => array('type' => 'entity'),
+    ));
+    $rule->condition('entity_is_of_bundle', array(
+      'entity:select' => 'entity',
+      'type' => 'node',
+      'bundle' => array('article'),
+    ));
+    $rule->action('data_set', array('data:select' => 'entity:field_tags', 'value' => array($term_wrapped->getIdentifier())));
+    $rule->integrityCheck();
+    $rule->execute(entity_metadata_wrapper('node', $article));
+    $this->assertEqual($term_wrapped->getIdentifier(), $article->field_tags[LANGUAGE_NONE][0]['tid'], 'Entity is of bundle condition has been met.');
+
+    // Test CRUD actions.
+    $action = rules_action('entity_create', array(
+      'type' => 'node',
+      'param_type' => 'page',
+      'param_title' => 'foo',
+      'param_author' => $GLOBALS['user'],
+    ));
+    $action->access();
+    $action->execute();
+    $text = RulesLog::logger()->render();
+    $pos = strpos($text, RulesTestCase::t('Added the provided variable %entity_created of type %node', array('entity_created', 'node')));
+    $pos = ($pos !== FALSE) ? strpos($text, RulesTestCase::t('Saved %entity_created of type %node.', array('entity_created', 'node')), $pos) : FALSE;
+    $this->assertTrue($pos !== FALSE, 'Data has been created and saved.');
+
+    $node = $this->drupalCreateNode(array('type' => 'page', 'sticky' => 0, 'status' => 0));
+    $rule = rule();
+    $rule->action('entity_fetch', array('type' => 'node', 'id' => $node->nid, 'entity_fetched:var' => 'node'));
+    $rule->action('entity_save', array('data:select' => 'node', 'immediate' => TRUE));
+    $rule->action('entity_delete', array('data:select' => 'node'));
+    $rule->access();
+    $rule->integrityCheck()->execute();
+
+    $text = RulesLog::logger()->render();
+    $pos = strpos($text, RulesTestCase::t('Evaluating the action %entity_fetch.', array('entity_fetch')));
+    $pos = ($pos !== FALSE) ? strpos($text, RulesTestCase::t('Added the provided variable %node of type %node', array('node')), $pos) : FALSE;
+    $pos = ($pos !== FALSE) ? strpos($text, RulesTestCase::t('Saved %node of type %node.', array('node')), $pos) : FALSE;
+    $pos = ($pos !== FALSE) ? strpos($text, RulesTestCase::t('Evaluating the action %entity_delete.', array('entity_delete')), $pos) : FALSE;
+    $this->assertTrue($pos !== FALSE, 'Data has been fetched, saved and deleted.');
+    //debug(RulesLog::logger()->render());
+
+
+
+    $node = entity_property_values_create_entity('node', array(
+      'type' => 'article',
+      'author' => $user,
+      'title' => 'foo',
+    ))->value();
+    $term_wrapped = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => 1,
+    ))->save();
+
+    // Test asserting the field and using it afterwards.
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->condition('entity_has_field', array('entity:select' => 'node', 'field' => 'field_tags'));
+    $rule->condition('entity_is_new', array('entity:select' => 'node'));
+    $rule->action('list_add', array('list:select' => 'node:field-tags', 'item' => $term_wrapped));
+    $rule->integrityCheck();
+    $rule->execute($node);
+
+    $tid = $term_wrapped->getIdentifier();
+    $this->assertEqual(array_values($node->field_tags[LANGUAGE_NONE]), array(0 => array('tid' => $tid)), 'Entity has field conditions evaluted.');
+
+    // Test loading a non-node entity.
+    $action = rules_action('entity_fetch', array('type' => 'taxonomy_term', 'id' => $tid));
+    list($term) = $action->execute();
+    $this->assertEqual($term->tid, $tid, 'Fetched a taxonomy term using "entity_fetch".');
+
+    // Test the entity is of type condition.
+    $rule = rule(array('entity' => array('type' => 'entity', 'label' => 'entity')));
+    $rule->condition('entity_is_of_type', array('type' => 'node'));
+    $rule->action('data_set', array('data:select' => 'entity:title', 'value' => 'bar'));
+    $rule->integrityCheck();
+    $rule->execute(entity_metadata_wrapper('node', $node));
+
+    $this->assertEqual(entity_metadata_wrapper('node', $node->nid)->title->value(), 'bar', 'Entity is of type condition correctly asserts the entity type.');
+
+
+    // Test the entity_query action.
+    $node = $this->drupalCreateNode(array('type' => 'page', 'title' => 'foo2'));
+    $rule = rule();
+    $rule->action('entity_query', array('type' => 'node', 'property' => 'title', 'value' => 'foo2'))
+         ->action('data_set', array('data:select' => 'entity_fetched:0:title', 'value' => 'bar'));
+    $rule->access();
+    $rule->integrityCheck();
+    $rule->execute();
+    $node = node_load($node->nid);
+    $this->assertEqual('bar', $node->title, 'Fetched a node by title and modified it.');
+
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test integration for the taxonomy module.
+   */
+  function testTaxonomyIntegration() {
+    $term = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => 1,
+    ))->value();
+    $term2 = clone $term;
+    taxonomy_term_save($term);
+    taxonomy_term_save($term2);
+
+    $tags[LANGUAGE_NONE][0]['tid'] = $term->tid;
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', 'field_tags' => $tags));
+
+    // Test assigning and remove a term from an article.
+    $rule = rule(array('node' => array('type' => 'node', 'bundle' => 'article')));
+    $term_wrapped = rules_wrap_data($term->tid, array('type' => 'taxonomy_term'));
+    $term_wrapped2 = rules_wrap_data($term2->tid, array('type' => 'taxonomy_term'));
+    $rule->action('list_add', array('list:select' => 'node:field-tags', 'item' => $term_wrapped2));
+    $rule->action('list_remove', array('list:select' => 'node:field-tags', 'item' => $term_wrapped));
+    $rule->execute($node);
+    RulesLog::logger()->checkLog();
+    $this->assertEqual(array_values($node->field_tags[LANGUAGE_NONE]), array(0 => array('tid' => $term2->tid)), 'Term removed and added from a node.');
+
+    // Test using the taxonomy term reference field on a term object.
+    $field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $field = field_create_field(array(
+      'field_name' => $field_name,
+      'type' => 'taxonomy_term_reference',
+      // Set cardinality to unlimited for tagging.
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+      'settings' => array(
+        'allowed_values' => array(
+          array(
+            'vocabulary' => 'tags',
+            'parent' => 0,
+          ),
+        ),
+      ),
+    ));
+    $instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'taxonomy_term',
+      'bundle' => 'tags', // Machine name of vocabulary.
+      'label' => $this->randomName() . '_label',
+      'description' => $this->randomName() . '_description',
+      'weight' => mt_rand(0, 127),
+      'widget' => array(
+        'type' => 'taxonomy_autocomplete',
+        'weight' => -4,
+      ),
+      'display' => array(
+        'default' => array(
+          'type' => 'taxonomy_term_reference_link',
+          'weight' => 10,
+        ),
+      ),
+    );
+    field_create_instance($instance);
+
+    $term1 = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => 1,
+    ))->save();
+    $term2 = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => 1,
+    ))->save();
+
+    // Test asserting the term reference field and using it afterwards.
+    $rule = rule(array('taxonomy_term' => array('type' => 'taxonomy_term')));
+    $rule->condition('entity_has_field', array('entity:select' => 'taxonomy-term', 'field' => $field_name));
+    // Add $term2 to $term1 using the term reference field.
+    $selector = str_replace('_', '-', 'taxonomy_term:' . $field_name);
+    $rule->action('list_add', array('list:select' => $selector, 'item' => $term2));
+    $rule->integrityCheck();
+    $rule->execute($term1);
+
+    RulesLog::logger()->checkLog();
+    $this->assertEqual($term1->{$field_name}[0]->getIdentifier(), $term2->getIdentifier(), 'Rule appended a term to the term reference field on a term.');
+
+    // Test an action set for merging term parents, which is provided as default
+    // config.
+    $term = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => 1,
+      'parent' => array($term1->value()),
+    ))->save();
+
+    $action = rules_action('component_rules_retrieve_term_parents');
+    list($parents) = $action->execute(array($term->getIdentifier()));
+    $this->assertTrue($parents[0]->tid == $term1->getIdentifier(), 'Invoked component to retrieve term parents.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test integration for the node module.
+   */
+  function testNodeIntegration() {
+    $tests = array(
+      array('node_unpublish', 'node_is_published', 'node_publish', 'status'),
+      array('node_make_unsticky', 'node_is_sticky', 'node_make_sticky', 'sticky'),
+      array('node_unpromote', 'node_is_promoted', 'node_promote', 'promote'),
+    );
+    $node = $this->drupalCreateNode(array('type' => 'page', 'status' => 1, 'sticky' => 1, 'promote' => 1));
+
+    foreach ($tests as $info) {
+      list($action1, $condition, $action2, $property) = $info;
+      rules_action($action1)->execute($node);
+
+      $node = node_load($node->nid, NULL, TRUE);
+      $this->assertFalse($node->$property, 'Action has permanently disabled node '. $property);
+      $return = rules_condition($condition)->execute($node);
+      $this->assertFalse($return, 'Condition determines node '. $property . ' is disabled.');
+
+      rules_action($action2)->execute($node);
+      $node = node_load($node->nid, NULL, TRUE);
+      $this->assertTrue($node->$property, 'Action has permanently enabled node '. $property);
+      $return = rules_condition($condition)->execute($node);
+      $this->assertTrue($return, 'Condition determines node '. $property . ' is enabled.');
+    }
+
+    $return = rules_condition('node_is_of_type', array('type' => array('page', 'article')))->execute($node);
+    $this->assertTrue($return, 'Condition determines node is of type page.');
+    $return = rules_condition('node_is_of_type', array('type' => array('article')))->execute($node);
+    $this->assertFalse($return, 'Condition determines node is not of type article.');
+
+
+    // Test auto saving of a new node after it has been inserted into the DB.
+    $rule = rules_reaction_rule();
+    $rand = $this->randomName();
+    $rule->event('node_insert')
+         ->action('data_set', array('data:select' => 'node:title', 'value' => $rand));
+    $rule->save('test');
+    $node = $this->drupalCreateNode();
+    $node = node_load($node->nid);
+    $this->assertEqual($node->title, $rand, 'Node title is correct.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test integration for the user module.
+   */
+  function testUserIntegration() {
+    $rid = $this->drupalCreateRole(array('administer nodes'), 'foo');
+    $user = $this->drupalCreateUser();
+
+    // Test assigning a role with the list_add action.
+    $rule = rule(array('user' => array('type' => 'user')));
+    $rule->action('list_add', array('list:select' => 'user:roles', 'item' => $rid));
+    $rule->execute($user);
+    $this->assertTrue(isset($user->roles[$rid]), 'Role assigned to user.');
+
+    // Test removing a role with the list_remove action.
+    $rule = rule(array('user' => array('type' => 'user')));
+    $rule->action('list_remove', array('list:select' => 'user:roles', 'item' => $rid));
+    $rule->execute($user);
+    $this->assertTrue(!isset($user->roles[$rid]), 'Role removed from user.');
+
+    // Test assigning a role with user_add_role action.
+    $rule = rule(array('user' => array('type' => 'user')));
+    $rule->action('user_add_role', array('account:select' => 'user', 'roles' => array($rid)));
+    $rule->execute($user);
+
+    $user = user_load($user->uid, TRUE);
+    $result = rules_condition('user_has_role', array('roles' => array($rid)))->execute($user);
+    $this->assertTrue($result, 'Role assigned to user.');
+
+    // Test removing a role with the user_remove_role action.
+    $rule = rule(array('user' => array('type' => 'user')));
+    $rule->action('user_remove_role', array('account:select' => 'user', 'roles' => array($rid)));
+    $rule->execute($user);
+
+    $user = user_load($user->uid, TRUE);
+    $result = rules_condition('user_has_role', array('roles' => array($rid)))->execute($user);
+    $this->assertFalse($result, 'Role removed from user.');
+
+    // Test user blocking.
+    rules_action('user_block')->execute($user);
+    $user = user_load($user->uid, TRUE);
+    $this->assertTrue(rules_condition('user_is_blocked')->execute($user), 'User has been blocked.');
+
+    rules_action('user_unblock')->execute($user);
+    $user = user_load($user->uid, TRUE);
+    $this->assertFalse(rules_condition('user_is_blocked')->execute($user), 'User has been unblocked.');
+
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test integration for the php module.
+   */
+  function testPHPIntegration() {
+    $node = $this->drupalCreateNode(array('title' => 'foo'));
+    $rule = rule(array('var_name' => array('type' => 'node')));
+    $rule->condition('php_eval', array('code' => 'return TRUE;'))
+         ->action('php_eval', array('code' => 'drupal_set_message("Executed-" . $var_name->title);'))
+         ->action('drupal_message', array('message' => 'Title: <?php echo $var_name->title; ?> Token: [var_name:title]'));
+
+    $rule->execute($node);
+    $rule->access();
+    RulesLog::logger()->checkLog();
+    $msg = drupal_get_messages();
+    $this->assertEqual(array_pop($msg['status']), "Title: foo Token: foo", 'PHP input evaluation has been applied.');
+    $this->assertEqual(array_pop($msg['status']), "Executed-foo", 'PHP code condition and action have been evaluated.');
+
+    // Test PHP data processor
+    $rule = rule(array('var_name' => array('type' => 'node')));
+    $rule->action('drupal_message', array(
+      'message:select' => 'var_name:title',
+      'message:process' => array(
+        'php' => array('code' => 'return "Title: $value";')
+      ),
+    ));
+    $rule->execute($node);
+    $rule->access();
+    RulesLog::logger()->checkLog();
+    $msg = drupal_get_messages();
+    $this->assertEqual(array_pop($msg['status']), "Title: foo", 'PHP data processor has been applied.');
+  }
+
+  /**
+   * Test the "rules_core" integration.
+   */
+  function testRulesCoreIntegration() {
+    // Make sure the date input evaluator evaluates properly using strtotime().
+    $node = $this->drupalCreateNode(array('title' => 'foo'));
+    $rule = rule(array('node' => array('type' => 'node')));
+    $rule->action('data_set', array('data:select' => 'node:created', 'value' => '+1 day'));
+
+    $rule->execute($node);
+    RulesLog::logger()->checkLog();
+    $node = node_load($node->nid, NULL, TRUE);
+    $now = RulesDateInputEvaluator::gmstrtotime('now');
+    // Tolerate a difference of a second.
+    $this->assertTrue(abs($node->created - $now - 86400) <= 1, 'Date input has been evaluated.');
+
+    // Test using a numeric offset.
+    $rule = rule(array('number' => array('type' => 'decimal')), array('number'));
+    $rule->action('data_set', array(
+      'data:select' => 'number',
+      'value:select' => 'number',
+      'value:process' => array(
+        'num_offset' => array('value' => 1),
+      ),
+    ));
+    $rule->integrityCheck();
+    list($result) = $rule->execute(10);
+    $this->assertTrue($result == 11, 'Numeric offset has been applied');
+
+    // Test using a date offset.
+    $set = rules_action_set(array('date' => array('type' => 'date')), array('date'));
+    $set->action('data_set', array(
+      'data:select' => 'date',
+      'value:select' => 'date',
+      'value:process' => array(
+        'date_offset' => array('value' => 1000),
+      ),
+    ));
+    $date = date_create("14 Mar 1984 10:19:23 +01:00")->format('U');
+    list($result) = $set->execute($date);
+    $this->assertEqual($result, $date + 1000, 'Date offset in seconds has been added.');
+
+    // Test using a negative offset of 2 months.
+    $set = rules_action_set(array('date' => array('type' => 'date')), array('date'));
+    $set->action('data_set', array(
+      'data:select' => 'date',
+      'value:select' => 'date',
+      'value:process' => array(
+        'date_offset' => array('value' => - 86400 * 30 * 2),
+      ),
+    ));
+    $date = date_create("14 Mar 1984 10:19:23 +01:00")->format('U');
+    list($result) = $set->execute($date);
+    $this->assertEqual($result, date_create("14 Jan 1984 10:19:23 +01:00")->format('U'), 'Date offset of -2 months has been added.');
+
+    // Test using a positive offset of 1 year 6 months and 30 minutes.
+    $set = rules_action_set(array('date' => array('type' => 'date')), array('date'));
+    $set->action('data_set', array(
+      'data:select' => 'date',
+      'value:select' => 'date',
+      'value:process' => array(
+        'date_offset' => array('value' => 86400 * 30 * 18 + 30 * 60),
+      ),
+    ));
+    $date = date_create("14 Mar 1984 10:19:23 +01:00")->format('U');
+    list($result) = $set->execute($date);
+    $this->assertEqual($result, date_create("14 Sep 1985 10:49:23 +01:00")->format('U'), 'Date offset of 1 year 6 months and 30 minutes has been added.');
+
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test site/system integration.
+   */
+  function testSystemIntegration() {
+    // Test using the 'site' variable.
+    $condition = rules_condition('data_is', array('data:select' => 'site:current-user:name', 'value' => $GLOBALS['user']->name));
+    $this->assertTrue($condition->execute(), 'Retrieved the current user\'s name.');
+    // Another test using a token replacement.
+    $condition = rules_condition('data_is', array('data:select' => 'site:current-user:name', 'value' => '[site:current-user:name]'));
+    $this->assertTrue($condition->execute(), 'Replaced the token for the current user\'s name.');
+
+    // Test breadcrumbs and drupal set message.
+    $rule = rules_reaction_rule();
+    $rule->event('init')
+         ->action('breadcrumb_set', array('titles' => array('foo'), 'paths' => array('bar')))
+         ->action('drupal_message', array('message' => 'A message.'));
+    $rule->save('test');
+
+    $this->drupalGet('node');
+    $this->assertLink('foo', 0, 'Breadcrumb has been set.');
+    $this->assertText('A message.', 'Drupal message has been shown.');
+
+    // Test the page redirect.
+    $node = $this->drupalCreateNode();
+    $rule = rules_reaction_rule();
+    $rule->event('node_view')
+         ->action('redirect', array('url' => 'user'));
+    $rule->save('test2');
+
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertEqual($this->getUrl(), url('user', array('absolute' => TRUE)), 'Redirect has been issued.');
+
+    // Also test using a url including a fragment.
+    $actions = $rule->actions();
+    $actions[0]->settings['url'] = 'user#fragment';
+    $rule->save();
+
+    $this->drupalGet('node/' . $node->nid);
+    $this->assertEqual($this->getUrl(), url('user', array('absolute' => TRUE, 'fragment' => 'fragment')), 'Redirect has been issued.');
+
+
+    // Test sending mail.
+    $settings = array('to' => 'mail@example.com', 'subject' => 'subject', 'message' => 'hello.');
+    rules_action('mail', $settings)->execute();
+    $this->assertMail('to', 'mail@example.com', 'Mail has been sent.');
+    $this->assertMail('from', variable_get('site_mail', ini_get('sendmail_from')), 'Default from address has been used');
+
+    rules_action('mail', $settings + array('from' => 'sender@example.com'))->execute();
+    $this->assertMail('from', 'sender@example.com', 'Specified from address has been used');
+
+    // Test sending mail to all users of a role. First make sure there is a
+    // custom role and a user for it.
+    $user = $this->drupalCreateUser(array('administer nodes'));
+    $roles = $user->roles;
+    // Remove the authenticate role so we only use the new role created by
+    // drupalCreateUser().
+    unset($roles[DRUPAL_AUTHENTICATED_RID]);
+    rules_action('mail_to_users_of_role', $settings + array('roles' => array_keys($roles)))->execute();
+    $this->assertMail('to', $user->mail, 'Mail to users of a role has been sent.');
+
+    // Test reacting on new log entries and make sure the log entry is usable.
+    $rule = rules_reaction_rule();
+    $rule->event('watchdog');
+    $rule->action('drupal_message', array('message:select' => 'log_entry:message'));
+    $rule->integrityCheck()->save('test_watchdog');
+
+    watchdog('php', 'test %message', array('%message' => 'message'));
+    $msg = drupal_get_messages();
+    $this->assertEqual(array_pop($msg['status']), t('test %message', array('%message' => 'message')), 'Watchdog event occurred and log entry properties can be used.');
+  }
+
+  /**
+   * Tests the path module integration.
+   */
+  function testPathIntegration() {
+    rules_action('path_alias')->execute('foo', 'bar');
+    $path = path_load('foo');
+    $this->assertTrue($path['alias'] == 'bar', 'URL alias has been created.');
+
+    $alias_exists = rules_condition('path_alias_exists', array('alias' => 'bar'))->execute();
+    $this->assertTrue($alias_exists, 'Created URL alias exists.');
+
+    $has_alias = rules_condition('path_has_alias', array('source' => 'foo'))->execute();
+    $this->assertTrue($has_alias, 'System path has an alias.');
+
+    // Test node alias action.
+    $node = $this->drupalCreateNode();
+    rules_action('node_path_alias')->execute($node, 'test');
+    $path = path_load("node/$node->nid");
+    $this->assertTrue($path['alias'] == 'test', 'Node URL alias has been created.');
+
+    // Test term alias action.
+    $term = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => 1,
+    ))->value();
+    rules_action('taxonomy_term_path_alias')->execute($term, 'term-test');
+    $path = path_load("taxonomy/term/$term->tid");
+    $this->assertTrue($path['alias'] == 'term-test', 'Term URL alias has been created.');
+
+    RulesLog::logger()->checkLog();
+  }
+}
+
+/**
+ * Test event dispatcher functionality.
+ */
+class RulesEventDispatcherTestCase extends DrupalWebTestCase {
+
+  static function getInfo() {
+    return array(
+      'name' => 'Rules event dispatchers',
+      'description' => 'Tests event dispatcher functionality.',
+      'group' => 'Rules',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rules', 'rules_test');
+  }
+
+  /**
+   * Tests start and stop functionality.
+   */
+  public function testStartAndStop() {
+    $handler = rules_get_event_handler('rules_test_event');
+    $rule = rules_reaction_rule();
+    $rule->event('rules_test_event');
+
+    // The handler should not yet be watching.
+    $this->assertFalse($handler->isWatching());
+
+    // Once saved, the event cache rebuild should start the watcher.
+    $rule->save();
+    RulesEventSet::rebuildEventCache();
+    $this->assertTrue($handler->isWatching());
+
+    // Deleting should stop the watcher.
+    $rule->delete();
+    $this->assertFalse($handler->isWatching());
+  }
+
+  /**
+   * Tests start and stop functionality when used with multiple events.
+   */
+  public function testStartAndStopMultiple() {
+    $handler = rules_get_event_handler('rules_test_event');
+
+    // Initially, the task handler should not be watching.
+    $this->assertFalse($handler->isWatching());
+
+    // Set up five rules that all use the same event.
+    $rules = array();
+    foreach (array(1, 2, 3, 4, 5) as $key) {
+      $rules[$key] = rules_reaction_rule();
+      $rules[$key]->event('rules_test_event');
+      $rules[$key]->save();
+    }
+
+    // Once saved, the event cache rebuild should start the watcher.
+    RulesEventSet::rebuildEventCache();
+    $this->assertTrue($handler->isWatching());
+
+    // It should continue watching until all events are deleted.
+    foreach ($rules as $key => $rule) {
+      $rule->delete();
+      $this->assertEqual($key !== 5, $handler->isWatching());
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/tests/rules_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = "Rules Tests"
+description = "Support module for the Rules tests."
+package = Testing
+core = 7.x
+files[] = rules_test.rules.inc
+files[] = rules_test.rules_defaults.inc
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2013-09-16
+version = "7.x-2.4"
+core = "7.x"
+project = "rules"
+datestamp = "1379354606"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/tests/rules_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @file Rules test module.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() to add a property without
+ * access.
+ */
+function rules_test_entity_property_info_alter(&$info) {
+  $properties =& $info['site']['properties'];
+
+  $properties['no_access_user'] = array(
+    'label' => t("Logged in user"),
+    'description' => t("The currently logged in user."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'access callback' => 'rules_test_no_access',
+    'type' => 'user',
+  );
+
+  $properties =& $info['node']['properties'];
+
+  $properties['reference'] = array(
+    'label' => t("Referenced entity"),
+    'getter callback' => 'rules_test_get_referenced_entity',
+    'type' => 'entity',
+  );
+  $properties['ref_nodes'] = array(
+    'label' => t("Referenced nodes"),
+    'getter callback' => 'rules_test_get_referenced_node',
+    'type' => 'list<node>',
+  );
+}
+
+/**
+ * Getter callback to get the referenced-entity property.
+ */
+function rules_test_get_referenced_entity($node) {
+  // For testing purposes we just return the node itself as property value.
+  return entity_metadata_wrapper('node', $node);
+}
+
+/**
+ * Getter callback to get the referenced-node list-property.
+ */
+function rules_test_get_referenced_node($node) {
+  // For testing purposes we just return the node itself as property value.
+  return array($node->nid);
+}
+
+function rules_test_no_access($op) {
+  return $op == 'edit' ? FALSE : TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/tests/rules_test.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,345 @@
+<?php
+
+/**
+ * @file Includes any rules integration provided by the module.
+ */
+
+/**
+ * Implements hook_rules_event_info().
+ */
+function rules_test_rules_event_info() {
+  return array('rules_test_event' => array(
+    'label' => t('Test event'),
+    'class' => 'RulesTestEventHandler',
+  ));
+}
+
+/**
+ * Implements hook_rules_file_info().
+ */
+function rules_test_rules_file_info() {
+  return array('rules_test.test');
+}
+
+/**
+ * Implements hook_rules_condition_info().
+ */
+function rules_test_rules_condition_info() {
+  $items = array();
+  $defaults = array(
+    'parameter' => array(
+      'node' => array('type' => 'node', 'label' => t('Content')),
+    ),
+    'group' => t('Node'),
+  );
+  $items['rules_condition_content_is_type'] = array(
+    'label' => t('Content has type'),
+    'parameter' => array(
+      'node' => array('type' => 'node', 'label' => t('Content')),
+      'type' => array('type' => 'list<text>', 'label' => t('Content types')),
+    ),
+    'help' => t('Evaluates to TRUE, if the given content has one of the selected content types.'),
+  ) + $defaults;
+  $items['rules_condition_content_is_published'] = $defaults + array(
+    'label' => t('Content is published'),
+  );
+  $items['rules_test_condition_true'] = array(
+    'label' => t('Test condition returning true'),
+    'group' => t('Rules test'),
+  );
+  $items['rules_test_condition_false'] = array(
+    'label' => t('Test condition returning false'),
+    'group' => t('Rules test'),
+  );
+  // A condition for testing passing entities wrapped.
+  $items['rules_test_condition_node_wrapped'] = array(
+    'label' => t('Content is published'),
+    'parameter' => array(
+      'node' => array(
+        'type' => 'node',
+        'label' => t('Content'),
+        'wrapped' => TRUE,
+      ),
+    ),
+    'group' => t('Node'),
+  );
+  return $items;
+}
+
+/**
+ * Condition implementation returning true.
+ */
+function rules_test_condition_true($settings, $state, $element) {
+  if (!$element instanceof RulesCondition) {
+    throw new Exception('Rules element has not been passed to condition.');
+  }
+  rules_log('condition true called');
+  return TRUE;
+}
+
+/**
+ * Condition implementation returning false.
+ */
+function rules_test_condition_false() {
+  rules_log('condition false called');
+  return FALSE;
+}
+
+/**
+ * Condition implementation receiving the node wrapped.
+ */
+function rules_test_condition_node_wrapped($wrapper) {
+  return $wrapper instanceof EntityMetadataWrapper;
+}
+
+/**
+ * Implements hook_rules_action_info().
+ */
+function rules_test_rules_action_info() {
+  $items['rules_test_action'] = array(
+    'label' => t('Test action'),
+    'group' => t('Rules test'),
+  );
+  return $items + array(
+    'rules_node_publish_action' => array(
+      'label' => t('Publish content, but do not save'),
+      'parameter' => array(
+        'node' => array('type' => 'node', 'label' => t('Content')),
+      ),
+      'callbacks' => array(
+        'help' => 'rules_test_custom_help',
+      ),
+      'base' => 'node_publish_action',
+    ),
+    'rules_node_publish_action_save' => array(
+      'label' => t('Publish content'),
+      'parameter' => array(
+        'node' => array(
+          'type' => 'node',
+          'label' => t('Content'),
+          'save' => TRUE,
+        ),
+      ),
+      'base' => 'node_publish_action',
+    ),
+    'rules_node_make_sticky_action' => array(
+      'label' => t('Make content sticky'),
+      'parameter' => array(
+        'node' => array(
+          'type' => 'node',
+          'label' => t('Content'),
+          'save' => TRUE,
+        ),
+      ),
+      'base' => 'node_make_sticky_action',
+    ),
+    // The same action again requiring a 'page' node.
+    'rules_node_page_make_sticky_action' => array(
+      'label' => t('Mage page content sticky'),
+      'parameter' => array(
+        'node' => array(
+          'type' => 'node',
+          'label' => t('Content'),
+          'save' => TRUE,
+          'bundles' => array('page'),
+        ),
+      ),
+      'base' => 'node_make_sticky_action',
+    ),
+    'rules_action_test_reference' => array(
+      'label' => t('Change argument passed by reference'),
+      'parameter' => array(
+         // For references working right, we need a data type with a wrapper.
+        'arg' => array('type' => 'test'),
+      ),
+    ),
+    'rules_action_load_node' => array(
+      'label' => t('Fetch content by id'),
+      'parameter' => array(
+        'nid' => array('type' => 'integer', 'label' => t('Content ID')),
+        'vid' => array(
+          'type' => 'integer',
+          'label' => t('Content Revision ID'),
+          'description' => t("If you want to fetch a specific revision, specify it's revision id. Else leave it empty to fetch the currently active revision."),
+          'optional' => TRUE,
+        ),
+      ),
+      'provides' => array(
+        'node_loaded' => array(
+          'type' => 'node',
+          'label' => t('Loaded content'),
+          'label callback' => 'rules_action_load_node_variable_label',
+        ),
+      ),
+      'group' => t('Node'),
+      'access callback' => 'rules_node_integration_access',
+    ),
+    'rules_action_delete_node' => array(
+      'label' => t('Delete content'),
+      'parameter' => array(
+        'node' => array('type' => 'node', 'label' => t('Content')),
+      ),
+      'group' => t('Node'),
+      'access callback' => 'rules_node_integration_access',
+    ),
+    // An action for testing named parameters.
+    'rules_action_node_set_title' => array(
+      'label' => t('Content'),
+      'parameter' => array(
+        'node' => array('type' => 'node', 'label' => t('Content')),
+        'title' => array('type' => 'text', 'label' => t('Text')),
+      ),
+      'named parameter' => TRUE,
+      'group' => t('Node'),
+      'access callback' => 'rules_node_integration_access',
+    ),
+    // Tests automatic saving with a non-entity data type.
+    'test_type_save' => array(
+      'base' => 'rules_test_type_save',
+      'label' => t('Save test type'),
+      'parameter' => array(
+        'node' => array('type' => 'rules_test_type', 'label' => t('Test content'), 'save' => TRUE),
+      ),
+      'group' => t('Node'),
+    ),
+  );
+}
+
+/**
+ * Test action doing nothing exception logging it has been called.
+ */
+function rules_test_action() {
+  rules_log('action called');
+}
+
+/**
+ * Action for testing writing class-based actions.
+ */
+class RulesTestClassAction extends RulesActionHandlerBase {
+
+  /**
+   * Defines the action.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'rules_test_class_action',
+      'label' => t('Test class based action'),
+      'group' => t('Node'),
+      'parameter' => array(
+        'node' => array(
+          'type' => 'node',
+          'label' => t('Node'),
+        ),
+      ),
+    );
+  }
+
+  /**
+   * Executes the action.
+   */
+  public function execute($node) {
+    rules_log('Action called with node ' . $node->nid);
+  }
+}
+
+/**
+ * Implements hook_rules_data_info().
+ */
+function rules_test_rules_data_info() {
+  return array(
+    'rules_test_type' => array(
+      'label' => t('test type'),
+      'wrap' => TRUE,
+      'wrapper class' => 'RulesTestTypeWrapper',
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_data_info_alter().
+ */
+function rules_test_rules_data_info_alter(&$data_info) {
+  $data_info['log_entry']['creation callback'] = 'rules_action_data_create_array';
+}
+
+/**
+ * The custom wrapper class for the rules test type.
+ *
+ * For testing we internally just make use of nodes.
+ */
+class RulesTestTypeWrapper extends RulesIdentifiableDataWrapper implements RulesDataWrapperSavableInterface {
+
+  protected function extractIdentifier($data) {
+    return $data->nid;
+  }
+
+  protected function load($id) {
+    return node_load($id);
+  }
+
+  public function save() {
+    node_save($this->value());
+  }
+}
+
+/**
+ * Implements hook_rules_plugin_info().
+ */
+function rules_test_rules_plugin_info() {
+  return array(
+    'rules test container' => array(
+      'label' => t('Test container'),
+      'class' => 'RulesTestContainer',
+      'embeddable' => 'RulesActionContainer',
+    ),
+  );
+}
+
+/**
+ * Test container plugin.
+ */
+class RulesTestContainer extends RulesContainerPlugin {
+  protected $itemName = 'rules test container';
+
+  /**
+   * Evaluate the element on a given rules evaluation state.
+   */
+  public function evaluate(RulesState $state) {
+    // Do nothing.
+  }
+}
+
+/**
+ * Test event handler class.
+ */
+class RulesTestEventHandler extends RulesEventDefaultHandler implements RulesEventDispatcherInterface {
+
+  /**
+   * Name of the variable in which to store the state of the event handler.
+   *
+   * @var string
+   */
+  protected $variableName = 'rules_test_event_handler_watch';
+
+  /**
+   * Implements RulesEventDispatcherInterface::startWatching().
+   */
+  public function startWatching() {
+    variable_set($this->variableName, TRUE);
+  }
+
+  /**
+   * Implements RulesEventDispatcherInterface::stopWatching().
+   */
+  public function stopWatching() {
+    variable_set($this->variableName, FALSE);
+  }
+
+  /**
+   * Implements RulesEventDispatcherInterface::isWatching().
+   */
+  public function isWatching() {
+    return (bool) variable_get($this->variableName);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/tests/rules_test.rules_defaults.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * @file Includes any rules integration provided by the module.
+ */
+
+
+/**
+ * Implements hook_default_rules_configuration().
+ */
+function rules_test_default_rules_configuration() {
+  $rule = rules_reaction_rule();
+  $rule->label = 'example default rule';
+  $rule->active = FALSE;
+  $rule->event('node_update')
+       ->condition(rules_condition('data_is', array('data:select' => 'node:status', 'value' => TRUE))->negate())
+       ->condition('data_is', array('data:select' => 'node:type', 'value' => 'page'))
+       ->action('drupal_message', array('message' => 'A node has been updated.'));
+
+  $configs['rules_test_default_1'] = $rule;
+
+  $action_set = rules_action_set(array('node' => array('type' => 'node', 'label' => 'Content')));
+  $action_set->action('node_publish');
+  $configs['rules_test_action_set'] = $action_set;
+
+  // Test providing a rule using an export.
+  $configs['rules_export_test'] = rules_import(_rules_export_get_test_export());
+
+  // An action set used to test merging term parents.
+  $configs['rules_retrieve_term_parents'] = rules_import('{ "rules_retrieve_term_parents" : {
+    "LABEL" : "Retrieve term parents",
+    "PLUGIN" : "action set",
+    "REQUIRES" : [ "rules" ],
+    "USES VARIABLES" : {
+      "terms" : { "label" : "Terms", "type" : "list\u003ctaxonomy_term\u003e" },
+      "term_parents" : {
+        "label" : "Term parents",
+        "type" : "list\u003ctaxonomy_term\u003e",
+        "parameter" : false
+      }
+    },
+    "ACTION SET" : [
+      { "LOOP" : {
+          "USING" : { "list" : [ "terms" ] },
+          "ITEM" : { "current_term" : "Current term" },
+          "DO" : [
+            { "LOOP" : {
+                "USING" : { "list" : [ "current-term:parent" ] },
+                "ITEM" : { "current_parent" : "Current parent" },
+                "DO" : [
+                  { "list_add" : {
+                      "list" : [ "term-parents" ],
+                      "item" : [ "current-parent" ],
+                      "unique" : 1
+                    }
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      }
+    ],
+    "PROVIDES VARIABLES" : [ "term_parents" ]
+  }
+}');
+
+  return $configs;
+}
+
+/**
+ * Defines the export of rule for testing import/export.
+ */
+function _rules_export_get_test_export() {
+  return '{ "rules_export_test" : {
+    "LABEL" : "Test import rule2",
+    "PLUGIN" : "reaction rule",
+    "WEIGHT" : "-1",
+    "ACTIVE" : false,
+    "TAGS" : [ "bar", "baz", "foo" ],
+    "REQUIRES" : [ "rules", "comment" ],
+    "ON" : { "comment_insert" : [] },
+    "IF" : [
+      { "OR" : [
+          { "NOT node_is_sticky" : { "node" : [ "comment:node" ] } },
+          { "node_is_of_type" : {
+              "node" : [ "comment:node" ],
+              "type" : { "value" : { "page" : "page" } }
+            }
+          },
+          { "NOT AND" : [ { "OR" : [] } ] }
+        ]
+      }
+    ],
+    "DO" : [
+      { "data_set" : {
+          "data" : [ "comment:node:created" ],
+          "value" : { "select" : "site:current-date", "date_offset" : { "value" : -604800 } }
+        }
+      },
+      { "node_make_sticky" : { "node" : [ "comment:node" ] } },
+      { "variable_add" : {
+          "USING" : { "type" : "token", "value" : "error" },
+          "PROVIDE" : { "variable_added" : { "level" : "Error level" } }
+        }
+      },
+      { "drupal_message" : {
+          "message" : "fein, [comment:node:title] has been made sticky!",
+          "type" : [ "level" ]
+        }
+      },
+      { "LOOP" : {
+          "USING" : { "list" : [ "site:current-user:roles" ] },
+          "ITEM" : { "current_role" : "Current role" },
+          "DO" : [ { "drupal_message" : { "message" : [ "current-role" ] } } ]
+        }
+      }
+    ]
+  }
+}';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/tests/rules_test.test.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * @file Include file for testing file inclusion.
+ */
+
+/**
+ * Extender for the node data type.
+ */
+function rules_test_custom_node_save($object) {
+  throw new RulesEvaluationException('Custom save method invoked.');
+}
+
+
+/**
+ * Custom help callback for the rules_node_publish_action
+ */
+function rules_test_custom_help() {
+  return 'custom';
+}
+
+/**
+ * Action callback
+ */
+function rules_action_test_reference($data) {
+  $data['changed'] = TRUE;
+  return array('arg' => $data);
+}
+
+/**
+ * Condition: Check for selected content types
+ */
+function rules_condition_content_is_type($node, $type) {
+  return in_array($node->type, $type);
+}
+
+/**
+ * Condition: Check if the node is published
+ */
+function rules_condition_content_is_published($node, $settings) {
+  return $node->status == 1;
+}
+
+/**
+ * Loads a node
+ */
+function rules_action_load_node($nid, $vid = NULL) {
+  return array('node_loaded' => node_load($nid, $vid ? $vid : NULL));
+}
+
+/**
+ * Action "Delete a node".
+ */
+function rules_action_delete_node($node) {
+  node_delete($node->nid);
+}
+
+/**
+ * An action making use of named parameters.
+ */
+function rules_action_node_set_title($arguments) {
+  // Make sure the data is unwrapped.
+  if ($arguments['node'] instanceof EntityMetadataWrapper) {
+    throw new Exception('Argument has not been correctly unwrapped.');
+  }
+  $arguments['node']->title = $arguments['title'];
+  return $arguments;
+}
+
+/**
+ * Action: Test saving - nothing to do here.
+ */
+function rules_test_type_save($node) {
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/rules.autocomplete.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,195 @@
+
+// Registers the rules namespace.
+Drupal.rules = Drupal.rules || {};
+
+(function($) {
+  Drupal.behaviors.rules_autocomplete = {
+    attach: function(context) {
+      var autocomplete_settings = Drupal.settings.rules_autocomplete;
+
+      $('input.rules-autocomplete').once(function() {
+        var input = this;
+        new Drupal.rules.autocomplete(input, autocomplete_settings[$(input).attr('id')]);
+      });
+    }
+  };
+
+  /**
+   * Rules autocomplete object.
+   */
+  Drupal.rules.autocomplete = function(input, settings) {
+    this.id = settings.inputId;
+    this.uri = settings.source;
+    this.jqObject = $('#' + this.id);
+    this.cache = new Array();
+    this.jqObject.addClass('ui-corner-left');
+
+    this.opendByFocus = false;
+    this.focusOpens = true;
+    this.groupSelected = false;
+
+    this.button = $('<span>&nbsp;</span>');
+    this.button.attr( {
+      'tabIndex': -1,
+      'title': 'Show all items'
+    });
+    this.button.insertAfter(this.jqObject);
+
+    this.button.button( {
+      icons: {
+        primary: 'ui-icon-triangle-1-s'
+      },
+      text: false
+    });
+
+    // Don't round the left corners.
+    this.button.removeClass('ui-corner-all');
+    this.button.addClass('ui-corner-right ui-button-icon rules-autocomplete-button');
+
+    this.jqObject.autocomplete();
+    this.jqObject.autocomplete("option", "minLength", 0);
+    // Add a custom class, so we can style the autocomplete box without
+    // interfering with other jquery autocomplete widgets.
+    this.jqObject.autocomplete("widget").addClass('rules-autocomplete');
+
+    // Save the current rules_autocomplete object, so it can be used in
+    // handlers.
+    var instance = this;
+
+    // Event handlers
+    this.jqObject.focus(function() {
+      if (instance.focusOpens) {
+        instance.toggle();
+        instance.opendByFocus = true;
+      }
+      else {
+        instance.focusOpens = true;
+      }
+    });
+
+    // Needed when the window is closed but the textfield has the focus.
+    this.jqObject.click(function() {
+      // Since the focus event happens earlier then the focus event, we need to
+      // check here, if the window should be opened.
+      if (!instance.opendByFocus) {
+        instance.toggle();
+      }
+      else {
+        instance.opendByFocus = false;
+      }
+    });
+
+    this.jqObject.bind("autocompleteselect", function(event, ui) {
+      // If a group was selected then set the groupSelected to true for the
+      // overriden close function from jquery autocomplete.
+      if (ui.item.value.substring(ui.item.value.length - 1, ui.item.value.length) == ":") {
+        instance.groupSelected = true;
+      }
+      instance.focusOpens = false;
+      instance.opendByFocus = false;
+    });
+
+    this.jqObject.autocomplete("option", "source", function(request, response) {
+      if (request.term in instance.cache) {
+        response(instance.cache[request.term]);
+        return;
+      }
+      $.ajax( {
+        url: instance.uri + '/' + request.term,
+        dataType: "json",
+        success: function(data) {
+          instance.success(data, request, response);
+        }
+      });
+    });
+
+    // Since jquery autocomplete by default strips html text by using .text()
+    // we need our own _renderItem function to display html content.
+    this.jqObject.data("autocomplete")._renderItem = function(ul, item) {
+      return $("<li></li>").data("item.autocomplete", item).append("<a>" + item.label + "</a>").appendTo(ul);
+    };
+
+    // Override close function
+    this.jqObject.data("autocomplete").close = function (event) {
+      var value = this.element.val();
+      // If the selector is not a group, then trigger the close event an and
+      // hide the menu.
+      if (value === undefined || instance.groupSelected === false) {
+        clearTimeout(this.closing);
+        if (this.menu.element.is(":visible")) {
+          this._trigger("close", event);
+          this.menu.element.hide();
+          this.menu.deactivate();
+        }
+      }
+      else {
+        // Else keep all open and trigger a search for the group.
+        instance.jqObject.autocomplete("search", instance.jqObject.val());
+        // After the suggestion box was opened again, we want to be able to
+        // close it.
+        instance.groupSelected = false;
+      }
+    };
+
+    this.button.click(function() {
+      instance.toggle();
+    });
+
+  };
+
+  /**
+   * Success function for Rules autocomplete object.
+   */
+  Drupal.rules.autocomplete.prototype.success = function(data, request, response) {
+    var list = new Array();
+    jQuery.each(data, function(index, value) {
+      list.push( {
+        label: value,
+        value: index
+      });
+    });
+
+    this.cache[request.term] = list;
+    response(list);
+  };
+
+  /**
+   * Open the autocomplete window.
+   * @param searchFor The term for will be searched for. If undefined then the
+   *                  entered input text will be used.
+   */
+  Drupal.rules.autocomplete.prototype.open = function(searchFor) {
+    // If searchFor is undefined, we want to search for the passed argument.
+    this.jqObject.autocomplete("search", ((searchFor === undefined) ? this.jqObject.val() : searchFor));
+    this.button.addClass("ui-state-focus");
+  };
+
+  /**
+   * Close the autocomplete window.
+   */
+  Drupal.rules.autocomplete.prototype.close = function() {
+    this.jqObject.autocomplete("close");
+    this.button.removeClass("ui-state-focus");
+  };
+
+  /**
+   * Toogle the autcomplete window.
+   */
+  Drupal.rules.autocomplete.prototype.toggle = function() {
+    if (this.jqObject.autocomplete("widget").is(":visible")) {
+      this.close();
+      this.focusOpens = true;
+    }
+    else {
+      var groups = this.jqObject.val().split(":");
+      var selector = "";
+      for (var i=0; i<groups.length-1; i++) {
+        selector = selector.concat(groups[i]) + ":";
+      }
+      this.focusOpens = false;
+      this.jqObject.focus();
+      this.open(selector);
+    }
+  };
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/rules.debug.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,68 @@
+/**
+ * @file
+ * Adds the collapsible functionality to the rules debug log.
+ */
+
+// Registers the rules namespace.
+Drupal.rules = Drupal.rules || {};
+
+(function($) {
+  Drupal.behaviors.rules_debug_log = {
+    attach: function(context) {
+      $('.rules-debug-open').click(function () {
+        var icon = $(this).children('span.ui-icon');
+        if ($(this).next().is(':hidden')) {
+          Drupal.rules.changeDebugIcon(icon, true);
+        }
+        else {
+          Drupal.rules.changeDebugIcon(icon, false);
+        }
+        $(this).next().toggle();
+      }).next().hide();
+
+      $('.rules-debug-open-main').click(function () {
+        var icon = $(this).children('span.ui-icon');
+        if ($(this).parent().next().is(':hidden')) {
+          Drupal.rules.changeDebugIcon(icon, true);
+          $(this).parent().children('.rules-debug-open-all').text(Drupal.t('-Close all-'));
+        }
+        else {
+          Drupal.rules.changeDebugIcon(icon, false);
+          $(this).parent().children('.rules-debug-open-all').text(Drupal.t('-Open all-'));
+        }
+        $(this).parent().next().toggle();
+      }).parent().next().hide();
+
+      $('.rules-debug-open-all').click(function() {
+        if ($('.rules-debug-open-main').parent().next().is(':hidden')) {
+          $('.rules-debug-open').next().show();
+          Drupal.rules.changeDebugIcon($('.rules-debug-open').children('span.ui-icon'), true);
+          $('.rules-debug-open-main').parent().next().show();
+          Drupal.rules.changeDebugIcon($(this).prev().children('span.ui-icon'), true);
+          $(this).text(Drupal.t('-Close all-'));
+        }
+        else {
+          $('.rules-debug-open-main').parent().next().hide();
+          Drupal.rules.changeDebugIcon($('.rules-debug-open-main').children('span.ui-icon'), false);
+          $(this).text(Drupal.t('-Open all-'));
+          $('.rules-debug-open').next().hide();
+          Drupal.rules.changeDebugIcon($(this).prev().children('span.ui-icon'), false);
+        }
+      });
+    }
+  };
+
+  /**
+   * Changes the icon of a collapsible div.
+   */
+  Drupal.rules.changeDebugIcon = function(item, open) {
+    if (open == true) {
+      item.removeClass('ui-icon-triangle-1-e');
+      item.addClass('ui-icon-triangle-1-s');
+    }
+    else {
+      item.removeClass('ui-icon-triangle-1-s');
+      item.addClass('ui-icon-triangle-1-e');
+    }
+  }
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/rules.ui.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,196 @@
+@CHARSET "UTF-8";
+
+.rules-show-js, html.js .rules-hide-js {
+  display: none;
+}
+
+.rules-hide-js, html.js .rules-show-js {
+  display: block;
+}
+
+.rules-elements-table ul.action-links {
+  margin: 0px;
+  padding: 0;
+}
+
+.rules-elements-table ul.rules-operations li {
+  list-style: none;
+  float: left;
+}
+
+.rules-elements-table ul.rules-operations a {
+  background: none;
+  padding-left: 0px;
+}
+
+table tr.rules-elements-add {
+  background-color: #e5eff4;
+}
+
+.rules-elements-table ul.rules-operations-add a {
+  line-height: 1em;
+}
+
+
+tr.rules-elements-add td {
+  padding-top: 2px;
+  padding-bottom: 2px;
+}
+
+ul.rules-operations-add li {
+  float: left;
+  list-style-position: inside;
+}
+
+.rules-elements-table {
+  margin-bottom: 3em;
+}
+/* We cannot set a positive margin-top for rules tables as the table drag link
+   should be positioned directly on top of the table. Thus we use a large bottom
+   margin and fix the upper most margin: */
+#rules-form-wrapper:first-child {
+  margin-top: 1.5em;
+}
+
+/* Fix table drag weights to don't take extra space */
+.rules-elements-table .tabledrag-toggle-weight-wrapper {
+  position: absolute;
+  right: 0px;
+}
+
+.rules-elements-table caption, .rules-overview-table caption {
+  font-size: 110%;
+  font-weight: bold;
+  padding-bottom: 0.5em;
+  text-align: left;
+}
+
+.rules-overview-table {
+  margin: 1em 0;
+}
+
+.rules-content-group-integrity-error {
+  color: #df0101;
+}
+
+.rules-debug-log {
+  font: 81.3% "Lucida Grande","Lucida Sans Unicode",sans-serif;
+  background-color: #eeeeee;
+  border: 1px solid #cccccc;
+  color: #333333;
+  padding: 5px;
+  margin: 1.5em 0em;
+}
+
+.rules-debug-collapsible-link {
+  position: relative;
+  cursor: pointer;
+
+  /* The span element with the icon which opens the log, has a whitepsace.
+     Since we don't want the user to mark this white space, we prevent this
+     using the this code.*/
+  -moz-user-select: -moz-none;
+  -khtml-user-select: none;
+  -webkit-user-select: none;
+  -o-user-select: none;
+  user-select: none;
+}
+
+.rules-debug-log-head {
+  font-weight: bold;
+}
+
+div.rules-debug-log-head {
+  margin: 0.5em 0em;
+}
+
+.rules-debug-icon-open {
+  position: relative;
+  float: left;
+}
+
+.rules-debug-open-all {
+  position: relative;
+  float: right;
+}
+
+.rules-debug-log ul {
+  padding-left: 2em;
+}
+
+.rules-debug-log .rules-debug-warn {
+  color: #df0101;
+}
+
+.rules-debug-log .rules-debug-error {
+  font-weight: bold;
+  color: #df0101;
+}
+
+#rules-filter-form {
+  margin-bottom: 1.5em;
+}
+
+.rules-parameter-label {
+  font-style: italic;
+}
+
+#rules-plugin-add-help {
+  margin-bottom: 1em;
+}
+
+.rules-element-content {
+  float: left;
+}
+
+form input.rules-switch-button {
+  -moz-border-radius: 5px 5px 5px 5px;
+  cursor: pointer;
+  font-size: 0.8em;
+  font-weight: normal;
+  margin-bottom: 1em;
+  padding: 2px;
+  text-align: center;
+}
+
+.rules-form-heading {
+  margin-top: 3em;
+}
+
+.rules-autocomplete-button {
+  top: 3px;
+  height: 22px;
+}
+
+ul.rules-autocomplete {
+  max-height: 23em;
+  overflow-y: auto;
+}
+
+ul.rules-autocomplete div {
+  padding-left: 5px;
+}
+
+ul.rules-autocomplete a.ui-corner-all {
+  padding: 0px;
+}
+
+ul.rules-autocomplete .rules-dsac-group {
+  background-color: #eee;
+}
+
+ul.rules-autocomplete .ui-corner-all {
+  -moz-border-radius: 0px;
+}
+
+/**
+ * Do not display the hide/show descriptions link above the permissions matrix.
+ */
+#rules-form-wrapper #edit-settings-access-permissions .compact-link {
+  display: none;
+}
+
+/* IE 6 hack for max-height. */
+* html ul.rule-autocomplete{
+  height: 23em;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/rules.ui.seven.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,95 @@
+/**
+ * JQuery UI style sheet fix for the seven theme.
+ */
+
+.ui-button {
+  border: 1px solid #cccccc;
+  background: #e6e6e6;
+}
+
+.ui-state-hover,
+.ui-state-focus {
+  border: 1px solid #bbbbbb;
+}
+
+.ui-button.ui-state-active {
+  border: 1px solid #777777;
+  font-weight: bold;
+}
+
+/**
+ * Corner radius
+ */
+.ui-corner-tl {
+  -moz-border-radius-topleft: 4px;
+  -webkit-border-top-left-radius: 4px;
+  border-top-left-radius: 4px;
+}
+
+.ui-corner-tr {
+  -moz-border-radius-topright: 4px;
+  -webkit-border-top-right-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.ui-corner-bl {
+  -moz-border-radius-bottomleft: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+
+.ui-corner-br {
+  -moz-border-radius-bottomright: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+}
+
+.ui-corner-top {
+  -moz-border-radius-topleft: 4px;
+  -moz-border-radius-topright: 4px;
+  -webkit-border-top-left-radius: 4px;
+  -webkit-border-top-right-radius: 4px;
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.ui-corner-bottom {
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-bottomright: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+  border-bottom-right-radius: 4px;
+}
+
+.ui-corner-right {
+  -moz-border-radius-bottomright: 4px;
+  -moz-border-radius-topright: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+  -webkit-border-top-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.ui-corner-left {
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-topleft: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-top-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+  border-top-left-radius: 4px;
+}
+
+.ui-corner-all {
+  -moz-border-radius: 4px;
+  -webkit-border-radius: 4px;
+  border-radius: 4px;
+}
+
+/**
+ * Fix the position of the core-autocomplete popup when shown in the settings
+ * fieldset.
+ */
+.form-item-settings-tags {
+  position: relative;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/ui.controller.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,324 @@
+<?php
+
+/**
+ * @file Contains the UI controller for Rules.
+ */
+
+/**
+ * Controller class for the Rules UI.
+ *
+ * The Rules UI controller defines the methods other modules may use in order
+ * to easily re-use the UI, regardless whether the rules admin module is
+ * enabled.
+ */
+class RulesUIController {
+
+  /**
+   * Generates menu items to manipulate rules configurations.
+   *
+   * @param $base_path
+   *   The path to the overview page from where the configurations are edited.
+   */
+  public function config_menu($base_path) {
+    $items = array();
+    $base_count = count(explode('/', $base_path));
+    $items[$base_path . '/manage/%rules_config'] = array(
+      'title callback' => 'rules_get_title',
+      'title arguments' => array('Editing !plugin "!label"', $base_count + 1),
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_form_edit_rules_config', $base_count + 1, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'type' => MENU_VISIBLE_IN_BREADCRUMB,
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/add/%rules_element'] = array(
+      // Adding another part to the path would hit the menu path-part-limit
+      // for base paths like admin/config/workflow/rules. Therefor we have to
+      // use this fugly way for setting the title.
+      'title callback' => 'rules_menu_add_element_title',
+      // Wrap the integer in an array, so it is passed as is.
+      'title arguments' => array(array($base_count + 4)),
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_add_element', $base_count + 1, $base_count + 4, $base_count + 3, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'load arguments' => array($base_count + 1),
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/add/event'] = array(
+      'title callback' => 'rules_get_title',
+      'title arguments' => array('Adding event to !plugin "!label"', $base_count + 1),
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_add_event_page', $base_count + 1, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'load arguments' => array($base_count + 1),
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/delete/event'] = array(
+      //@todo: improve title.
+      'title' => 'Remove event',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_remove_event', $base_count + 1, $base_count + 4, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'description' => 'Remove an event from a reaction rule.',
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/edit/%rules_element'] = array(
+      'title callback' => 'rules_get_title',
+      'title arguments' => array('Editing !plugin "!label"', $base_count + 3),
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_edit_element', $base_count + 1, $base_count + 3, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'load arguments' => array($base_count + 1),
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/autocomplete'] = array(
+      'page callback' => 'rules_ui_form_data_selection_auto_completion',
+      'page arguments' => array($base_count + 3, $base_count + 4, $base_count + 5),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'type' => MENU_CALLBACK,
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/delete/%rules_element'] = array(
+      'title callback' => 'rules_get_title',
+      'title arguments' => array('Editing !plugin "!label"', $base_count + 3),
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_delete_element', $base_count + 1, $base_count + 3, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'load arguments' => array($base_count + 1),
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/%'] = array(
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_form_rules_config_confirm_op', $base_count + 1, $base_count + 2, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/clone'] = array(
+      'title callback' => 'rules_get_title',
+      'title arguments' => array('Cloning !plugin "!label"', $base_count + 1),
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_form_clone_rules_config', $base_count + 1, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/export'] = array(
+      'title callback' => 'rules_get_title',
+      'title arguments' => array('Export of !plugin "!label"', $base_count + 1),
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_form_export_rules_config', $base_count + 1, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('view', $base_count + 1),
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    $items[$base_path . '/manage/%rules_config/execute'] = array(
+      'title callback' => 'rules_get_title',
+      'title arguments' => array('Executing !plugin "!label"', $base_count + 1),
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('rules_ui_form_execute_rules_config', $base_count + 1, $base_path),
+      'access callback' => 'rules_config_access',
+      'access arguments' => array('update', $base_count + 1),
+      'file' => 'ui/ui.forms.inc',
+      'file path' => drupal_get_path('module', 'rules'),
+    );
+    drupal_alter('rules_ui_menu', $items, $base_path, $base_count);
+
+    if (module_exists('rules_scheduler')) {
+      $items[$base_path . '/manage/%rules_config/schedule'] = array(
+        'title callback' => 'rules_get_title',
+        'title arguments' => array('Schedule !plugin "!label"', $base_count + 1),
+        'page callback' => 'drupal_get_form',
+        'page arguments' => array('rules_scheduler_schedule_form', $base_count + 1, $base_path),
+        'access callback' => 'rules_config_access',
+        'access arguments' => array('update', $base_count + 1),
+        'file' => 'rules_scheduler.admin.inc',
+        'file path' => drupal_get_path('module', 'rules_scheduler'),
+      );
+    }
+    return $items;
+  }
+
+  /**
+   * Generates the render array for a overview configuration table for arbitrary
+   * rule configs that match the given conditions.
+   *
+   * Note: The generated overview table contains multiple links for editing the
+   * rule configurations. For the links to properly work use
+   * RulesUIController::config_menu($base_path) to generate appropriate menu
+   * items for the path at which the overview table is displayed.
+   *
+   * @param $conditions
+   *   An array of conditions as needed by rules_config_load_multiple().
+   * @param $options
+   *   An array with optional options. Known keys are:
+   *   - 'hide status op': If set to TRUE, enable/disable links are not added.
+   *     Defaults to FALSE.
+   *   - 'show plugin': If set to FALSE, the plugin is not shown. Defaults to
+   *     TRUE.
+   *   - 'show events': If set to TRUE, the event column is shown. Defaults to
+   *     TRUE if only reaction rules are listed.
+   *   - 'show execution op': If set to TRUE an operation for execution a
+   *     component is shown for components, as well as a link to schedule a
+   *     component if the rules scheduler module is enabled.
+   *   - 'base path': Optionally, a different base path to use instead of the
+   *     currently set RulesPluginUI::$basePath. If no base path has been set
+   *     yet, the current path is used by default.
+   *
+   * @return Array
+   *   A renderable array.
+   */
+  public function overviewTable($conditions = array(), $options = array()) {
+    $options += array(
+      'hide status op' => FALSE,
+      'show plugin' => TRUE,
+      'show events' => isset($conditions['plugin']) && $conditions['plugin'] == 'reaction rule',
+      'show execution op' => !(isset($conditions['plugin']) && $conditions['plugin'] == 'reaction rule'),
+    );
+    // By default show only configurations owned by rules.
+    $conditions += array(
+      'owner' => 'rules',
+    );
+    if (!empty($options['base path'])) {
+      RulesPluginUI::$basePath = $options['base path'];
+    }
+    else if (!isset(RulesPluginUI::$basePath)) {
+      // Default to the current path, only if no path has been set yet.
+      RulesPluginUI::$basePath = current_path();
+    }
+
+    $entities = entity_load('rules_config', FALSE, $conditions);
+    ksort($entities);
+
+    // Prepare some variables used by overviewTableRow().
+    $this->event_info = rules_fetch_data('event_info');
+    $this->cache = rules_get_cache();
+
+    $rows = array();
+    foreach ($entities as $id => $entity) {
+      if (user_access('bypass rules access') || $entity->access()) {
+        $rows[] = $this->overviewTableRow($conditions, $id, $entity, $options);
+      }
+    }
+    // Assemble the right table header.
+    $header = array(t('Name'), t('Event'), t('Plugin'), t('Status'), array('data' => t('Operations')));
+    if (!$options['show events']) {
+      // Remove the event heading as there is no such column.
+      unset($header[1]);
+    }
+    if (!$options['show plugin']) {
+      unset($header[2]);
+    }
+    // Fix the header operation column colspan.
+    $num_cols = isset($rows[0]) ? count($rows[0]) : 0;
+    if (($addition = $num_cols - count($header)) > 0) {
+      $header[4]['colspan'] = $addition + 1;
+    }
+
+    $table = array(
+      '#theme' => 'table',
+      '#header' => $header,
+      '#rows' => $rows,
+      '#empty' => t('None.'),
+    );
+    $table['#attributes']['class'][] = 'rules-overview-table';
+    $table['#attached']['css'][] = drupal_get_path('module', 'rules') . '/ui/rules.ui.css';
+
+    // TODO: hide configs where access() is FALSE.
+    return $table;
+  }
+
+  /**
+   * Generates the row for a single rules config.
+   *
+   * @param $additional_cols
+   *   Additional columns to be added after the entity label column.
+   */
+  protected function overviewTableRow($conditions, $name, $config, $options) {
+    // Build content includes the label, as well as a short overview including
+    // the machine name.
+    $row[] = array('data' => $config->buildContent());
+
+    // Add events if the configs are assigned to events.
+    if ($options['show events']) {
+      $events = array();
+      if ($config instanceof RulesTriggerableInterface) {
+        foreach ($config->events() as $event_name) {
+          $event_handler = rules_get_event_handler($event_name, $config->getEventSettings($event_name));
+          $events[] = $event_handler->summary();
+        }
+      }
+      $row[] = implode(", ", $events);
+    }
+    if ($options['show plugin']) {
+      $plugin = $config->plugin();
+      $row[] = isset($this->cache['plugin_info'][$plugin]['label']) ? $this->cache['plugin_info'][$plugin]['label'] : $plugin;
+    }
+
+    $row[] = array('data' => array(
+      '#theme' => 'entity_status',
+      '#status' => $config->status,
+    ));
+
+    // Add operations depending on the options and the exportable status.
+    if (!$config->hasStatus(ENTITY_FIXED)) {
+      $row[] =  l(t('edit'), RulesPluginUI::path($name), array('attributes' => array('class' => array('edit', 'action'))));
+      if (module_exists('rules_i18n')) {
+        $row[] =  l(t('translate'), RulesPluginUI::path($name, 'translate'), array('attributes' => array('class' => array('translate', 'action'))));
+      }
+    }
+    else {
+      $row[] = '';
+      if (module_exists('rules_i18n')) {
+        $row[] = '';
+      }
+    }
+
+    if (!$options['hide status op']) {
+      // Add either an enable or disable link.
+      $text = $config->active ? t('disable') : t('enable');
+      $active_class = $config->active ? 'disable' : 'enable';
+      $link_path = RulesPluginUI::path($name, $active_class);
+      $row[] = $config->hasStatus(ENTITY_FIXED) ? '' : l($text, $link_path, array('attributes' => array('class' => array($active_class, 'action')), 'query' => drupal_get_destination()));
+    }
+    $row[] = l(t('clone'), RulesPluginUI::path($name, 'clone'), array('attributes' => array('class' => array('clone', 'action'))));
+
+    // Add execute link for for components.
+    if ($options['show execution op']) {
+      $row[] = ($config instanceof RulesTriggerableInterface) ? '' : l(t('execute'), RulesPluginUI::path($name, 'execute'), array('attributes' => array('class' => array('execute', 'action')), 'query' => drupal_get_destination()));
+      if (module_exists('rules_scheduler')) {
+        // Add schedule link for action components only.
+        $row[] = $config instanceof RulesActionInterface ? l(t('schedule'), RulesPluginUI::path($name, 'schedule'), array('attributes' => array('class' => array('schedule', 'action')), 'query' => drupal_get_destination())) : '';
+      }
+    }
+
+    if (!$config->hasStatus(ENTITY_IN_CODE) && !$config->hasStatus(ENTITY_FIXED)) {
+      $row[] = l(t('delete'), RulesPluginUI::path($name, 'delete'), array('attributes' => array('class' => array('delete', 'action')), 'query' => drupal_get_destination()));
+    }
+    elseif ($config->hasStatus(ENTITY_OVERRIDDEN) && !$config->hasStatus(ENTITY_FIXED)) {
+      $row[] = l(t('revert'), RulesPluginUI::path($name, 'revert'), array('attributes' => array('class' => array('revert', 'action')), 'query' => drupal_get_destination()));
+    }
+    else {
+      $row[] = '';
+    }
+    $row[] = l(t('export'), RulesPluginUI::path($name, 'export'), array('attributes' => array('class' => array('export', 'action'))));
+    return $row;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/ui.core.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1275 @@
+<?php
+
+/**
+ * @file Contains core ui functions.
+ */
+
+/**
+ * Plugin UI Interface.
+ */
+interface RulesPluginUIInterface {
+
+  /**
+   * Adds the whole configuration form of this rules configuration. For rule
+   * elements that are part of a configuration this method just adds the
+   * elements configuration form.
+   *
+   * @param $form
+   *   The form array where to add the form.
+   * @param $form_state
+   *   The current form state.
+   * @param $options
+   *   An optional array of options with the known keys:
+   *    - 'show settings': Whether to include the 'settings' fieldset for
+   *      editing configuration settings like the label or categories. Defaults
+   *      to FALSE.
+   *    - 'button': Whether a submit button should be added. Defaults to FALSE.
+   *    - 'init': Whether the element is about to be configured the first time
+   *      and the configuration is about to be initialized. Defaults to FALSE.
+   *    - 'restrict plugins: May be used to restrict the list of rules plugins
+   *      that may be added to this configuration. For that set an array of
+   *      valid plugins. Note that conditions and actions are always valid, so
+   *      just set an empty array for just allowing those.
+   *    - 'restrict conditions': Optionally set an array of condition names to
+   *      restrict the conditions that are available for adding.
+   *    - 'restrict actions': Optionally set an array of action names to
+   *      restrict the actions that are available to for adding.
+   *    - 'restrict events': Optionally set an array of event names to restrict
+   *      the events that are available for adding.
+   *
+   *  @todo
+   *    Implement the 'restrict *' options.
+   */
+  public function form(&$form, &$form_state, $options = array());
+
+  /**
+   * Validate the configuration form of this rule element.
+   *
+   * @param $form
+   * @param $form_state
+   */
+  public function form_validate($form, &$form_state);
+
+  /**
+   * Submit the configuration form of this rule element. This makes sure to
+   * put the updated configuration in the form state. For saving changes
+   * permanently, just call $config->save() afterwards.
+   *
+   * @param $form
+   * @param $form_state
+   */
+  public function form_submit($form, &$form_state);
+
+  /**
+   * Returns a structured array for rendering this element in overviews.
+   */
+  public function buildContent();
+
+  /**
+   * Returns the help text for editing this plugin.
+   */
+  public function help();
+
+  /**
+   * Returns ui operations for this element.
+   */
+  public function operations();
+
+}
+
+/**
+ * Helper object for mapping elements to ids.
+ */
+class RulesElementMap {
+
+  /**
+   * @var RulesPlugin
+   */
+  protected $configuration;
+  protected $index = array();
+  protected $counter = 0;
+
+  public function __construct(RulesPlugin $config) {
+    $this->configuration = $config->root();
+  }
+
+  /**
+   * Makes sure each element has an assigned id.
+   */
+  public function index() {
+    foreach ($this->getUnIndexedElements($this->configuration) as $element) {
+      $id = &$element->property('elementId');
+      $id = ++$this->counter;
+      $this->index[$id] = $element;
+    }
+  }
+
+  protected function getUnIndexedElements($element, &$unindexed = array()) {
+    // Remember unindexed elements.
+    $id = $element->property('elementId');
+    if (!isset($id)) {
+      $unindexed[] = $element;
+    }
+    else {
+      // Make sure $this->counter refers to the highest id.
+      if ($id > $this->counter) {
+        $this->counter = $id;
+      }
+      $this->index[$id] = $element;
+    }
+    // Recurse down the tree.
+    if ($element instanceof RulesContainerPlugin) {
+      foreach ($element as $child) {
+        $this->getUnIndexedElements($child, $unindexed);
+      }
+    }
+    return $unindexed;
+  }
+
+  /**
+   * Looks up the element with the given id.
+   */
+  public function lookup($id) {
+    if (!$this->index) {
+      $this->index();
+    }
+    return isset($this->index[$id]) ? $this->index[$id] : FALSE;
+  }
+}
+
+/**
+ * Faces UI extender for all kind of Rules plugins. Provides various useful
+ * methods for any rules UI.
+ */
+class RulesPluginUI extends FacesExtender implements RulesPluginUIInterface {
+
+  /**
+   * @var RulesPlugin
+   */
+  protected $element;
+
+  /**
+   * The base path determines where a Rules overview UI lives. All forms that
+   * want to display Rules (overview) forms need to set this variable. This is
+   * necessary in order to get correct operation links, paths, redirects, bread
+   * crumbs etc. for the form() and overviewTable() methods.
+   *
+   * @see RulesUIController
+   * @see rules_admin_reaction_overview()
+   * @see rules_admin_components_overview()
+   */
+  public static $basePath = NULL;
+
+  /**
+   * Provide $this->element to make the code more meaningful.
+   */
+  public function __construct(FacesExtendable $object) {
+    parent::__construct($object);
+    $this->element = $object;
+  }
+
+  /**
+   * Returns the form values for the given form, possible being only a part of the whole form.
+   *
+   * In case the form is embedded somewhere, this function figures out the
+   * location of its form values and returns them for further use.
+   *
+   * @param $form
+   *   A form array, or an array of form elements to get the value for.
+   * @param $form_state
+   *   The form state as usual.
+   */
+  public static function &getFormStateValues($form, &$form_state) {
+    $values = NULL;
+    if (isset($form_state['values'])) {
+      // Assume the top level if parents are not yet set.
+      $form += array('#parents' => array());
+      $values = &$form_state['values'];
+      foreach ($form['#parents'] as $parent) {
+        $values = &$values[$parent];
+      }
+    }
+    return $values;
+  }
+
+  /**
+   * Implements RulesPluginUIInterface.
+   * Generates the element edit form.
+   *
+   * Note: Make sure that you set RulesPluginUI::$basePath before using this
+   * method, otherwise paths, links, redirects etc. won't be correct.
+   */
+  public function form(&$form, &$form_state, $options = array()) {
+    self::formDefaults($form, $form_state);
+    $form_state += array('rules_element' => $this->element);
+
+    // Add the help to the top of the form.
+    $help = $this->element->help();
+    $form['help'] = is_array($help) ? $help : array('#markup' => $help);
+
+    // We use $form_state['element_settings'] to store the settings of both
+    // parameter modes. That way one can switch between the parameter modes
+    // without losing the settings of those.
+    $form_state += array('element_settings' => $this->element->settings);
+    $settings = $this->element->settings + $form_state['element_settings'];
+
+    $form['parameter'] = array(
+      '#tree' => TRUE,
+    );
+
+    foreach ($this->element->pluginParameterInfo() as $name => $parameter) {
+      if ($parameter['type'] == 'hidden') {
+        continue;
+      }
+
+      $form['parameter'][$name] = array(
+        '#type' => 'fieldset',
+        '#title' => check_plain($parameter['label']),
+        '#description' => filter_xss(isset($parameter['description']) ? $parameter['description'] : ''),
+      );
+
+      // Init the parameter input mode.
+      $form_state['parameter_mode'][$name] = !isset($form_state['parameter_mode'][$name]) ? NULL : $form_state['parameter_mode'][$name];
+      $form['parameter'][$name] += $this->getParameterForm($name, $parameter, $settings, $form_state['parameter_mode'][$name]);
+    }
+
+    // Provide a form for editing the label and name of provided variables.
+    $settings = $this->element->settings;
+    foreach ($this->element->pluginProvidesVariables() as $var_name => $var_info) {
+      $form['provides'][$var_name] = array(
+        '#type' => 'fieldset',
+        '#title' => check_plain($var_info['label']),
+        '#description' => filter_xss(isset($var_info['description']) ? $var_info['description'] : ''),
+      );
+      $form['provides'][$var_name]['label'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Variable label'),
+        '#default_value' => isset($settings[$var_name . ':label']) ? $settings[$var_name . ':label'] : $var_info['label'],
+        '#required' => TRUE,
+      );
+      $form['provides'][$var_name]['var'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Variable name'),
+        '#default_value' => isset($settings[$var_name . ':var']) ? $settings[$var_name . ':var'] : $var_name,
+        '#description' => t('The variable name must contain only lowercase letters, numbers, and underscores and must be unique in the current scope.'),
+        '#element_validate' => array('rules_ui_element_machine_name_validate'),
+        '#required' => TRUE,
+      );
+    }
+    if (!empty($form['provides'])) {
+      $help = '<div class="description">' . t('Adjust the names and labels of provided variables, but note that renaming of already utilizied variables invalidates the existing uses.') . '</div>';
+      $form['provides'] += array(
+        '#tree' => TRUE,
+        '#prefix' => '<h4 class="rules-form-heading">' . t('Provided variables') . '</h4>' . $help,
+      );
+    }
+
+    // Add settings form, if specified.
+    if (!empty($options['show settings'])) {
+      $this->settingsForm($form, $form_state);
+    }
+    // Add submit button, if specified.
+    if (!empty($options['button'])) {
+      $form['submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Save'),
+        '#weight' => 10,
+      );
+    }
+  }
+
+  /**
+   * Actually generates the parameter form for the given data type.
+   */
+  protected function getParameterForm($name, $info, $settings, &$mode) {
+    $class = $this->getDataTypeClass($info['type'], $info);
+    $supports_input_mode = in_array('RulesDataDirectInputFormInterface', class_implements($class));
+
+    // Init the mode.
+    if (!isset($mode)) {
+      if (isset($settings[$name . ':select'])) {
+        $mode = 'selector';
+      }
+      elseif (isset($settings[$name]) && $supports_input_mode) {
+        $mode = 'input';
+      }
+      elseif (isset($info['restriction'])) {
+        $mode = $info['restriction'];
+      }
+      else {
+        // Allow the parameter to define the 'default mode' and fallback to the
+        // data type default.
+        $mode = !empty($info['default mode']) ? $info['default mode'] : call_user_func(array($class, 'getDefaultMode'));
+      }
+    }
+
+    // For translatable parameters, pre-populate an internal translation source
+    // key so data type forms or input evaluators (i18n) may produce suiting
+    // help.
+    if (drupal_multilingual() && !empty($info['translatable'])) {
+      $parameter = $this->element->pluginParameterInfo();
+      $info['custom translation language'] = !empty($parameter['language']);
+    }
+
+    // Add the parameter form.
+    if ($mode == 'input' && $supports_input_mode) {
+      $form['settings'] = call_user_func(array($class, 'inputForm'), $name, $info, $settings, $this->element);
+    }
+    else {
+      $form['settings'] = call_user_func(array($class, 'selectionForm'), $name, $info, $settings, $this->element);
+    }
+
+    // Add a link for switching the input mode when JS is enabled and a button
+    // to switch it without javascript, in case switching is possible.
+    if ($supports_input_mode && empty($info['restriction'])) {
+      $value = $mode == 'selector' ? t('Switch to the direct input mode') : t('Switch to data selection');
+
+      $form['switch_button'] = array(
+        '#type' => 'submit',
+        '#name' => 'param_' . $name,
+        '#attributes' => array('class' => array('rules-switch-button')),
+        '#parameter' => $name,
+        '#value' => $value,
+        '#submit' => array('rules_ui_parameter_replace_submit'),
+        '#ajax' => rules_ui_form_default_ajax('none'),
+        // Do not validate!
+        '#limit_validation_errors' => array(),
+      );
+    }
+    return $form;
+  }
+
+  /**
+   * Implements RulesPluginUIInterface.
+   */
+  public function form_validate($form, &$form_state) {
+    $this->form_extract_values($form, $form_state);
+    $form_values = RulesPluginUI::getFormStateValues($form, $form_state);
+
+    if (isset($form_values['provides'])) {
+      $vars = $this->element->availableVariables();
+      foreach ($form_values['provides'] as $name => $values) {
+        if (isset($vars[$values['var']])) {
+          form_error($form['provides'][$name]['var'], t('The variable name %name is already taken.', array('%name' => $values['var'])));
+        }
+      }
+    }
+    // Settings have been updated, so process them now.
+    $this->element->processSettings(TRUE);
+
+    // Make sure the current user really has access to configure this element
+    // as well as the used input evaluators and data processors.
+    if (!user_access('bypass rules access') && !$this->element->root()->access()) {
+      form_set_error('', t('Access violation! You have insufficient access permissions to edit this configuration.'));
+    }
+    if (!empty($form['settings'])) {
+      $this->settingsFormValidate($form, $form_state);
+    }
+  }
+
+  /**
+   * Applies the values of the form to the element.
+   */
+  public function form_extract_values($form, &$form_state) {
+    $this->element->settings = array();
+    $form_values = RulesPluginUI::getFormStateValues($form, $form_state);
+    if (isset($form_values['parameter'])) {
+      foreach ($form_values['parameter'] as $name => $values) {
+        $this->element->settings += $values['settings'];
+      }
+    }
+    if (isset($form_values['provides'])) {
+      foreach ($form_values['provides'] as $name => $values) {
+        $this->element->settings[$name . ':label'] = $values['label'];
+        $this->element->settings[$name . ':var'] = $values['var'];
+      }
+    }
+    if (!empty($form['settings'])) {
+      $this->settingsFormExtractValues($form, $form_state);
+    }
+  }
+
+  /**
+   * Implements RulesPluginUIInterface.
+   */
+  public function form_submit($form, &$form_state) {
+    if (!empty($form['settings'])) {
+      $this->settingsFormSubmit($form, $form_state);
+    }
+    $this->element->save();
+  }
+
+  /**
+   * Adds the configuration settings form (label, tags, description, ..).
+   */
+  public function settingsForm(&$form, &$form_state) {
+    $form_values = RulesPluginUI::getFormStateValues($form, $form_state);
+    // Add the settings in a separate fieldset below.
+    $form['settings'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Settings'),
+      '#collapsible' => TRUE,
+      '#collapsed' => empty($form_values['settings']['vars']['more']),
+      '#weight' => 5,
+      '#tree' => TRUE,
+    );
+    $form['settings']['label'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Name'),
+      '#default_value' => $this->element->label(),
+      '#required' => TRUE,
+      '#weight' => -5,
+    );
+    // @todo: For Drupal 8 use "owner" for generating machine names and
+    // module only for the modules providing default configurations.
+    if (!empty($this->element->module) && !empty($this->element->name) && $this->element->module == 'rules' && strpos($this->element->name, 'rules_') === 0) {
+      // Remove the Rules module prefix from the machine name.
+      $machine_name = substr($this->element->name, strlen($this->element->module) + 1);
+    }
+    else {
+      $machine_name = $this->element->name;
+    }
+    $form['settings']['name'] = array(
+      '#type' => 'machine_name',
+      '#default_value' => isset($machine_name) ? $machine_name : '',
+      // The string 'rules_' is pre-pended to machine names, so the
+      // maxlength must be less than the field length of 64 characters.
+      '#maxlength' => 58,
+      '#disabled' => entity_has_status('rules_config', $this->element, ENTITY_IN_CODE) && !(isset($form_state['op']) && $form_state['op'] == 'clone'),
+      '#machine_name' => array(
+        'exists' => 'rules_config_load',
+        'source' => array('settings', 'label'),
+      ),
+      '#required' => TRUE,
+      '#description' => t('The machine-readable name of this configuration is used by rules internally to identify the configuration. This name must contain only lowercase letters, numbers, and underscores and must be unique.'),
+    );
+    $form['settings']['tags'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Tags'),
+      '#default_value' => isset($this->element->tags) ? drupal_implode_tags($this->element->tags) : '',
+      '#autocomplete_path' => 'admin/config/workflow/rules/autocomplete_tags',
+      '#description' => t('Tags associated with this configuration, used for filtering in the admin interface. Separate multiple tags with commas.'),
+    );
+
+    // Show a form for editing variables for components.
+    if (($plugin_info = $this->element->pluginInfo()) && !empty($plugin_info['component'])) {
+      if ($this->element->hasStatus(ENTITY_IN_CODE)) {
+        $description = t('The variables used by the component. They can not be edited for configurations that are provided in code.');
+      }
+      else {
+        $description = t('Variables are normally input <em>parameters</em> for the component – data that should be available for the component to act on. Additionaly, action components may <em>provide</em> variables back to the caller. Each variable must have a specified data type, a label and a unique machine readable name containing only lowercase alphanumeric characters and underscores. See <a href="@url">the online documentation</a> for more information about variables.',
+          array('@url' => rules_external_help('variables'))
+        );
+      }
+      $form['settings']['vars'] = array(
+        '#prefix' => '<div id="rules-component-variables">',
+        '#suffix' => '</div>',
+        '#tree' => TRUE,
+        '#element_validate' => array('rules_ui_element_variable_form_validate'),
+        '#theme' => 'rules_ui_variable_form',
+        '#title' => t('Variables'),
+        '#description' => $description,
+        // Variables can not be edited on configurations in code.
+        '#disabled' => $this->element->hasStatus(ENTITY_IN_CODE),
+      );
+
+      $weight = 0;
+      $provides = $this->element->providesVariables();
+      foreach ($this->element->componentVariables() as $name => $var_info) {
+        $form['settings']['vars']['items'][$name] = RulesPluginUI::getVariableForm($name, $var_info, isset($provides[$name]));
+        $form['settings']['vars']['items'][$name]['weight']['#default_value'] = $weight++;
+      }
+      // Always add three empty forms.
+      for ($i = 0; $i < 3; $i++) {
+        $form['settings']['vars']['items'][$i] = RulesPluginUI::getVariableForm();
+        $form['settings']['vars']['items'][$i]['weight']['#default_value'] = $weight++;
+      }
+      $form['settings']['vars']['more'] = array(
+        '#type' => 'submit',
+        '#value' => t('Add more'),
+        // Enable AJAX once #756762 is fixed.
+        // '#ajax' => rules_ui_form_default_ajax('none'),
+        '#limit_validation_errors' => array(array('vars')),
+        '#submit' => array('rules_form_submit_rebuild'),
+      );
+      if (!empty($this->element->id)) {
+        // Display a setting to manage access.
+        $form['settings']['access'] = array(
+          '#weight' => 50,
+        );
+        $plugin_type = $this->element instanceof RulesActionInterface ? t('action') : t('condition');
+        $form['settings']['access']['access_exposed'] = array(
+          '#type' => 'checkbox',
+          '#title' => t('Configure access for using this component with a permission.'),
+          '#default_value' => !empty($this->element->access_exposed),
+          '#description' => t('By default, the @plugin-type for using this component may be only used by users that have access to configure the component. If checked, access is determined by a permission instead.', array('@plugin-type' => $plugin_type))
+        );
+        $form['settings']['access']['permissions'] = array(
+          '#type' => 'container',
+          '#states' => array(
+            'visible' => array(
+              ':input[name="settings[access][access_exposed]"]' => array('checked' => TRUE),
+            ),
+          ),
+        );
+        $form['settings']['access']['permissions']['matrix'] = $this->settingsFormPermissionMatrix();
+      }
+    }
+
+    // TODO: Attach field form thus description.
+  }
+
+  /**
+   * Provides a matrix permission for the component based in the existing roles.
+   *
+   * @return
+   *   Form elements with the matrix of permissions for a component.
+   */
+  protected function settingsFormPermissionMatrix() {
+    $form['#theme'] = 'user_admin_permissions';
+    $status = array();
+    $options = array();
+
+    $role_names = user_roles();
+    $role_permissions = user_role_permissions($role_names);
+    $component_permission = rules_permissions_by_component(array($this->element));
+    $component_permission_name = key($component_permission);
+
+    $form['permission'][$component_permission_name] = array(
+      '#type' => 'item',
+      '#markup' => $component_permission[$component_permission_name]['title'],
+    );
+    $options[$component_permission_name] = '';
+    foreach ($role_names as $rid => $name) {
+      if (isset($role_permissions[$rid][$component_permission_name])) {
+        $status[$rid][] = $component_permission_name;
+      }
+    }
+
+    // Build the checkboxes for each role.
+    foreach ($role_names as $rid => $name) {
+      $form['checkboxes'][$rid] = array(
+        '#type' => 'checkboxes',
+        '#options' => $options,
+        '#default_value' => isset($status[$rid]) ? $status[$rid] : array(),
+        '#attributes' => array('class' => array('rid-' . $rid)),
+      );
+      $form['role_names'][$rid] = array('#markup' => check_plain($name), '#tree' => TRUE);
+    }
+
+    // Attach the default permissions page JavaScript.
+    $form['#attached']['js'][] = drupal_get_path('module', 'user') . '/user.permissions.js';
+
+    return $form;
+  }
+
+  public function settingsFormExtractValues($form, &$form_state) {
+    $form_values = RulesPluginUI::getFormStateValues($form['settings'], $form_state);
+    $this->element->label = $form_values['label'];
+    // If the name was changed we have to redirect to the URL that contains
+    // the new name, instead of rebuilding on the old URL with the old name
+    if ($form['settings']['name']['#default_value'] != $form_values['name']) {
+      $module = isset($this->element->module) ? $this->element->module : 'rules';
+      $this->element->name = $module . '_' . $form_values['name'];
+      $form_state['redirect'] = RulesPluginUI::path($this->element->name, 'edit', $this->element);
+    }
+    $this->element->tags = empty($form_values['tags']) ? array() : drupal_explode_tags($form_values['tags']);
+
+    if (isset($form_values['vars']['items'])) {
+      $vars = &$this->element->componentVariables();
+      $vars = array();
+      if ($this->element instanceof RulesActionContainer) {
+        $provides = &$this->element->componentProvidesVariables();
+        $provides = array();
+      }
+
+      usort($form_values['vars']['items'], 'rules_element_sort_helper');
+      foreach ($form_values['vars']['items'] as $item) {
+        if ($item['type'] && $item['name'] && $item['label']) {
+          $vars[$item['name']] = array('label' => $item['label'], 'type' => $item['type']);
+          if (!$item['usage'][0]) {
+            $vars[$item['name']]['parameter'] = FALSE;
+          }
+          if ($item['usage'][1] && isset($provides)) {
+            $provides[] = $item['name'];
+          }
+        }
+      }
+      // Disable FAPI persistence for the variable form so renumbering works.
+      $input = &$form_state['input'];
+      foreach ($form['settings']['#parents'] as $parent) {
+        $input = &$input[$parent];
+      }
+      unset($input['vars']);
+    }
+    $this->element->access_exposed = isset($form_values['access']['access_exposed']) ? $form_values['access']['access_exposed'] : FALSE;
+  }
+
+  public function settingsFormValidate($form, &$form_state) {
+    $form_values = RulesPluginUI::getFormStateValues($form['settings'], $form_state);
+    if ($form['settings']['name']['#default_value'] != $form_values['name'] && rules_config_load($this->element->name)) {
+      form_error($form['settings']['name'], t('The machine-readable name %name is already taken.', array('%name' => $form_values['name'])));
+    }
+  }
+
+  public function settingsFormSubmit($form, &$form_state) {
+    if (isset($form_state['values']['settings']['access']) && !empty($this->element->access_exposed)) {
+      // Save the permission matrix.
+      foreach ($form_state['values']['settings']['access']['permissions']['matrix']['checkboxes'] as $rid => $value) {
+        user_role_change_permissions($rid, $value);
+      }
+    }
+  }
+
+  /**
+   * Returns the form for configuring the info of a single variable.
+   */
+  public function getVariableForm($name = '', $info = array(), $provided = FALSE) {
+    $form['type'] = array(
+      '#type' => 'select',
+      '#options' => array(0 => '--') + RulesPluginUI::getOptions('data'),
+      '#default_value' => isset($info['type']) ? $info['type'] : 0,
+    );
+    $form['label'] = array(
+      '#type' => 'textfield',
+      '#size' => 40,
+      '#default_value' => isset($info['label']) ? $info['label'] : '',
+    );
+    $form['name'] = array(
+      '#type' => 'textfield',
+      '#size' => 40,
+      '#default_value' => $name,
+      '#element_validate' => array('rules_ui_element_machine_name_validate'),
+    );
+
+    $usage[0] = !isset($info['parameter']) || $info['parameter'] ? 1 : 0;
+    $usage[1] = $provided ? 1 : 0;
+
+    $form['usage'] = array(
+      '#type' => 'select',
+      '#default_value' => implode('', $usage),
+      '#options' => array(
+        '10' => t('Parameter'),
+        '11' => t('Parameter + Provided'),
+        '01' => t('Provided'),
+      ),
+    );
+    if ($this->element instanceof RulesConditionContainer) {
+      $form['usage']['#disabled'] = TRUE;
+    }
+
+    // Just set the weight #default_value for the returned form.
+    $form['weight'] = array(
+      '#type' => 'weight',
+    );
+    return $form;
+  }
+
+  /**
+   * Returns the name of class for the given data type.
+   *
+   * @param $data_type
+   *   The name of the data typ
+   * @param $parameter_info
+   *   (optional) An array of info about the to be configured parameter. If
+   *   given, this array is complemented with data type defaults also.
+   */
+  public function getDataTypeClass($data_type, &$parameter_info = array()) {
+    $cache = rules_get_cache();
+    $data_info = $cache['data_info'];
+    // Add in data-type defaults.
+    if (empty($parameter_info['ui class'])) {
+      $parameter_info['ui class'] = (is_string($data_type) && isset($data_info[$data_type]['ui class'])) ? $data_info[$data_type]['ui class'] : 'RulesDataUI';
+    }
+    if (is_subclass_of($parameter_info['ui class'], 'RulesDataInputOptionsListInterface')) {
+      $parameter_info['options list'] = array($parameter_info['ui class'], 'optionsList');
+    }
+    return $parameter_info['ui class'];
+  }
+
+  /**
+   * Implements RulesPluginUIInterface.
+   * Show a preview of the configuration settings.
+   */
+  public function buildContent() {
+    $config_name = $this->element->root()->name;
+    $content['label'] = array(
+      '#type' => 'link',
+      '#title' => $this->element->label(),
+      '#href' => $this->element->isRoot() ? RulesPluginUI::path($config_name) : RulesPluginUI::path($config_name, 'edit', $this->element),
+      '#prefix' => '<div class="rules-element-label">',
+      '#suffix' => '</div>'
+    );
+    // Put the elements below in a "description" div.
+    $content['description'] = array(
+      '#prefix' => '<div class="description">',
+    );
+    $content['description']['parameter'] = array(
+      '#caption' => t('Parameter'),
+      '#theme' => 'rules_content_group',
+    );
+    foreach ($this->element->pluginParameterInfo() as $name => $parameter) {
+      $element = array();
+      if (!empty($this->element->settings[$name . ':select'])) {
+        $element['content'] = array(
+         '#markup' => '[' . $this->element->settings[$name . ':select'] . ']',
+        );
+      }
+      elseif (isset($this->element->settings[$name]) && (!isset($parameter['default value']) || $parameter['default value'] != $this->element->settings[$name])) {
+        $class = $this->getDataTypeClass($parameter['type'], $parameter);
+        $method = empty($parameter['options list']) ? 'render' : 'renderOptionsLabel';
+        // We cannot use method_exists() here as it would trigger a PHP bug,
+        // @see http://drupal.org/node/1258284
+        $element = call_user_func(array($class, $method), $this->element->settings[$name], $name, $parameter, $this->element);
+      }
+      // Only add parameters that are really configured / not default.
+      if ($element) {
+        $content['description']['parameter'][$name] = array(
+          '#theme' => 'rules_parameter_configuration',
+          '#info' => $parameter,
+        ) + $element;
+      }
+    }
+    foreach ($this->element->providesVariables() as $name => $var_info) {
+      $content['description']['provides'][$name] = array(
+        '#theme' => 'rules_variable_view',
+        '#info' => $var_info,
+        '#name' => $name,
+      );
+    }
+    if (!empty($content['description']['provides'])) {
+      $content['description']['provides'] += array(
+        '#caption' => t('Provides variables'),
+        '#theme' => 'rules_content_group',
+      );
+    }
+    // Add integrity exception messages if there are any for this element.
+    try {
+      $this->element->integrityCheck();
+      // A configuration is still marked as dirty, but already works again.
+      if (!empty($this->element->dirty)) {
+        rules_config_update_dirty_flag($this->element);
+        $variables = array('%label' => $this->element->label(), '%name' => $this->element->name, '@plugin' => $this->element->plugin());
+        drupal_set_message(t('The @plugin %label (%name) was marked dirty, but passes the integrity check now and is active again.', $variables));
+        rules_clear_cache();
+      }
+    }
+    catch (RulesIntegrityException $e) {
+      $content['description']['integrity'] = array(
+        '#theme' => 'rules_content_group',
+        '#caption' => t('Error'),
+        '#attributes' => array('class' => array('rules-content-group-integrity-error')),
+        'error' => array(
+          '#markup' => filter_xss($e->getMessage()),
+        ),
+      );
+      // Also make sure the rule is marked as dirty.
+      if (empty($this->element->dirty)) {
+        rules_config_update_dirty_flag($this->element);
+        rules_clear_cache();
+      }
+    }
+
+    $content['#suffix'] = '</div>';
+    $content['#type'] = 'container';
+    $content['#attributes']['class'][] = 'rules-element-content';
+    return $content;
+  }
+
+  /**
+   * Implements RulesPluginUIInterface.
+   */
+  public function operations() {
+    $name = $this->element->root()->name;
+    $render = array(
+      '#theme' => 'links__rules',
+    );
+    $render['#attributes']['class'][] = 'rules-operations';
+    $render['#attributes']['class'][] = 'action-links';
+    $render['#links']['edit'] = array(
+      'title' => t('edit'),
+      'href' => RulesPluginUI::path($name, 'edit', $this->element),
+    );
+    $render['#links']['delete'] = array(
+      'title' => t('delete'),
+      'href' => RulesPluginUI::path($name, 'delete', $this->element),
+    );
+    return $render;
+  }
+
+  /**
+   * Implements RulesPluginUIInterface.
+   */
+  public function help() {}
+
+
+  /**
+   * Deprecated by the controllers overviewTable() method.
+   */
+  public static function overviewTable($conditions = array(), $options = array()) {
+    return rules_ui()->overviewTable($conditions, $options);
+  }
+
+  /**
+   * Generates a path using the given operation for the element with the given
+   * id of the configuration with the given name.
+   */
+  public static function path($name, $op = NULL, RulesPlugin $element = NULL, $parameter = FALSE) {
+    $element_id = isset($element) ? $element->elementId() : FALSE;
+    if (isset(self::$basePath)) {
+      $base_path = self::$basePath;
+    }
+    // Default to the paths used by 'rules_admin', so modules can easily re-use
+    // its UI.
+    else {
+      $base_path = isset($element) && $element instanceof RulesTriggerableInterface ? 'admin/config/workflow/rules/reaction' : 'admin/config/workflow/rules/components';
+    }
+    return implode('/', array_filter(array($base_path . '/manage', $name, $op, $element_id, $parameter)));
+  }
+
+  /**
+   * Determines the default redirect target for an edited/deleted element. This
+   * is a parent element which is either a rule or the configuration root.
+   */
+  public static function defaultRedirect(RulesPlugin $element) {
+    while (!$element->isRoot()) {
+      if ($element instanceof Rule) {
+        return self::path($element->root()->name, 'edit', $element);
+      }
+      $element = $element->parentElement();
+    }
+    return self::path($element->name);
+  }
+
+  /**
+   * @see RulesUICategory::getOptions()
+   */
+  public static function getOptions($item_type, $items = NULL) {
+    return RulesUICategory::getOptions($item_type, $items = NULL);
+  }
+
+  public static function formDefaults(&$form, &$form_state) {
+    form_load_include($form_state, 'inc', 'rules', 'ui/ui.forms');
+    // Add our own css.
+    $form['#attached']['css'][] = drupal_get_path('module', 'rules') . '/ui/rules.ui.css';
+    // Workaround for problems with jquery css in seven theme and the core
+    // autocomplete.
+    if ($GLOBALS['theme'] == 'seven') {
+      $form['#attached']['css'][] = drupal_get_path('module', 'rules') . '/ui/rules.ui.seven.css';
+    }
+
+    // Specify the wrapper div used by #ajax.
+    $form['#prefix'] = '<div id="rules-form-wrapper">';
+    $form['#suffix'] = '</div>';
+
+    // Preserve the base path in the form state. The after build handler will
+    // set self::$basePath again for cached forms.
+    if (isset(self::$basePath)) {
+      $form_state['_rules_base_path'] = RulesPluginUI::$basePath;
+      $form['#after_build'][] = 'rules_form_after_build_restore_base_path';
+    }
+  }
+
+  public static function getTags() {
+    $result = db_select('rules_tags')
+      ->distinct()
+      ->fields('rules_tags', array('tag'))
+      ->groupBy('tag')
+      ->execute()
+      ->fetchCol('tag');
+    return drupal_map_assoc($result);
+  }
+}
+
+/**
+ * UI for abstract plugins (conditions & actions).
+ */
+class RulesAbstractPluginUI extends RulesPluginUI {
+
+  /**
+   * Overridden to invoke the abstract plugins form alter callback and to add
+   * the negation checkbox for conditions.
+   */
+  public function form(&$form, &$form_state, $options = array()) {
+    parent::form($form, $form_state, $options);
+
+    if ($this->element instanceof RulesCondition) {
+      $form['negate'] = array(
+        '#title' => t('Negate'),
+        '#type' => 'checkbox',
+        '#description' => t('If checked, the condition result is negated such that it returns TRUE if it evaluates to FALSE.'),
+        '#default_value' => $this->element->isNegated(),
+        '#weight' => 5,
+      );
+    }
+    $this->element->call('form_alter', array(&$form, &$form_state, $options));
+  }
+
+  public function form_extract_values($form, &$form_state) {
+    parent::form_extract_values($form, $form_state);
+    $form_values = RulesPluginUI::getFormStateValues($form, $form_state);
+    if ($this->element instanceof RulesCondition && isset($form_values['negate'])) {
+      $this->element->negate($form_values['negate']);
+    }
+  }
+
+  public function form_validate($form, &$form_state) {
+    parent::form_validate($form, $form_state);
+    // Validate the edited element and throw validation errors if it fails.
+    try {
+      $this->element->integrityCheck();
+    }
+    catch (RulesIntegrityException $e) {
+      form_set_error(implode('][', $e->keys), $e->getMessage());
+    }
+  }
+}
+
+/**
+ * UI for Rules Container.
+ */
+class RulesContainerPluginUI extends RulesPluginUI {
+
+  /**
+   * Generates a table for editing the contained elements.
+   */
+  public function form(&$form, &$form_state, $options = array(), $iterator = NULL) {
+    parent::form($form, $form_state, $options);
+    $form['elements'] = array(
+      // Hide during creation or for embedded elements.
+      '#access' => empty($options['init']) && $this->element->isRoot(),
+      '#tree' => TRUE,
+      '#theme' => 'rules_elements',
+      '#empty' => t('None'),
+      '#caption' => t('Elements')
+    );
+    $form['elements']['#attributes']['class'][] = 'rules-container-plugin';
+
+    // Recurse over all element childrens or use the provided iterator.
+    $iterator = isset($iterator) ? $iterator : $this->element->elements();
+    $root_depth = $this->element->depth();
+    foreach ($iterator as $key => $child) {
+      $id = $child->elementId();
+
+      // Do not render rules as container element when displayed in a rule set.
+      $is_container = $child instanceof RulesContainerPlugin && !($child instanceof Rule);
+      $form['elements'][$id] = array(
+        '#depth' => $child->depth() - $root_depth - 1,
+        '#container' => $is_container,
+      );
+      $form['elements'][$id]['label'] = $child->buildContent();
+      $form['elements'][$id]['weight'] = array(
+        '#type' => 'weight',
+        '#default_value' => $child->weight,
+        '#delta' => 50,
+      );
+      $form['elements'][$id]['parent_id'] = array(
+        '#type' => 'hidden',
+        // If another iterator is passed in, the childs parent may not equal
+        // the current element. Thus ask the child for its parent.
+        '#default_value' => $child->parentElement()->elementId(),
+      );
+      $form['elements'][$id]['element_id'] = array(
+        '#type' => 'hidden',
+        '#default_value' => $id,
+      );
+      $form['elements'][$id]['operations'] = $child->operations();
+    }
+
+    // Alter the submit button label.
+    if (!empty($options['button']) && !empty($options['init'])) {
+      $form['submit']['#value'] = t('Continue');
+    }
+    elseif (!empty($options['button']) && $this->element->isRoot()) {
+      $form['submit']['#value'] = t('Save changes');
+    }
+  }
+
+  /**
+   * Applies the values of the form to the given rule configuration.
+   */
+  public function form_extract_values($form, &$form_state) {
+    parent::form_extract_values($form, $form_state);
+    $values = RulesPluginUI::getFormStateValues($form, $form_state);
+    // Now apply the new hierarchy.
+    if (isset($values['elements'])) {
+      foreach ($values['elements'] as $id => $data) {
+        $child = $this->element->elementMap()->lookup($id);
+        $child->weight = $data['weight'];
+        $parent = $this->element->elementMap()->lookup($data['parent_id']);
+        $child->setParent($parent ? $parent : $this->element);
+      }
+      $this->element->sortChildren(TRUE);
+    }
+  }
+
+  public function operations() {
+    $ops = parent::operations();
+    $add_ops = self::addOperations();
+    $ops['#links'] += $add_ops['#links'];
+    return $ops;
+  }
+
+  /**
+   * Gets the Add-* operations for the given element.
+   */
+  public function addOperations() {
+    $name = $this->element->root()->name;
+    $render = array(
+      '#theme' => 'links__rules',
+    );
+    $render['#attributes']['class'][] = 'rules-operations-add';
+    $render['#attributes']['class'][] = 'action-links';
+    foreach (rules_fetch_data('plugin_info') as $plugin => $info) {
+      if (!empty($info['embeddable']) && $this->element instanceof $info['embeddable']) {
+        $render['#links']['add_' . $plugin] = array(
+          'title' => t('Add !name', array('!name' => $plugin)),
+          'href' => RulesPluginUI::path($name, 'add', $this->element, $plugin),
+        );
+      }
+    }
+    return $render;
+  }
+
+
+  public function buildContent() {
+    $content = parent::buildContent();
+    // Don't link the title for embedded container plugins, except for rules.
+    if (!$this->element->isRoot() && !($this->element instanceof Rule)) {
+      $content['label']['#type'] = 'markup';
+      $content['label']['#markup'] = check_plain($content['label']['#title']);
+      unset($content['label']['#title']);
+    }
+    elseif ($this->element->isRoot()) {
+      $content['description']['settings'] = array(
+        '#theme' => 'rules_content_group',
+        '#weight' => -4,
+        'machine_name' => array(
+          '#markup' => t('Machine name') . ': ' . $this->element->name,
+        ),
+        'weight' => array(
+          '#access' => $this->element instanceof RulesTriggerableInterface,
+          '#markup' => t('Weight') . ': ' . $this->element->weight,
+        ),
+      );
+      if (!empty($this->element->tags)) {
+        $content['description']['tags'] = array(
+          '#theme' => 'rules_content_group',
+          '#caption' => t('Tags'),
+          'tags' => array(
+            '#markup' => check_plain(drupal_implode_tags($this->element->tags)),
+          ),
+        );
+      }
+      if ($vars = $this->element->componentVariables()) {
+        $content['description']['variables'] = array(
+          '#caption' => t('Parameter'),
+          '#theme' => 'rules_content_group',
+        );
+        foreach ($vars as $name => $info) {
+          if (!isset($info['parameter']) || $info['parameter']) {
+            $content['description']['variables'][$name] = array(
+              '#theme' => 'rules_variable_view',
+              '#info' => $info,
+              '#name' => $name,
+            );
+          }
+        }
+      }
+    }
+    return $content;
+  }
+}
+
+/**
+ * UI for Rules condition container.
+ */
+class RulesConditionContainerUI extends RulesContainerPluginUI {
+
+  public function form(&$form, &$form_state, $options = array(), $iterator = NULL) {
+    parent::form($form, $form_state, $options, $iterator);
+    // Add the add-* operation links.
+    $form['elements']['#add'] = self::addOperations();
+    $form['elements']['#attributes']['class'][] = 'rules-condition-container';
+    $form['elements']['#caption'] = t('Conditions');
+
+    // By default skip
+    if (!empty($options['init']) && !$this->element->isRoot()) {
+      $config = $this->element->root();
+      $form['init_help'] = array(
+        '#type' => 'container',
+        '#id' => 'rules-plugin-add-help',
+        'content' => array(
+          '#markup' => t('You are about to add a new @plugin to the @config-plugin %label. Use indentation to make conditions a part of this logic group. See <a href="@url">the online documentation</a> for more information on condition sets.',
+            array('@plugin' => $this->element->plugin(),
+                  '@config-plugin' => $config->plugin(),
+                  '%label' => $config->label(),
+                  '@url' => rules_external_help('condition-components'))),
+        ),
+      );
+    }
+    $form['negate'] = array(
+      '#title' => t('Negate'),
+      '#type' => 'checkbox',
+      '#description' => t('If checked, the condition result is negated such that it returns TRUE if it evaluates to FALSE.'),
+      '#default_value' => $this->element->isNegated(),
+      '#weight' => 5,
+    );
+  }
+
+  public function form_extract_values($form, &$form_state) {
+    parent::form_extract_values($form, $form_state);
+    $form_values = RulesPluginUI::getFormStateValues($form, $form_state);
+    if (isset($form_values['negate'])) {
+      $this->element->negate($form_values['negate']);
+    }
+  }
+}
+
+/**
+ * UI for Rules action container.
+ */
+class RulesActionContainerUI extends RulesContainerPluginUI {
+
+  public function form(&$form, &$form_state, $options = array(), $iterator = NULL) {
+    parent::form($form,  $form_state, $options, $iterator);
+    // Add the add-* operation links.
+    $form['elements']['#add'] = self::addOperations();
+    $form['elements']['#attributes']['class'][] = 'rules-action-container';
+    $form['elements']['#caption'] = t('Actions');
+  }
+}
+
+/**
+ * Class holding category related methods.
+ */
+class RulesUICategory {
+
+  /**
+   * Gets info about all available categories, or about a specific category.
+   *
+   * @return array
+   */
+  public static function getInfo($category = NULL) {
+    $data = rules_fetch_data('category_info');
+    if (isset($category)) {
+      return $data[$category];
+    }
+    return $data;
+  }
+
+  /**
+   * Returns a group label, e.g. as usable for opt-groups in a select list.
+   *
+   * @param array $item_info
+   *   The info-array of an item, e.g. an entry of hook_rules_action_info().
+   * @param bool $in_category
+   *   (optional) Whether group labels for grouping inside a category should be
+   *   return. Defaults to FALSE.
+   *
+   * @return string|boolean
+   *   The group label to use, or FALSE if none can be found.
+   */
+  public static function getItemGroup($item_info, $in_category = FALSE) {
+    if (isset($item_info['category']) && !$in_category) {
+      return self::getCategory($item_info, 'label');
+    }
+    else if (!empty($item_info['group'])) {
+      return $item_info['group'];
+    }
+    return FALSE;
+  }
+
+  /**
+   * Gets the category for the given item info array.
+   *
+   * @param array $item_info
+   *   The info-array of an item, e.g. an entry of hook_rules_action_info().
+   * @param string|null $key
+   *   (optional) The key of the category info to return, e.g. 'label'. If none
+   *   is given the whole info array is returned.
+   *
+   * @return array|mixed|false
+   *   Either the whole category info array or the value of the given key. If
+   *   no category can be found, FALSE is returned.
+   */
+  public static function getCategory($item_info, $key = NULL) {
+    if (isset($item_info['category'])) {
+      $info = self::getInfo($item_info['category']);
+      return isset($key) ? $info[$key] : $info;
+    }
+    return FALSE;
+  }
+
+  /**
+   * Returns an array of options to use with a select for the items specified
+   * in the given hook.
+   *
+   * @param $item_type
+   *   The item type to get options for. One of 'data', 'event', 'condition' and
+   *   'action'.
+   * @param $items
+   *   (optional) An array of items to restrict the options to.
+   *
+   * @return
+   *   An array of options.
+   */
+  public static function getOptions($item_type, $items = NULL) {
+    $sorted_data = array();
+    $ungrouped = array();
+    $data = $items ? $items : rules_fetch_data($item_type . '_info');
+    foreach ($data as $name => $info) {
+      // Verfiy the current user has access to use it.
+      if (!user_access('bypass rules access') && !empty($info['access callback']) && !call_user_func($info['access callback'], $item_type, $name)) {
+        continue;
+      }
+      if ($group = RulesUICategory::getItemGroup($info)) {
+        $sorted_data[drupal_ucfirst($group)][$name] = drupal_ucfirst($info['label']);
+      }
+      else {
+        $ungrouped[$name] = drupal_ucfirst($info['label']);
+      }
+    }
+    asort($ungrouped);
+    foreach ($sorted_data as $key => $choices) {
+      asort($choices);
+      $sorted_data[$key] = $choices;
+    }
+
+    // Sort the grouped data by category weights, defaulting to weight 0 for
+    // groups without a respective category.
+    $sorted_groups = array();
+    foreach (array_keys($sorted_data) as $label) {
+      $sorted_groups[$label] = array('weight' => 0, 'label' => $label);
+    }
+    // Add in category weights.
+    foreach (RulesUICategory::getInfo() as $info) {
+      if (isset($sorted_groups[$info['label']])) {
+        $sorted_groups[$info['label']] = $info;
+      }
+    }
+    uasort($sorted_groups, '_rules_ui_sort_categories');
+
+    // Now replace weights with group content.
+    foreach ($sorted_groups as $group => $weight) {
+      $sorted_groups[$group] = $sorted_data[$group];
+    }
+    return $ungrouped + $sorted_groups;
+  }
+}
+
+/**
+ * Helper for sorting categories.
+ */
+function _rules_ui_sort_categories($a, $b) {
+  // @see element_sort()
+  $a_weight = isset($a['weight']) ? $a['weight'] : 0;
+  $b_weight = isset($b['weight']) ? $b['weight'] : 0;
+  if ($a_weight == $b_weight) {
+    // @see element_sort_by_title()
+    $a_title = isset($a['label']) ? $a['label'] : '';
+    $b_title = isset($b['label']) ? $b['label'] : '';
+    return strnatcasecmp($a_title, $b_title);
+  }
+  return ($a_weight < $b_weight) ? -1 : 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/ui.data.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,581 @@
+<?php
+
+/**
+ * @file Contains data type related forms.
+ */
+
+
+/**
+ * Interface for data types providing a direct input form.
+ */
+interface RulesDataDirectInputFormInterface {
+
+  /**
+   * Constructs the direct input form.
+   *
+   * @return Array
+   *  The direct input form.
+   */
+  public static function inputForm($name, $info, $settings, RulesPlugin $element);
+
+  /**
+   * Render the configured value.
+   *
+   * @return Array
+   *   A renderable array.
+   */
+  public static function render($value);
+
+}
+
+/**
+ * Interface for data UI classes providing an options list.
+ */
+interface RulesDataInputOptionsListInterface extends RulesDataDirectInputFormInterface {
+
+  /**
+   * Returns the options list for the data type.
+   *
+   * @param RulesPlugin $element
+   *   The rules element to get the options for.
+   * @param string $name
+   *   The name of the parameter for which to get options.
+   *
+   * For retrieving information about the used data type and parameter, the
+   * helper RulesDataUI::getTypeInfo() may be used as following:
+   * @code
+   *   list($type, $parameter_info) = RulesDataUI::getTypeInfo($element, $name);
+   * @endcode
+   *
+   * @return
+   *   An array of options as used by hook_options_list().
+   */
+  public static function optionsList(RulesPlugin $element, $name);
+}
+
+/**
+ * Default UI related class for data types.
+ */
+class RulesDataUI {
+
+  /**
+   * Specifies the default input mode per data type.
+   */
+  public static function getDefaultMode() {
+    return 'selector';
+  }
+
+  /**
+   * Provides the selection form for a parameter.
+   */
+  public static function selectionForm($name, $info, $settings, RulesPlugin $element) {
+    if (!isset($settings[$name . ':select'])) {
+      $settings[$name . ':select'] = '';
+      $vars = $element->availableVariables();
+      // Default to variables with the same name as the parameter.
+      if (isset($vars[$name])) {
+        $settings[$name . ':select'] = $name;
+      }
+      // If there is only one match, use it by default.
+      elseif (count($matches = RulesData::matchingDataSelector($vars, $info, '', 1, FALSE)) == 1) {
+        $settings[$name . ':select'] = rules_array_key($matches);
+      }
+    }
+    $form[$name . ':select'] = array(
+      '#type' => 'rules_data_selection',
+      '#title' => t('Data selector'),
+      '#default_value' => $settings[$name . ':select'],
+      '#required' => empty($info['optional']),
+      '#autocomplete_path' => RulesPluginUI::path($element->root()->name, 'autocomplete' . '/' . $name),
+      // Make the autocomplete textfield big enough so that it can display
+      // descriptions without word wraps.
+      '#size' => 75,
+      '#description' => t("The data selector helps you drill down into the data available to Rules. <em>To make entity fields appear in the data selector, you may have to use the condition 'entity has field' (or 'content is of type').</em> More useful tips about data selection is available in <a href='@url'>the online documentation</a>.",
+        array('@url' => rules_external_help('data-selection'))),
+    );
+
+    $cache = rules_get_cache();
+    $form['types_help'] = array(
+      '#theme' => 'rules_settings_help',
+      '#heading' => t('Data types'),
+    );
+    if ($info['type'] == '*') {
+      $type_labels[] = t('any');
+    }
+    else {
+      $types = is_array($info['type']) ? $info['type'] : array($info['type']);
+      $type_labels = array();
+      foreach ($types as $type) {
+        $type_labels[] = drupal_ucfirst(isset($cache['data_info'][$type]['label']) ? $cache['data_info'][$type]['label'] : $type);
+      }
+    }
+    $form['types_help']['#text'] = format_plural(count($type_labels), 'Select data of the type %types.', 'Select data of the types %types.', array('%types' => implode(', ', $type_labels)));
+
+    if (!empty($info['translatable'])) {
+      if (empty($info['custom translation language'])) {
+        $text = t('If a multilingual data source (i.e. a translatable field) is given, the argument is translated to the current interface language.');
+      }
+      else {
+        $text = t('If a multilingual data source (i.e. a translatable field) is given, the argument is translated to the configured language.');
+      }
+      $form['translation'] = array(
+        '#theme' => 'rules_settings_help',
+        '#text' => $text,
+        '#heading' => t('Translation'),
+      );
+    }
+    $form['help'] = array(
+      '#theme' => 'rules_data_selector_help',
+      '#variables' => $element->availableVariables(),
+      '#parameter' => $info,
+    );
+
+    // Add data processor.
+    $settings += array($name . ':process' => array());
+    $form[$name . ':process'] = array();
+    RulesDataProcessor::attachForm($form[$name . ':process'], $settings[$name . ':process'], $info, $element->availableVariables());
+    return $form;
+  }
+
+  /**
+   * Renders the value by making use of the label if an options list is available.
+   *
+   * Used for data UI classes implementing the
+   * RulesDataDirectInputFormInterface.
+   *
+   * In case an options list is available, the the usual render() method won't
+   * be invoked, instead the selected entry is rendered via this method.
+   *
+   * @todo for Drupal 8: Refactor to avoid implementations have to care about
+   * option lists when generating the form, but not when rendering values.
+   */
+  public static function renderOptionsLabel($value, $name, $info, RulesPlugin $element) {
+    if (!empty($info['options list'])) {
+      $element->call('loadBasicInclude');
+      $options = entity_property_options_flatten(call_user_func($info['options list'], $element, $name));
+      if (!is_array($value) && isset($options[$value])) {
+        $value = $options[$value];
+      }
+      elseif (is_array($value)) {
+        foreach ($value as $key => $single_value) {
+          if (isset($options[$single_value])) {
+            $value[$key] = $options[$single_value];
+          }
+        }
+        $value = implode(', ', $value);
+      }
+      return array(
+        'content' => array('#markup' => check_plain($value)),
+        '#attributes' => array('class' => array('rules-parameter-options-entry')),
+      );
+    }
+  }
+
+  /**
+   * Returns the data type and parameter information for the given arguments.
+   *
+   * This helper may be used by options list callbacks operation at data-type
+   * level, see RulesDataInputOptionsListInterface.
+   */
+  public static function getTypeInfo(RulesPlugin $element, $name) {
+    $parameters = $element->pluginParameterInfo();
+    return array($parameters[$name]['type'], $parameters[$name]);
+  }
+}
+
+/**
+ * UI for textual data.
+ */
+class RulesDataUIText extends RulesDataUI implements RulesDataDirectInputFormInterface {
+
+  public static function getDefaultMode() {
+    return 'input';
+  }
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    if (!empty($info['options list'])) {
+      // Make sure the .rules.inc of the providing module is included as the
+      // options list callback may reside there.
+      $element->call('loadBasicInclude');
+      $form[$name] = array(
+        '#type' => 'select',
+        '#options' => call_user_func($info['options list'], $element, $name),
+      );
+    }
+    else {
+      $form[$name] = array(
+        '#type' => 'textarea',
+      );
+      RulesDataInputEvaluator::attachForm($form, $settings, $info, $element->availableVariables());
+    }
+    $settings += array($name => isset($info['default value']) ? $info['default value'] : NULL);
+    $form[$name] += array(
+      '#title' => t('Value'),
+      '#default_value' => $settings[$name],
+      '#required' => empty($info['optional']),
+      '#after_build' => array('rules_ui_element_fix_empty_after_build'),
+      '#rows' => 3,
+    );
+    return $form;
+  }
+
+  public static function render($value) {
+    return array(
+      'content' => array('#markup' => check_plain($value)),
+      '#attributes' => array('class' => array('rules-parameter-text')),
+    );
+  }
+}
+
+/**
+ * UI for text tokens.
+ */
+class RulesDataUITextToken extends RulesDataUIText {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+    if ($form[$name]['#type'] == 'textarea') {
+      $form[$name]['#element_validate'][] = 'rules_ui_element_token_validate';
+      $form[$name]['#description'] = t('May only contain lowercase letters, numbers, and underscores and has to start with a letter.');
+      $form[$name]['#rows'] = 1;
+    }
+    return $form;
+  }
+}
+
+/**
+ * UI for formatted text.
+ */
+class RulesDataUITextFormatted extends RulesDataUIText {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+    $settings += array($name => isset($info['default value']) ? $info['default value'] : array('value' => NULL, 'format' => NULL));
+
+    $form[$name]['#type'] = 'text_format';
+    $form[$name]['#base_type'] = 'textarea';
+    $form[$name]['#default_value'] = $settings[$name]['value'];
+    $form[$name]['#format'] = $settings[$name]['format'];
+    return $form;
+  }
+
+  public static function render($value) {
+    return array(
+      'content' => array('#markup' => check_plain($value['value'])),
+      '#attributes' => array('class' => array('rules-parameter-text-formatted')),
+    );
+  }
+}
+
+
+
+/**
+ * UI for decimal data.
+ */
+class RulesDataUIDecimal extends RulesDataUIText {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+    if (empty($info['options list'])) {
+      $form[$name]['#type'] = 'textfield';
+    }
+    $form[$name]['#element_validate'][] = 'rules_ui_element_decimal_validate';
+    $form[$name]['#rows'] = 1;
+    return $form;
+  }
+}
+
+/**
+ * UI for integers.
+ */
+class RulesDataUIInteger extends RulesDataUIText {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+    if (empty($info['options list'])) {
+      $form[$name]['#type'] = 'textfield';
+    }
+    $form[$name]['#element_validate'][] = 'rules_ui_element_integer_validate';
+    return $form;
+  }
+}
+
+/**
+ * UI for boolean data.
+ */
+class RulesDataUIBoolean extends RulesDataUI implements RulesDataDirectInputFormInterface {
+
+  public static function getDefaultMode() {
+    return 'input';
+  }
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $settings += array($name => isset($info['default value']) ? $info['default value'] : NULL);
+    // Note: Due to the checkbox even optional parameter always receive a value.
+    $form[$name] = array(
+      '#type' => 'checkbox',
+      '#title' => check_plain($info['label']),
+      '#default_value' => $settings[$name],
+    );
+    return $form;
+  }
+
+  public static function render($value) {
+    return array(
+      'content' => array('#markup' => !empty($value) ? t('true') : t('false')),
+      '#attributes' => array('class' => array('rules-parameter-boolean')),
+    );
+  }
+}
+
+/**
+ * UI for dates.
+ */
+class RulesDataUIDate extends RulesDataUIText {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $settings += array($name => isset($info['default value']) ? $info['default value'] : (empty($info['optional']) ? gmdate('Y-m-d H:i:s', time()) : NULL));
+
+    // Convert any configured timestamp into a readable format.
+    if (is_numeric($settings[$name])) {
+      $settings[$name] = gmdate('Y-m-d H:i:s', $settings[$name]);
+    }
+    $form = parent::inputForm($name, $info, $settings, $element);
+    $form[$name]['#type'] = 'textfield';
+    $form[$name]['#element_validate'][] = 'rules_ui_element_date_validate';
+    // Note that the date input evaluator takes care for parsing dates using
+    // strtotime() into a timestamp, which is the internal date format.
+    $form[$name]['#description'] = t('The date in GMT. You may enter a fixed time (like %format) or any other values in GMT known by the PHP !strtotime function (like "+1 day"). Relative dates like "+1 day" or "now" relate to the evaluation time.',
+      array('%format' => gmdate('Y-m-d H:i:s', time() + 86400),
+            '!strtotime' => l('strtotime()', 'http://php.net/strtotime')));
+
+    //TODO: Leverage the jquery datepicker+timepicker once a module providing
+    //the timpeicker is available.
+    return $form;
+  }
+
+  public static function render($value) {
+    $value = is_numeric($value) ? format_date($value, 'short') : check_plain($value);
+    return array(
+      'content' => array('#markup' => $value),
+      '#attributes' => array('class' => array('rules-parameter-date')),
+    );
+  }
+}
+
+/**
+ * UI for duration type parameter.
+ */
+class RulesDataUIDuration extends RulesDataUIText {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+    $form[$name]['#type'] = 'rules_duration';
+    $form[$name]['#after_build'][] = 'rules_ui_element_duration_after_build';
+    return $form;
+  }
+
+  public static function render($value) {
+    $value = is_numeric($value) ? format_interval($value) : check_plain($value);
+    return array(
+      'content' => array('#markup' => $value),
+      '#attributes' => array('class' => array('rules-parameter-duration')),
+    );
+  }
+}
+
+/**
+ * UI for the URI type parameter.
+ */
+class RulesDataUIURI extends RulesDataUIText {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+    $form[$name]['#rows'] = 1;
+    $form[$name]['#description'] = t('You may enter relative URLs like %url as well as absolute URLs like %absolute-url.', array('%url' => 'user/login?destination=node', '%absolute-url' => 'http://drupal.org'));
+    return $form;
+  }
+}
+
+/**
+ * UI for lists of textual data.
+ */
+class RulesDataUIListText extends RulesDataUIText {
+
+  public static function getDefaultMode() {
+    return 'input';
+  }
+
+  /**
+   * @todo This does not work for inputting textual values including "\n".
+   */
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $settings += array($name => isset($info['default value']) ? $info['default value'] : NULL);
+    $form = parent::inputForm($name, $info, $settings, $element);
+
+    if ($form[$name]['#type'] == 'textarea') {
+      // Fix up the value to be an array during after build.
+      $form[$name]['#delimiter'] = "\n";
+      $form[$name]['#after_build'][] = 'rules_ui_list_textarea_after_build';
+      $form[$name]['#pre_render'][] = 'rules_ui_list_textarea_pre_render';
+      $form[$name]['#default_value'] = !empty($settings[$name]) ? implode("\n", $settings[$name]) : NULL;
+      $form[$name]['#description'] = t('A list of values, one on each line.');
+    }
+    else {
+      $form[$name]['#multiple'] = TRUE;
+    }
+    return $form;
+  }
+
+  public static function render($value) {
+    return array(
+      'content' => array('#markup' => check_plain(implode(', ', $value))),
+      '#attributes' => array('class' => array('rules-parameter-list')),
+    );
+  }
+}
+
+/**
+ * UI for lists of integers.
+ */
+class RulesDataUIListInteger extends RulesDataUIListText {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $settings += array($name => isset($info['default value']) ? $info['default value'] : NULL);
+    $form = parent::inputForm($name, $info, $settings, $element);
+
+    if ($form[$name]['#type'] == 'textarea') {
+      $form[$name]['#description'] = t('A list of integers, separated by commas. E.g. enter "1, 2, 3".');
+      $form[$name]['#delimiter'] = ',';
+      $form[$name]['#default_value'] = !empty($settings[$name]) ? implode(", ", $settings[$name]) : NULL;
+      $form[$name]['#element_validate'][] = 'rules_ui_element_integer_list_validate';
+      $form[$name]['#rows'] = 1;
+    }
+    return $form;
+  }
+}
+
+/**
+ * UI for lists of tokens.
+ */
+class RulesDataUIListToken extends RulesDataUIListInteger {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+
+    if ($form[$name]['#type'] == 'textarea') {
+      $form[$name]['#description'] = t('A list of text tokens, separated by commas. E.g. enter "one, two, three".');
+      $form[$name]['#element_validate'] = array('rules_ui_element_token_list_validate');
+    }
+    return $form;
+  }
+}
+
+/**
+ * UI for entity-based data types.
+ */
+class RulesDataUIEntity extends RulesDataUIText {
+
+  public static function getDefaultMode() {
+    return 'selector';
+  }
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+    if (empty($info['options list'])) {
+      $form[$name]['#type'] = 'textfield';
+
+      $entity_info = entity_get_info($info['type']);
+      if (empty($entity_info['entity keys']['name'])) {
+        $form[$name]['#element_validate'][] = 'rules_ui_element_integer_validate';
+      }
+      $form[$name]['#title'] = t('@entity identifier', array('@entity' => $entity_info['label']));
+      $entity_label = strtolower($entity_info['label'][0]) . substr($entity_info['label'], 1);
+      $form[$name]['#description'] = t('Specify an identifier of a @entity.', array('@entity' => $entity_label));
+    }
+    return $form;
+  }
+}
+
+/**
+ * UI for exportable entity-based data types.
+ */
+class RulesDataUIEntityExportable extends RulesDataUIEntity {
+
+  public static function getDefaultMode() {
+    return 'input';
+  }
+}
+
+/**
+ * Data UI variant displaying a select list of available bundle entities.
+ *
+ * This is used for "bundle entities" implemented via the 'bundle of' feature
+ * of entity.module.
+ */
+class RulesDataUIBundleEntity extends RulesDataUIEntity implements RulesDataInputOptionsListInterface {
+
+  public static function getDefaultMode() {
+    return 'input';
+  }
+
+  /**
+   * Implements RulesDataInputOptionsListInterface::optionsList().
+   */
+  public static function optionsList(RulesPlugin $element, $name) {
+    list($data_type, $parameter_info) = RulesDataUI::getTypeInfo($element, $name);
+    $bundles = array();
+    $entity_info = entity_get_info();
+    $bundle_of_type = $entity_info[$data_type]['bundle of'];
+    if (isset($entity_info[$bundle_of_type]['bundles'])) {
+      foreach ($entity_info[$bundle_of_type]['bundles'] as $bundle_name => $bundle_info) {
+        $bundles[$bundle_name] = $bundle_info['label'];
+      }
+    }
+    return $bundles;
+  }
+}
+
+/**
+ * UI for taxonomy vocabularies.
+ *
+ * @see RulesTaxonomyVocabularyWrapper
+ */
+class RulesDataUITaxonomyVocabulary extends RulesDataUIEntity implements RulesDataInputOptionsListInterface {
+
+  public static function getDefaultMode() {
+    return 'input';
+  }
+
+  /**
+   * Implements RulesDataInputOptionsListInterface::optionsList().
+   */
+  public static function optionsList(RulesPlugin $element, $name) {
+    $options = array();
+    foreach (taxonomy_vocabulary_get_names() as $machine_name => $vocab) {
+      $options[$machine_name] = $vocab->name;
+    }
+    return $options;
+  }
+}
+
+/**
+ * UI for lists of entity-based data types.
+ */
+class RulesDataUIListEntity extends RulesDataUIListInteger {
+
+  public static function inputForm($name, $info, $settings, RulesPlugin $element) {
+    $form = parent::inputForm($name, $info, $settings, $element);
+    if (empty($info['options list'])) {
+
+      $entity_info = entity_get_info(entity_property_list_extract_type($info['type']));
+      if (!empty($entity_info['entity keys']['name'])) {
+        $form[$name]['#element_validate'] = array('rules_ui_element_token_list_validate');
+      }
+      $form[$name]['#title'] = t('@entity identifiers', array('@entity' => $entity_info['label']));
+      $entity_label = strtolower($entity_info['label'][0]) . substr($entity_info['label'], 1);
+      $form[$name]['#description'] = t('Specify a comma-separated list of identifiers of @entity entities.', array('@entity' => $entity_label));
+    }
+    return $form;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/ui.forms.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,954 @@
+<?php
+
+/**
+ * @file Rules UI forms
+ */
+
+/**
+ * Ajax callback for reloading the whole form.
+ */
+function rules_ui_form_ajax_reload_form($form, $form_state) {
+  return $form;
+}
+
+/**
+ * Defines #ajax properties.
+ */
+function rules_ui_form_default_ajax($effect = 'slide') {
+  return array(
+    'callback' => 'rules_ui_form_ajax_reload_form',
+    'wrapper' => 'rules-form-wrapper',
+    'effect' => $effect,
+    'speed' => 'fast',
+  );
+}
+
+/**
+ * Submit handler for switching the parameter input mode.
+ */
+function rules_ui_parameter_replace_submit($form, &$form_state) {
+  if (isset($form_state['triggering_element'])) {
+    $name = $form_state['triggering_element']['#parameter'];
+    $form_state['parameter_mode'][$name] = $form_state['parameter_mode'][$name] == 'selector' ? 'input' : 'selector';
+  }
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * General form submit handler, that rebuilds the form
+ */
+function rules_form_submit_rebuild($form, &$form_state) {
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Edit a rules configuration.
+ */
+function rules_ui_form_edit_rules_config($form, &$form_state, $rules_config, $base_path) {
+  RulesPluginUI::$basePath = $base_path;
+  $form_state += array('rules_element' => $rules_config);
+  // Add the rule configuration's form.
+  $rules_config->form($form, $form_state, array('show settings' => TRUE, 'button' => TRUE));
+  $form['#validate'] = array('rules_ui_form_rules_config_validate');
+  return $form;
+}
+
+/**
+ * General rules configuration form validation callback. Also populates the
+ * rules configuration with the form values.
+ */
+function rules_ui_form_rules_config_validate($form, &$form_state) {
+  $form_state['rules_element']->form_validate($form, $form_state);
+}
+
+/**
+ * Edit a rules configuration form submit callback.
+ */
+function rules_ui_form_edit_rules_config_submit($form, &$form_state) {
+  $form_state['rules_element']->form_submit($form, $form_state);
+  drupal_set_message(t('Your changes have been saved.'));
+  if (empty($form_state['redirect'])) {
+    $form_state['redirect'] = RulesPluginUI::defaultRedirect($form_state['rules_element']);
+  }
+}
+
+/**
+ * Clone a rules configuration form.
+ */
+function rules_ui_form_clone_rules_config($form, &$form_state, $rules_config, $base_path) {
+  RulesPluginUI::$basePath = $base_path;
+  $rules_config = clone $rules_config;
+  $rules_config->id = NULL;
+  $rules_config->name = '';
+  $rules_config->label .= ' (' . t('cloned') . ')';
+  $rules_config->status = ENTITY_CUSTOM;
+
+  $form['#validate'][] = 'rules_ui_form_rules_config_validate';
+  $form['#submit'][] = 'rules_ui_form_edit_rules_config_submit';
+  $form_state += array('rules_element' => $rules_config, 'op' => 'clone');
+
+  // Add the rule configuration's form.
+  $rules_config->form($form, $form_state, array('show settings' => TRUE, 'button' => TRUE, 'init' => TRUE));
+
+  // Open the settings fieldset so altering the name is easier.
+  $form['settings']['#collapsed'] = FALSE;
+  return $form;
+}
+
+/**
+ * A simple form just showing a textarea with the export.
+ */
+function rules_ui_form_export_rules_config($form, &$form_state, $rules_config, $base_path) {
+  $form['export'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Export'),
+    '#description' => t('For importing copy the content of the text area and paste it into the import page.'),
+    '#rows' => 25,
+    '#default_value' => $rules_config->export(),
+  );
+  return $form;
+}
+
+/**
+ * Configuration form to directly execute a rules configuration.
+ */
+function rules_ui_form_execute_rules_config($form, &$form_state, $rules_config, $base_path) {
+  // Only components can be executed.
+  if (!($rules_config instanceof RulesTriggerableInterface)) {
+    RulesPluginUI::$basePath = $base_path;
+    // Create either the appropriate action or condition element.
+    $element = rules_plugin_factory($rules_config instanceof RulesActionInterface ? 'action' : 'condition', 'component_' . $rules_config->name);
+    $form['exec_help'] = array(
+      '#prefix' => '<p>',
+      '#markup' => t('This form allows you to manually trigger the execution of the @plugin "%label". If this component requires any parameters, input the suiting execution arguments below.', array('@plugin' => $rules_config->plugin(), '%label' => $rules_config->label())),
+      '#suffix' => '</p>',
+    );
+    $element->form($form, $form_state);
+
+    // For conditions hide the option to negate them.
+    if (isset($form['negate'])) {
+      $form['negate']['#access'] = FALSE;
+    }
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Execute'),
+      '#weight' => 20,
+    );
+    // Re-use the validation callback, which will also populate the action with
+    // the configuration settings in the form.
+    $form['#validate'] = array('rules_ui_form_rules_config_validate');
+    return $form;
+  }
+  drupal_not_found();
+  exit;
+}
+
+/**
+ * Submit callback for directly executing a component.
+ */
+function rules_ui_form_execute_rules_config_submit($form, &$form_state) {
+  $element = $form_state['rules_element'];
+  $result = $element->execute();
+  if ($element instanceof RulesActionInterface) {
+    drupal_set_message(t('Component %label has been executed.', array('%label' => $element->label())));
+  }
+  else {
+    drupal_set_message(t('Component %label evaluated to %result.', array('%label' => $element->label(), '%result' => $result ? 'true' : 'false')));
+  }
+}
+
+/**
+ * Gets the confirmation question for valid operations, or else FALSE.
+ */
+function rules_ui_confirm_operations($op, $rules_config) {
+  $vars = array('%plugin' => $rules_config->plugin(), '%label' => $rules_config->label());
+
+  switch ($op) {
+    case 'enable':
+      return array(t('Are you sure you want to enable the %plugin %label?', $vars), '');
+    case 'disable':
+      return array(t('Are you sure you want to disable the %plugin %label?', $vars), '');
+    case 'revert':
+      return array(t('Are you sure you want to revert the %plugin %label?', $vars), t('This action cannot be undone.'));
+    case 'delete':
+      return array(t('Are you sure you want to delete the %plugin %label?', $vars), t('This action cannot be undone.'));
+    default:
+      return FALSE;
+  }
+}
+
+/**
+ * Confirmation form for applying the operation to the config.
+ */
+function rules_ui_form_rules_config_confirm_op($form, &$form_state, $rules_config, $op, $base_path) {
+  if (list($confirm_question, $description) = rules_ui_confirm_operations($op, $rules_config)) {
+    RulesPluginUI::$basePath = $base_path;
+    $form_state += array('rules_config' => $rules_config, 'op' => $op);
+    return confirm_form($form, $confirm_question, $base_path, $description, t('Confirm'), t('Cancel'));
+  }
+  else {
+    drupal_not_found();
+    exit;
+  }
+}
+
+/**
+ * Applies the operation and returns the message to show to the user. Also the
+ * operation is logged to the watchdog. Note that the string is defined two
+ * times so that the translation extractor can find it.
+ */
+function rules_ui_confirm_operation_apply($op, $rules_config) {
+  $vars = array('%plugin' => $rules_config->plugin(), '%label' => $rules_config->label());
+  $edit_link = l(t('edit'), RulesPluginUI::path($rules_config->name));
+
+  switch ($op) {
+    case 'enable':
+      $rules_config->active = TRUE;
+      $rules_config->save();
+      watchdog('rules', 'Enabled %plugin %label.', $vars, WATCHDOG_NOTICE, $edit_link);
+      return t('Enabled %plugin %label.', $vars);
+
+    case 'disable':
+      $rules_config->active = FALSE;
+      $rules_config->save();
+      watchdog('rules', 'Disabled %plugin %label.', $vars, WATCHDOG_NOTICE, $edit_link);
+      return t('Disabled %plugin %label.', $vars);
+
+    case 'revert':
+      $rules_config->delete();
+      watchdog('rules', 'Reverted %plugin %label to the defaults.', $vars, WATCHDOG_NOTICE, $edit_link);
+      return t('Reverted %plugin %label to the defaults.', $vars);
+
+    case 'delete':
+      $rules_config->delete();
+      watchdog('rules', 'Deleted %plugin %label.', $vars);
+      return t('Deleted %plugin %label.', $vars);
+  }
+}
+
+/**
+ * Rule config deletion form submit callback.
+ */
+function rules_ui_form_rules_config_confirm_op_submit($form, &$form_state) {
+  if ($form_state['values']['confirm']) {
+    $msg = rules_ui_confirm_operation_apply($form_state['op'], $form_state['rules_config']);
+    drupal_set_message($msg);
+  }
+}
+
+/**
+ * Add a new element a rules configuration.
+ */
+function rules_ui_add_element($form, &$form_state, $rules_config, $plugin_name, RulesContainerPlugin $parent, $base_path) {
+  $cache = rules_get_cache();
+  if (!isset($cache['plugin_info'][$plugin_name]['class'])) {
+    drupal_not_found();
+    exit;
+  }
+  RulesPluginUI::$basePath = $base_path;
+  $plugin_is_abstract = in_array('RulesAbstractPlugin', class_parents($cache['plugin_info'][$plugin_name]['class']));
+  // In the first step create the element and in the second step show its edit
+  // form.
+  if ($plugin_is_abstract && !isset($form_state['rules_element'])) {
+    RulesPluginUI::formDefaults($form, $form_state);
+    $form_state += array('parent_element' => $parent, 'plugin' => $plugin_name);
+
+    $form['element_name'] = array(
+      '#type' => 'select',
+      '#title' => t('Select the %element to add', array('%element' => $plugin_name)),
+      '#options' => RulesPluginUI::getOptions($plugin_name),
+      '#ajax' => rules_ui_form_default_ajax() + array(
+        'trigger_as' => array('name' => 'continue'),
+      ),
+    );
+    $form['continue'] = array(
+      '#type' => 'submit',
+      '#name' => 'continue',
+      '#value' => t('Continue'),
+      '#ajax' => rules_ui_form_default_ajax(),
+    );
+  }
+  elseif (!$plugin_is_abstract) {
+    // Create the initial, empty element.
+    $element = rules_plugin_factory($plugin_name);
+    // Always add the new element at the bottom, thus set an appropriate weight.
+    $iterator = $parent->getIterator();
+    if ($sibling = end($iterator)) {
+      $element->weight = $sibling->weight + 1;
+    }
+    $element->setParent($parent);
+    $form_state['rules_element'] = $element;
+  }
+
+  if (isset($form_state['rules_element'])) {
+    $form_state['rules_element']->form($form, $form_state, array('button' => TRUE, 'init' => TRUE));
+    $form['#validate'][] = 'rules_ui_edit_element_validate';
+    $form['#submit'][] = 'rules_ui_edit_element_submit';
+  }
+  return $form;
+}
+
+/**
+ * Add element submit callback.
+ * Used for "abstract plugins" to create the initial element object with the
+ * given implemenation name and rebuild the form.
+ */
+function rules_ui_add_element_submit($form, &$form_state) {
+  $element = rules_plugin_factory($form_state['plugin'], $form_state['values']['element_name']);
+
+  // Always add the new element at the bottom, thus set an appropriate weight.
+  $iterator = $form_state['parent_element']->getIterator();
+  if ($sibling = end($iterator)) {
+    $element->weight = $sibling->weight + 1;
+  }
+  // Clear the element settings so they won't be processed on serialization as
+  // there is nothing to be processed yet.
+  $element->settings = array();
+  $element->setParent($form_state['parent_element']);
+
+  $form_state['rules_element'] = $element;
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Delete elements.
+ */
+function rules_ui_delete_element($form, &$form_state, $rules_config, $rules_element, $base_path) {
+  RulesPluginUI::$basePath = $base_path;
+
+  if (empty($form_state['rules_config'])) {
+    // Before modifying the rules config we have to clone it, so any
+    // modifications won't appear in the static cache of the loading controller.
+    $rules_config = clone $rules_config;
+    // Also get the element from the cloned config.
+    $rules_element = $rules_config->elementMap()->lookup($rules_element->elementId());
+
+    $form_state['rules_config'] = $rules_config;
+    $form_state['rules_element'] = $rules_element;
+    $form_state['element_parent'] = $rules_element->parentElement();
+  }
+
+  // Try deleting the element and warn the user if something breaks, but
+  // save the parent for determining the right redirect target on submit.
+  $removed_plugin = $form_state['rules_element']->plugin();
+  $rules_element->delete();
+
+  if (empty($rules_config->dirty) && empty($form_state['input'])) {
+    try {
+      $rules_config->integrityCheck();
+    }
+    catch (RulesIntegrityException $e) {
+      $args = array(
+        '@plugin' => $e->element->plugin(),
+        '%label' => $e->element->label(),
+        '@removed-plugin' => $removed_plugin,
+        '!url' => url(RulesPluginUI::path($form_state['rules_config']->name, 'edit', $e->element)),
+      );
+      drupal_set_message(t('Deleting this @removed-plugin would break your configuration as some of its provided variables are utilized by the @plugin <a href="!url">%label</a>.', $args), 'warning');
+    }
+  }
+
+  $confirm_question = t('Are you sure you want to delete the %element_plugin %element_name?', array('%element_plugin' => $rules_element->plugin(), '%element_name' => $rules_element->label(), '%plugin' => $rules_config->plugin(), '%label' => $rules_config->label()));
+  return confirm_form($form, $confirm_question, RulesPluginUI::path($rules_config->name), t('This action cannot be undone.'), t('Delete'), t('Cancel'));
+}
+
+/**
+ * Rule config deletion form submit callback.
+ */
+function rules_ui_delete_element_submit($form, &$form_state) {
+  $rules_config = $form_state['rules_config'];
+  $rules_config->save();
+  if (empty($form_state['redirect'])) {
+    $form_state['redirect'] = RulesPluginUI::defaultRedirect($form_state['element_parent']);
+  }
+}
+
+
+/**
+ * Configure a rule element.
+ */
+function rules_ui_edit_element($form, &$form_state, $rules_config, $element, $base_path) {
+  RulesPluginUI::$basePath = $base_path;
+  $form_state += array('rules_element' => $element);
+  $form_state['rules_element']->form($form, $form_state, array('button' => TRUE));
+  return $form;
+}
+
+/**
+ * Validate the element configuration.
+ */
+function rules_ui_edit_element_validate($form, &$form_state) {
+  $form_state['rules_element']->form_validate($form, $form_state);
+}
+
+/**
+ * Submit the element configuration.
+ */
+function rules_ui_edit_element_submit($form, &$form_state) {
+  $form_state['rules_element']->form_submit($form, $form_state);
+  drupal_set_message(t('Your changes have been saved.'));
+  if (empty($form_state['redirect'])) {
+    $form_state['redirect'] = RulesPluginUI::defaultRedirect($form_state['rules_element']);
+  }
+}
+
+/**
+ * Form builder for the "add event" page.
+ */
+function rules_ui_add_event_page($form, &$form_state, RulesTriggerableInterface $rules_config, $base_path) {
+  RulesPluginUI::$basePath = $base_path;
+  RulesPluginUI::formDefaults($form, $form_state);
+  $form = rules_ui_add_event($form, $form_state, $rules_config, $base_path);
+  $form['#validate'][] = 'rules_ui_add_event_validate';
+  return $form;
+}
+
+/**
+ * Submit the event configuration.
+ */
+function rules_ui_add_event_page_submit($form, &$form_state) {
+  rules_ui_add_event_apply($form, $form_state);
+  $rules_config = $form_state['rules_config'];
+
+  // Tell the user if this breaks something, but let him proceed.
+  if (empty($rules_config->dirty)) {
+    try {
+      $rules_config->integrityCheck();
+    }
+    catch (RulesIntegrityException $e) {
+      $warning = TRUE;
+      drupal_set_message(t('Added the event, but it does not provide all variables utilized.'), 'warning');
+    }
+  }
+  $rules_config->save();
+  if (!isset($warning)) {
+    $events = rules_fetch_data('event_info');
+    $label = $events[$form_state['values']['event']]['label'];
+    drupal_set_message(t('Added event %event.', array('%event' => $label)));
+  }
+}
+
+/**
+ * Add a new event.
+ */
+function rules_ui_add_event($form, &$form_state, RulesReactionRule $rules_config, $base_path) {
+  $form_state += array('rules_config' => $rules_config);
+  $events = array_diff_key(rules_fetch_data('event_info'), array_flip($rules_config->events()));
+
+  $form['help'] = array(
+    '#markup' => t('Select the event to add. However note that all added events need to provide all variables that should be available to your rule.'),
+  );
+  $form['event'] = array(
+    '#type' => 'select',
+    '#title' => t('React on event'),
+    '#options' => RulesPluginUI::getOptions('event', $events),
+    '#description' => t('Whenever the event occurs, rule evaluation is triggered.'),
+    '#ajax' => rules_ui_form_default_ajax(),
+    '#required' => TRUE,
+  );
+  if (!empty($form_state['values']['event'])) {
+    $handler = rules_get_event_handler($form_state['values']['event']);
+    $form['event_settings'] = $handler->buildForm($form_state);
+  }
+  else {
+    $form['event_settings'] = array();
+  }
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add'),
+  );
+  $form_state['redirect'] = RulesPluginUI::path($rules_config->name);
+  return $form;
+}
+
+/**
+ * Validation callback for adding an event.
+ */
+function rules_ui_add_event_validate($form, $form_state) {
+  $handler = rules_get_event_handler($form_state['values']['event']);
+  $handler->extractFormValues($form['event_settings'], $form_state);
+  try {
+    $handler->validate();
+  }
+  catch (RulesIntegrityException $e) {
+    form_set_error(implode('][', $e->keys), $e->getMessage());
+  }
+}
+
+/**
+ * Submit callback that just adds the selected event.
+ *
+ * @see rules_admin_add_reaction_rule()
+ */
+function rules_ui_add_event_apply($form, &$form_state) {
+  $handler = rules_get_event_handler($form_state['values']['event']);
+  $handler->extractFormValues($form['event_settings'], $form_state);
+  $form_state['rules_config']->event($form_state['values']['event'], $handler->getSettings());
+}
+
+/**
+ * Form to remove a event from a rule.
+ */
+function rules_ui_remove_event($form, &$form_state, $rules_config, $event, $base_path) {
+  RulesPluginUI::$basePath = $base_path;
+  $form_state += array('rules_config' => $rules_config, 'rules_event' => $event);
+  $event_info = rules_get_event_info($event);
+  $form_state['event_label'] = $event_info['label'];
+  $confirm_question = t('Are you sure you want to remove the event?');
+  return confirm_form($form, $confirm_question, RulesPluginUI::path($rules_config->name), t('You are about to remove the event %event.', array('%event' => $form_state['event_label'])), t('Remove'), t('Cancel'));
+}
+
+/**
+ * Submit the event configuration.
+ */
+function rules_ui_remove_event_submit($form, &$form_state) {
+  $rules_config = $form_state['rules_config'];
+  $rules_config->removeEvent($form_state['rules_event']);
+  // Tell the user if this breaks something, but let him proceed.
+  if (empty($rules_config->dirty)) {
+    try {
+      $rules_config->integrityCheck();
+    }
+    catch (RulesIntegrityException $e) {
+      $warning = TRUE;
+      drupal_set_message(t('Removed the event, but it had provided some variables which are now missing.'), 'warning');
+    }
+  }
+  $rules_config->save();
+  if (!isset($warning)) {
+    drupal_set_message(t('Event %event has been removed.', array('%event' => $form_state['event_label'])));
+  }
+  $form_state['redirect'] = RulesPluginUI::path($rules_config->name);
+}
+
+/**
+ * Import form for rule configurations.
+ */
+function rules_ui_import_form($form, &$form_state, $base_path) {
+  RulesPluginUI::$basePath = $base_path;
+  RulesPluginUI::formDefaults($form, $form_state);
+  $form['import'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Import'),
+    '#description' => t('Paste an exported Rules configuration here.'),
+    '#rows' => 20,
+  );
+  $form['overwrite'] = array(
+    '#title' => t('Overwrite'),
+    '#type' => 'checkbox',
+    '#description' => t('If checked, any existing configuration with the same identifier will be replaced by the import.'),
+    '#default_value' => FALSE,
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Import'),
+  );
+  return $form;
+}
+
+/**
+ * Validation callback for the import form.
+ */
+function rules_ui_import_form_validate($form, &$form_state) {
+  if ($rules_config = rules_import($form_state['values']['import'], $error_msg)) {
+    // Store the successfully imported entity in $form_state.
+    $form_state['rules_config'] = $rules_config;
+    if (!$form_state['values']['overwrite']) {
+      // Check for existing entities with the same identifier.
+      if (rules_config_load($rules_config->name)) {
+        $vars = array('@entity' => t('Rules configuration'), '%label' => $rules_config->label());
+        form_set_error('import', t('Import of @entity %label failed, a @entity with the same machine name already exists. Check the overwrite option to replace it.', $vars));
+      }
+    }
+    try {
+      $rules_config->integrityCheck();
+    }
+    catch (RulesIntegrityException $e) {
+      form_set_error('import', t('Integrity check for the imported configuration failed. Error message: %message.', array('%message' => $e->getMessage())));
+    }
+    if (!user_access('bypass rules access') && !$rules_config->access()) {
+      form_set_error('import', t('You have insufficient access permissions for importing this Rules configuration.'));
+    }
+  }
+  else {
+    form_set_error('import', t('Import failed.'));
+    if ($error_msg) {
+      drupal_set_message($error_msg, 'error');
+    }
+  }
+}
+
+/**
+ * Submit callback for the import form.
+ */
+function rules_ui_import_form_submit($form, &$form_state) {
+  $rules_config = $form_state['rules_config'];
+
+  if ($existing_config = rules_config_load($rules_config->name)) {
+    // Copy DB id and remove the new indicator to overwrite the existing record.
+    $rules_config->id = $existing_config->id;
+    unset($rules_config->is_new);
+  }
+  $rules_config->save();
+  $vars = array('@entity' => t('Rules configuration'), '%label' => $rules_config->label());
+  watchdog('rules_config', 'Imported @entity %label.', $vars);
+  drupal_set_message(t('Imported @entity %label.', $vars));
+  $form_state['redirect'] = RulesPluginUI::$basePath;
+}
+
+/**
+ * FAPI process callback for the data selection widget.
+ * This finalises the auto completion callback path by appending the form build
+ * id.
+ */
+function rules_data_selection_process($element, &$form_state, $form) {
+  $element['#autocomplete_path'] .= '/' . $form['#build_id'];
+  $form_state['cache'] = TRUE;
+  return $element;
+}
+
+/**
+ * Autocomplete data selection results.
+ */
+function rules_ui_form_data_selection_auto_completion($parameter, $form_build_id, $string = '') {
+  // Get the form and its state from the cache to get the currently edited
+  // or created element.
+  $form_state = form_state_defaults();
+  $form = form_get_cache($form_build_id, $form_state);
+  if (!isset($form_state['rules_element'])) {
+    return;
+  }
+  $element = $form_state['rules_element'];
+
+  $params = $element->pluginParameterInfo();
+  $matches = array();
+  if (isset($params[$parameter])) {
+    $parts = explode(':', $string);
+    // Remove the last part as it might be unfinished.
+    $last_part = array_pop($parts);
+    $selector = implode(':', $parts);
+
+    // Start with the partly given selector or from scratch.
+    $result = array();
+    if ($selector && $wrapper = $element->applyDataSelector($selector)) {
+      $result = RulesData::matchingDataSelector($wrapper, $params[$parameter], $selector . ':', 0);
+    }
+    elseif (!$selector) {
+      $result = RulesData::matchingDataSelector($element->availableVariables(), $params[$parameter], '', 0);
+    }
+
+    foreach ($result as $selector => $info) {
+      // If we have an uncomplete last part, take it into account now.
+      $attributes = array();
+      if (!$last_part || strpos($selector, $string) === 0) {
+        $attributes['class'][] = 'rules-dsac-item';
+        $attributes['title'] = isset($info['description']) ? strip_tags($info['description']) : '';
+        if ($selector[strlen($selector) - 1] == ':') {
+          $attributes['class'][] = 'rules-dsac-group';
+          $text = check_plain($selector) . '... (' . check_plain($info['label']) . ')';
+        }
+        else {
+          $text = check_plain($selector) . ' (' . check_plain($info['label']) . ')';
+        }
+        $matches[$selector] = "<div" . drupal_attributes($attributes) . ">$text</div>";
+      }
+    }
+  }
+  drupal_json_output($matches);
+}
+
+
+/**
+ * FAPI validation of an integer element. Copy of the private function
+ * _element_validate_integer().
+ */
+function rules_ui_element_integer_validate($element, &$form_state) {;
+  $value = $element['#value'];
+  if (isset($value) && $value !== '' && (!is_numeric($value) || intval($value) != $value)) {
+    form_error($element, t('%name must be an integer value.', array('%name' => isset($element['#title']) ? $element['#title'] : t('Element'))));
+  }
+}
+
+/**
+ * FAPI validation of a decimal element. Improved version of the private
+ * function _element_validate_number().
+ */
+function rules_ui_element_decimal_validate($element, &$form_state) {
+  // Substitute the decimal separator ",".
+  $value = strtr($element['#value'], ',', '.');
+  if ($value != '' && !is_numeric($value)) {
+    form_error($element, t('%name must be a number.', array('%name' => $element['#title'])));
+  }
+  elseif ($value != $element['#value']) {
+    form_set_value($element, $value, $form_state);
+  }
+}
+
+/**
+ * FAPI validation of a date element. Makes sure the specified date format is
+ * correct and converts date values specifiy a fixed (= non relative) date to
+ * a timestamp. Relative dates are handled by the date input evaluator.
+ */
+function rules_ui_element_date_validate($element, &$form_state) {
+  $value = $element['#value'];
+  if ($value == '' || (is_numeric($value) && intval($value) == $value)) {
+    // The value is a timestamp.
+    return;
+  }
+  elseif (is_string($value) && RulesDateInputEvaluator::gmstrtotime($value) === FALSE) {
+    form_error($element, t('Wrong date format. Specify the date in the format %format.', array('%format' => gmdate('Y-m-d H:i:s', time() + 86400))));
+  }
+  elseif (is_string($value) && RulesDateInputEvaluator::isFixedDateString($value)) {
+    // As the date string specifies a fixed format, we can convert it now.
+    $value = RulesDateInputEvaluator::gmstrtotime($value);
+    form_set_value($element, $value, $form_state);
+  }
+}
+
+/**
+ * FAPI process callback for the duration element type.
+ */
+function rules_ui_element_duration_process($element, &$form_state) {
+  $element['value'] = array(
+    '#type' => 'textfield',
+    '#size' => 8,
+    '#element_validate' => array('rules_ui_element_integer_validate'),
+    '#default_value' => $element['#default_value'],
+    '#required' => !empty($element['#required']),
+  );
+  $element['multiplier'] = array(
+    '#type' => 'select',
+    '#options' => rules_ui_element_duration_multipliers(),
+    '#default_value' => 1,
+  );
+
+  // Put the child elements in a container-inline div.
+  $element['value']['#prefix'] = '<div class="rules-duration container-inline">';
+  $element['multiplier']['#suffix'] = '</div>';
+
+  // Set an appropriate multiplier.
+  if (!empty($element['value']['#default_value'])) {
+    foreach (array_keys(rules_ui_element_duration_multipliers()) as $m) {
+      if ($element['value']['#default_value'] % $m == 0) {
+        $element['multiplier']['#default_value'] = $m;
+      }
+    }
+    // Divide value by the multiplier, so the display is correct.
+    $element['value']['#default_value'] /= $element['multiplier']['#default_value'];
+  }
+  return $element;
+}
+
+/**
+ * Defines possible duration multiplier.
+ */
+function rules_ui_element_duration_multipliers() {
+  return array(
+    1 => t('seconds'),
+    60 => t('minutes'),
+    3600 => t('hours'),
+    // Just use approximate numbers for days (might last 23h on DST change),
+    // months and years.
+    86400 => t('days'),
+    86400 * 30 => t('months'),
+    86400 * 30 * 12 => t('years'),
+  );
+}
+
+/**
+ * Helper function to determine the value for a rules duration form
+ * element.
+ */
+function rules_ui_element_duration_value($element, $input = FALSE) {
+  // This runs before child elements are processed, so we cannot calculate the
+  // value here. But we have to make sure the value is an array, so the form
+  // API is able to process the children to set their values in the array. Thus
+  // once the form API has finished processing the element, the value is an
+  // array containing the child element values. Then finally the after build
+  // callback converts it back to the numeric value and sets that.
+  return array();
+}
+
+/**
+ * FAPI after build callback for the duration parameter type form.
+ * Fixes up the form value by applying the multiplier.
+ */
+function rules_ui_element_duration_after_build($element, &$form_state) {
+  if ($element['value']['#value'] !== '') {
+    $element['#value'] = $element['value']['#value'] * $element['multiplier']['#value'];
+    form_set_value($element, $element['#value'], $form_state);
+  }
+  else {
+    $element['#value'] = NULL;
+    form_set_value($element, NULL, $form_state);
+  }
+  return $element;
+}
+
+/**
+ * FAPI after build callback to ensure empty form elements result in no value.
+ */
+function rules_ui_element_fix_empty_after_build($element, &$form_state) {
+  if (isset($element['#value']) && $element['#value'] === '') {
+    $element['#value'] = NULL;
+    form_set_value($element, NULL, $form_state);
+  }
+  // Work-a-round for the text_format element.
+  elseif ($element['#type'] == 'text_format' && !isset($element['value']['#value'])) {
+    form_set_value($element, NULL, $form_state);
+  }
+  return $element;
+}
+
+
+/**
+ * FAPI after build callback for specifying a list of values.
+ *
+ * Turns the textual value in an array by splitting the text in chunks using the
+ * delimiter set at $element['#delimiter'].
+ */
+function rules_ui_list_textarea_after_build($element, &$form_state) {
+  $element['#value'] = $element['#value'] ? explode($element['#delimiter'], $element['#value']) : array();
+  $element['#value'] = array_map('trim', $element['#value']);
+  form_set_value($element, $element['#value'], $form_state);
+  return $element;
+}
+
+/**
+ * FAPI pre render callback. Turns the value back to a string for rendering.
+ *
+ * @see rules_ui_list_textarea_after_build()
+ */
+function rules_ui_list_textarea_pre_render($element) {
+  $element['#value'] = implode($element['#delimiter'], $element['#value']);
+  return $element;
+}
+
+/**
+ * FAPI callback to validate a list of integers.
+ */
+function rules_ui_element_integer_list_validate($element, &$form_state) {
+  foreach ($element['#value'] as $value) {
+    if ($value !== '' && (!is_numeric($value) || intval($value) != $value)) {
+      form_error($element, t('Each value must be an integer.'));
+    }
+  }
+}
+
+/**
+ * FAPI callback to validate a token.
+ */
+function rules_ui_element_token_validate($element) {
+  $value = $element['#value'];
+  if (isset($value) && $value !== '' && !entity_property_verify_data_type($value, 'token')) {
+    form_error($element, t('%name may only contain lowercase letters, numbers, and underscores and has to start with a letter.', array('%name' => isset($element['#title']) ? $element['#title'] : t('Element'))));
+  }
+}
+
+/**
+ * FAPI callback to validate a list of tokens.
+ */
+function rules_ui_element_token_list_validate($element, &$form_state) {
+  foreach ($element['#value'] as $value) {
+    if ($value !== '' && !entity_property_verify_data_type($value, 'token')) {
+      form_error($element, t('Each value may only contain lowercase letters, numbers, and underscores and has to start with a letter.'));
+    }
+  }
+}
+
+/**
+ * FAPI callback to validate a machine readable name.
+ */
+function rules_ui_element_machine_name_validate($element, &$form_state) {
+  if ($element['#value'] && !preg_match('!^[a-z0-9_]+$!', $element['#value'])) {
+    form_error($element, t('Machine-readable names must contain only lowercase letters, numbers, and underscores.'));
+  }
+}
+
+/**
+ * FAPI callback to validate the form for editing variable info.
+ * @see RulesPluginUI::getVariableForm()
+ */
+function rules_ui_element_variable_form_validate($elements, &$form_state) {
+  $names = array();
+  foreach (element_children($elements['items']) as $item_key) {
+    $element = &$elements['items'][$item_key];
+    if ($element['name']['#value'] || $element['type']['#value'] || $element['label']['#value']) {
+      foreach (array('name' => t('Machine name'), 'label' => t('Label'), 'type' => t('Data type')) as $key => $title) {
+        if (!$element[$key]['#value']) {
+          form_error($element[$key], t('!name field is required.', array('!name' => $title)));
+        }
+      }
+      if (isset($names[$element['name']['#value']])) {
+        form_error($element['name'], t('The machine-readable name %name is already taken.', array('%name' => $element['name']['#value'])));
+      }
+      $names[$element['name']['#value']] = TRUE;
+    }
+  }
+}
+
+/**
+ * Helper to sort elements by their 'weight' key.
+ */
+function rules_element_sort_helper($a, $b) {
+  $a += array('weight' => 0);
+  $b += array('weight' => 0);
+  if ($a['weight'] == $b['weight']) {
+    return 0;
+  }
+  return ($a['weight'] < $b['weight']) ? -1 : 1;
+}
+
+/**
+ * Form after build handler to set the static base path.
+ *
+ * @see RulesPluginUI::formDefaults()
+ */
+function rules_form_after_build_restore_base_path($form, &$form_state) {
+  if (isset($form_state['_rules_base_path'])) {
+    RulesPluginUI::$basePath = $form_state['_rules_base_path'];
+  }
+  return $form;
+}
+
+/**
+ * AJAX page callback to load tag suggestions.
+ *
+ * Largely copied from taxonomy_autocomplete().
+ */
+function rules_autocomplete_tags($tags_typed = '') {
+  // The user enters a comma-separated list of tags. We only autocomplete the
+  // last tag.
+  $tags_typed = drupal_explode_tags($tags_typed);
+  $tag_last = drupal_strtolower(array_pop($tags_typed));
+
+  $tag_matches = array();
+  if ($tag_last != '') {
+    $query = db_select('rules_tags', 'rt');
+    // Do not select already entered terms.
+    if (!empty($tags_typed)) {
+      $query->condition('rt.tag', $tags_typed, 'NOT IN');
+    }
+    // Select rows that match by tag name.
+    $tags_return = $query
+      ->distinct()
+      ->fields('rt', array('tag'))
+      ->condition('rt.tag', '%' . db_like($tag_last) . '%', 'LIKE')
+      ->groupBy('rt.tag')
+      ->range(0, 10)
+      ->execute()
+      ->fetchCol('rt.tag');
+
+    $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
+
+    foreach ($tags_return as $name) {
+      $n = $name;
+      // Tag names containing commas or quotes must be wrapped in quotes.
+      if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
+        $n = '"' . str_replace('"', '""', $name) . '"';
+      }
+      $tag_matches[$prefix . $n] = check_plain($name);
+    }
+  }
+  drupal_json_output($tag_matches);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/ui.plugins.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,254 @@
+<?php
+
+/**
+ * @file Contains UI for diverse plugins provided by Rules.
+ */
+
+/**
+ * Rule specific UI.
+ */
+class RulesRuleUI extends RulesActionContainerUI {
+
+  protected $rule, $conditions;
+
+  public function __construct(FacesExtendable $object) {
+    parent::__construct($object);
+    $this->rule = $object;
+    $this->conditions = $this->rule->conditionContainer();
+  }
+
+  public function form(&$form, &$form_state, $options = array()) {
+    $form_state['rules_element'] = $this->rule;
+    $label = $this->element->label();
+    // Automatically add a counter to unlabelled rules.
+    if ($label == t('unlabeled') && !$this->element->isRoot() && !empty($options['init'])) {
+      $parent = $this->element->parentElement();
+      $label .= ' ' . count($parent->getIterator());
+    }
+    // Components have already a label. If used inside a rule-set add a label
+    // though. It's called 'Name' in the UI though.
+    if (!$this->element->isRoot()) {
+      $form['label'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Name'),
+        '#default_value' => empty($options['init']) ? $label : '',
+        '#required' => TRUE,
+        '#weight' => 5,
+        '#description' => t('A human-readable name shortly describing the rule.'),
+      );
+    }
+
+    $form += array('conditions' => array('#weight' => -5, '#tree' => TRUE));
+    $this->conditions->form($form['conditions'], $form_state);
+    unset($form['conditions']['negate']);
+
+    // Add actions form.
+    $iterator = new RecursiveIteratorIterator($this->rule->actions(), RecursiveIteratorIterator::SELF_FIRST);
+    parent::form($form, $form_state, $options, $iterator);
+    // Hide nested elements during creation.
+    $form['elements']['#access'] = empty($options['init']);
+    $form['conditions']['elements']['#access'] = empty($options['init']);
+
+    $form_state['redirect'] = RulesPluginUI::path($this->element->root()->name, 'edit', $this->element);
+    if (!empty($options['button'])) {
+      $form['submit']['#value'] = t('Save changes');
+    }
+  }
+
+  /**
+   * Applies the values of the form to the rule configuration.
+   */
+  function form_extract_values($form, &$form_state) {
+    $form_values = RulesPluginUI::getFormStateValues($form, $form_state);
+    // Run condition and action container value extraction.
+    if (isset($form['conditions'])) {
+      $this->conditions->extender('RulesConditionContainerUI')->form_extract_values($form['conditions'], $form_state);
+    }
+    if (!empty($form_values['label'])) {
+      $this->element->label = $form_values['label'];
+    }
+    parent::form_extract_values($form, $form_state);
+  }
+
+
+  public function operations() {
+    // When rules are listed only show the edit and delete operations.
+    $ops = parent::operations();
+    $ops['#links'] = array_intersect_key($ops['#links'], array_flip(array('edit', 'delete')));
+    return $ops;
+  }
+}
+
+/**
+ * Reaction rule specific UI.
+ */
+class RulesReactionRuleUI extends RulesRuleUI {
+
+  public function form(&$form, &$form_state, $options = array()) {
+    $form['events'] = array(
+      '#type' => 'container',
+      '#weight' => -10,
+      '#access' => empty($options['init']),
+    );
+
+    $form['events']['table'] = array(
+      '#theme' => 'table',
+      '#caption' => 'Events',
+      '#header' => array('Event', 'Operations'),
+      '#empty' => t('None'),
+    );
+    $form['events']['table']['#attributes']['class'][] = 'rules-elements-table';
+    foreach ($this->rule->events() as $event_name) {
+      $event_handler = rules_get_event_handler($event_name, $this->rule->getEventSettings($event_name));
+
+      $event_operations = array(
+        '#theme' => 'links__rules',
+        '#attributes' => array(
+          'class' => array(
+            'rules-operations',
+            'action-links',
+            'rules_rule_event',
+          ),
+        ),
+        '#links' => array(
+          'delete_event' => array(
+            'title' => t('delete'),
+            'href' => RulesPluginUI::path($this->rule->name, 'delete/event/' . $event_name),
+            'query' => drupal_get_destination(),
+          ),
+        ),
+      );
+
+      $form['events']['table']['#rows'][$event_name] = array(
+        'data' => array(
+          $event_handler->summary(),
+          array('data' => $event_operations),
+        ),
+      );
+    }
+
+    // Add the "add event" row.
+    $cell['colspan'] = 3;
+    $cell['data']['#theme'] = 'links__rules';
+    $cell['data']['#attributes']['class'][] = 'rules-operations-add';
+    $cell['data']['#attributes']['class'][] = 'action-links';
+    $cell['data']['#links']['add_event'] = array(
+      'title' => t('Add event'),
+      'href' => RulesPluginUI::path($this->rule->name, 'add/event'),
+      'query' => drupal_get_destination(),
+    );
+    $form['events']['table']['#rows'][] = array('data' => array($cell), 'class' => array('rules-elements-add'));
+
+    parent::form($form, $form_state, $options);
+    unset($form['label']);
+  }
+
+  /**
+   * Adds the configuration settings form (label, tags, description, ..).
+   */
+  public function settingsForm(&$form, &$form_state) {
+    parent::settingsForm($form, $form_state);
+    $form['settings']['active'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Active'),
+      '#default_value' => !isset($this->rule->active) || $this->rule->active,
+    );
+    $form['settings']['weight'] = array(
+      '#type' => 'weight',
+      '#title' => t('Weight'),
+      '#default_value' => $this->element->weight,
+      '#weight' => 5,
+      '#delta' => 10,
+      '#description' => t('Order rules that react on the same event. Rules with a higher weight are evaluated after rules with less weight.'),
+    );
+    unset($form['settings']['component_provides']);
+  }
+
+  public function settingsFormExtractValues($form, &$form_state) {
+    $form_values = RulesPluginUI::getFormStateValues($form['settings'], $form_state);
+    parent::settingsFormExtractValues($form, $form_state);
+    $this->rule->active = $form_values['active'];
+    $this->rule->weight = $form_values['weight'];
+  }
+}
+
+/**
+ * Rule set specific UI.
+ */
+class RulesRuleSetUI extends RulesActionContainerUI {
+
+  public function form(&$form, &$form_state, $options = array(), $iterator = NULL) {
+    // Pass an iterator just iterating over the rules, thus no further child
+    // elements will be displayed.
+    parent::form($form, $form_state, $options, $this->element->getIterator());
+    // Only show the add rule link.
+    $form['elements']['#add']['#links'] = array_intersect_key($form['elements']['#add']['#links'], array('add_rule' => 1));
+    $form['elements']['#attributes']['class'][] = 'rules-rule-set';
+    $form['elements']['#caption'] = t('Rules');
+  }
+}
+
+/**
+ * UI for Rules loops.
+ */
+class RulesLoopUI extends RulesActionContainerUI {
+
+  public function form(&$form, &$form_state, $options = array()) {
+    parent::form($form, $form_state, $options);
+    $settings = $this->element->settings;
+
+    $form['item'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Current list item'),
+      '#description' => t('The variable used for holding each list item in the loop. This variable will be available inside the loop only.'),
+      '#tree' => TRUE,
+    );
+    $form['item']['label'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Variable label'),
+      '#default_value' => $settings['item:label'],
+      '#required' => TRUE,
+    );
+    $form['item']['var'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Variable name'),
+      '#default_value' => $settings['item:var'],
+      '#description' => t('The variable name must contain only lowercase letters, numbers, and underscores and must be unique in the current scope.'),
+      '#element_validate' => array('rules_ui_element_machine_name_validate'),
+      '#required' => TRUE,
+    );
+  }
+
+  function form_extract_values($form, &$form_state) {
+    parent::form_extract_values($form, $form_state);
+    $form_values = RulesPluginUI::getFormStateValues($form, $form_state);
+
+    $this->element->settings['item:var'] = $form_values['item']['var'];
+    $this->element->settings['item:label'] = $form_values['item']['label'];
+  }
+
+  public function form_validate($form, &$form_state) {
+    parent::form_validate($form, $form_state);
+
+    $vars = $this->element->availableVariables();
+    $name = $this->element->settings['item:var'];
+    if (isset($vars[$name])) {
+      form_error($form['item']['var'], t('The variable name %name is already taken.', array('%name' => $name)));
+    }
+  }
+
+  public function buildContent() {
+    $content = parent::buildContent();
+
+    $content['description']['item'] = array(
+      '#caption' => t('List item'),
+      '#theme' => 'rules_content_group',
+    );
+    $content['description']['item']['var'] = array(
+      '#theme' => 'rules_variable_view',
+      '#info' => $this->element->listItemInfo(),
+      '#name' => $this->element->settings['item:var'],
+    );
+    return $content;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/rules/ui/ui.theme.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,287 @@
+<?php
+
+/**
+ * @file Rules theme functions
+ */
+
+
+/**
+ * Themes a tree of rule elements in a draggable table.
+ *
+ * @ingroup themeable
+ */
+function theme_rules_elements($variables) {
+  $form = $variables['element'];
+  $form['#theme'] = 'table';
+  $form['#header'] = array(t('Elements'), t('Weight'), t('Operations'));
+  $form['#attributes']['id'] = 'rules-' . drupal_html_id($form['#caption']) . '-id';
+
+  foreach (element_children($form) as $element_id) {
+    $element = &$form[$element_id];
+
+    // Add special classes to be used for tabledrag.js.
+    $element['parent_id']['#attributes']['class'] = array('rules-parent-id');
+    $element['element_id']['#attributes']['class'] = array('rules-element-id');
+    $element['weight']['#attributes']['class'] = array('rules-element-weight');
+
+    $row = array();
+    $row[] = theme('indentation', array('size' => $element['#depth'])) . drupal_render($element['label']);
+
+    $row[] = drupal_render($element['weight']) . drupal_render($element['parent_id']) . drupal_render($element['element_id']);
+    $row[] = array('class' => 'rules-operations', 'data' => $element['operations']);
+
+    $row = array('data' => $row) + $element['#attributes'];
+    $row['class'][] = 'draggable';
+    if (!$element['#container']) {
+      $row['class'][] = 'tabledrag-leaf';
+    }
+    $form['#rows'][] = $row;
+  }
+  if (!empty($form['#rows'])) {
+    drupal_add_tabledrag($form['#attributes']['id'], 'match', 'parent', 'rules-parent-id', 'rules-parent-id', 'rules-element-id', TRUE, 10);
+    drupal_add_tabledrag($form['#attributes']['id'], 'order', 'sibling', 'rules-element-weight');
+  }
+  else {
+    $form['#rows'][] = array(array('data' => t('None'), 'colspan' => 3));
+  }
+  if (!empty($form['#add'])) {
+    $row = array();
+    $row[] = array('data' => $form['#add'], 'colspan' => 3);
+    $form['#rows'][] = array('data' => $row, 'class' => array('rules-elements-add'));
+  }
+
+  // Add a wrapping div.
+  return '<div class="rules-elements-table">' . drupal_render($form) . '</div>';
+}
+
+/**
+ * Themes the rules form for editing the used variables.
+ *
+ * @see RulesPluginUI::getVariableForm()
+ * @ingroup themeable
+ */
+function theme_rules_ui_variable_form($variables) {
+  $elements = $variables['element'];
+
+  $table['#theme'] = 'table';
+  $table['#header'] = array(t('Data type'), t('Label'), t('Machine name'), t('Usage'), array('data' => t('Weight'), 'class' => array('tabledrag-hide')));
+  $table['#attributes']['id'] = 'rules-' . drupal_html_id($elements['#title']) . '-id';
+
+  foreach (element_children($elements['items']) as $key) {
+    $element = &$elements['items'][$key];
+    // Add special classes to be used for tabledrag.js.
+    $element['weight']['#attributes']['class'] = array('rules-element-weight');
+
+    $row = array();
+    $row[] = array('data' => $element['type']);
+    $row[] = array('data' => $element['label']);
+    $row[] = array('data' => $element['name']);
+    $row[] = array('data' => $element['usage']);
+    $row[] = array('data' => $element['weight']);
+    $row = array('data' => $row) + $element['#attributes'];
+    $row['class'][] = 'draggable';
+    $table['#rows'][] = $row;
+  }
+  $elements['items']['#printed'] = TRUE;
+  if (!empty($table['#rows'])) {
+    drupal_add_tabledrag($table['#attributes']['id'], 'order', 'sibling', 'rules-element-weight');
+  }
+
+  // Theme it like a form item, but with the description above the content.
+  $attributes['class'][] = 'form-item';
+  $attributes['class'][] = 'rules-variables-form';
+
+  $output = '<div' . drupal_attributes($attributes) . '>' . "\n";
+  $output .= theme('form_element_label', $variables);
+  if (!empty($elements['#description'])) {
+    $output .= ' <div class="description">' . $elements['#description'] . "</div>\n";
+  }
+  $output .= ' ' . drupal_render($table) . "\n";
+  // Add in any further children elements.
+  foreach (element_children($elements, TRUE) as $key) {
+    $output .= drupal_render($elements[$key]);
+  }
+  $output .= "</div>\n";
+  return $output;
+}
+
+/**
+ * Themes a view of multiple configuration items.
+ * @ingroup themeable
+ */
+function theme_rules_content_group($variables) {
+  $element = $variables['element'];
+  $output = array();
+  foreach (element_children($element) as $key) {
+    $output[] = drupal_render($element[$key]);
+  }
+  $output = array_filter($output);
+  $heading = !empty($element['#caption']) ? "<span class='rules-content-heading'>" . $element['#caption'] . ': </span>' : '';
+  if (!empty($output)) {
+    $element['#attributes']['class'][] = 'rules-element-content-group';
+    return '<div' . drupal_attributes($element['#attributes']) . '>' . $heading . implode(', ', $output) . '</div>';
+  }
+}
+
+/**
+ * Themes the view of a single parameter configuration.
+ * @ingroup themeable
+ */
+function theme_rules_parameter_configuration($variables) {
+  $element = $variables['element'];
+  $content = drupal_render_children($element);
+  // Add the full content to the span's title, but don't use drupal_attributes
+  // for that as this would invoke check_plain() again.
+  $title = strip_tags($content);
+  $element['#attributes']['class'][] = 'rules-parameter-configuration';
+  $attributes = drupal_attributes($element['#attributes']) . " title='$title'";
+
+  $label_attributes['class'][] = 'rules-parameter-label';
+  if (!empty($element['#info']['description'])) {
+    $label_attributes['title'] = $element['#info']['description'];
+  }
+  $label_attributes = drupal_attributes($label_attributes);
+
+  $output = "<span $label_attributes>" . check_plain($element['#info']['label']) . ': </span>';
+  $output .= "<span $attributes>" . truncate_utf8($content, 30, TRUE, TRUE) . "</span>";
+  return $output;
+}
+
+/**
+ * Themes info about variables.
+ * @ingroup themeable
+ */
+function theme_rules_variable_view($variables) {
+  $element = $variables['element'];
+
+  $label_attributes['class'][] = 'rules-variable-label';
+  $label_attributes['title'] = '';
+  if (!empty($element['#info']['description'])) {
+    $label_attributes['title'] = $element['#info']['description'] . ' ';
+  }
+  $label_attributes['title'] .= t('Data type: !type', array('!type' => $element['#info']['type']));
+  $label_attributes = drupal_attributes($label_attributes);
+
+  $output = check_plain($element['#info']['label']);
+  $output .= ' (' . check_plain($element['#name']) . ')';
+  return "<span $label_attributes>" . $output . '</span>';
+}
+
+/**
+ * Themes help for using the data selector.
+ * @ingroup themeable
+ */
+function theme_rules_data_selector_help($variables) {
+  $variables_info = $variables['variables'];
+  $param_info = $variables['parameter'];
+
+  $render = array(
+    '#type' => 'fieldset',
+    '#title' => t('Data selectors'),
+    '#pre_render' => array(),
+    '#attributes' => array(),
+  );
+  // Make it manually collapsible as we cannot use #collapsible without the
+  // FAPI element processor.
+  $render['#attached']['js'][] = 'misc/collapse.js';
+  $render['#attributes']['class'][] = 'collapsible';
+  $render['#attributes']['class'][] = 'collapsed';
+
+  $render['table'] = array(
+    '#theme' => 'table',
+    '#header' => array(t('Selector'), t('Label'), t('Description')),
+  );
+  foreach (RulesData::matchingDataSelector($variables_info, $param_info) as $selector => $info) {
+    $info += array('label' => '', 'description' => '');
+    $render['table']['#rows'][] = array(check_plain($selector), check_plain(drupal_ucfirst($info['label'])), check_plain($info['description']));
+  }
+  return drupal_render($render);
+}
+
+/**
+ * Themes the rules log debug output.
+ * @ingroup themeable
+ */
+function theme_rules_log($variables) {
+  $element = $variables['element'];
+  drupal_add_css(drupal_get_path('module', 'rules') . '/ui/rules.ui.css');
+  // Add jquery ui core css and functions, which are needed for the icons.
+  drupal_add_library('system', 'ui');
+  drupal_add_js(drupal_get_path('module', 'rules') . '/ui/rules.debug.js');
+
+  $output = '<div class="rules-debug-log">';
+
+  $output .= '<h3 class="rules-debug-log-head">';
+  $output .= '<span class="rules-debug-open-main rules-debug-collapsible-link">';
+  $output .= '<span unselectable="on" class="ui-icon ui-icon-triangle-1-e rules-debug-icon-open">&nbsp;</span>';
+  $output .= t('Rules evaluation log');
+  $output .= '</span>';
+  $output .= '</span>';
+  $output .= '<span class="rules-debug-open-all rules-debug-collapsible-link">-' . t('Open all') . '-<span>';
+  $output .= '</h3>';
+
+  $output .= '<div>';
+  $output .= $element['#children'];
+  $output .= '</div>';
+  $output .= '</div>';
+
+  return $output;
+}
+
+/**
+ * Theme rules debug log elements.
+ * @ingroup themeable
+ */
+function theme_rules_debug_element($variables) {
+  $output = '<div class="rules-debug-block">';
+  $output .= '<div class="rules-debug-log-head rules-debug-open rules-debug-collapsible-link">"';
+  $output .= '<span unselectable="on" class="ui-icon ui-icon-triangle-1-e rules-debug-icon-open">&nbsp;</span>';
+  $output .= $variables['head'];
+  if (isset($variables['link'])) {
+    $output .= ' ' . $variables['link'];
+  }
+  $output .= '</div>';
+  $output .= $variables['log'];
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Themes rules autocomplete forms.
+ * @ingroup themeable
+ */
+function theme_rules_autocomplete($variables) {
+  $element = $variables['element'];
+  drupal_add_js(drupal_get_path('module', 'rules') . '/ui/rules.autocomplete.js');
+  drupal_add_library('system', 'ui.autocomplete');
+  drupal_add_library('system', 'ui.button');
+
+  $element['#attributes']['type'] = 'text';
+  element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength'));
+  _form_set_class($element, array('form-text', 'rules-autocomplete'));
+
+  $id = $element['#attributes']['id'];
+  $id_button = drupal_html_id($id . '-button');
+
+  $js_vars['rules_autocomplete'][$id] = array(
+    'inputId' => $id,
+    'source' => url($element['#autocomplete_path'], array('absolute' => TRUE)),
+  );
+  drupal_add_js($js_vars, 'setting');
+
+  $output = '<div class="rules-autocomplete">';
+  $output .= '<input' . drupal_attributes($element['#attributes']) . ' />';
+  $output .= '</div>';
+
+  return $output;
+}
+
+/**
+ * General theme function for displaying settings related help.
+ * @ingroup themeable
+ */
+function theme_rules_settings_help($variables) {
+  $text = $variables['text'];
+  $heading = $variables['heading'];
+  return "<p class=\"rules-settings-help\"><strong>$heading:</strong> $text</p>";
+}
Binary file sites/all/.DS_Store has changed
Binary file sites/all/libraries/ARC2/.DS_Store has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/.gitignore	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,4 @@
+*.DS_Store
+plugins/*
+triggers/*
+tests/coverage/*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/ARC2.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,484 @@
+<?php
+/**
+ * ARC2 core class (static, not instantiated)
+ *
+ * @author Benjamin Nowack
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ */
+
+/* E_STRICT hack */
+if (function_exists('date_default_timezone_get')) {
+  date_default_timezone_set(@date_default_timezone_get());
+}
+
+class ARC2 {
+
+  static function getVersion() {
+    return '2011-12-01';
+  }
+
+  /*  */
+  
+  static function getIncPath($f = '') {
+    $r = realpath(dirname(__FILE__)) . '/';
+    $dirs = array(
+      'plugin' => 'plugins',
+      'trigger' => 'triggers',
+      'store' => 'store', 
+      'serializer' => 'serializers', 
+      'extractor' => 'extractors', 
+      'sparqlscript' => 'sparqlscript', 
+      'parser' => 'parsers', 
+    );
+    foreach ($dirs as $k => $dir) {
+      if (preg_match('/' . $k . '/i', $f)) {
+        return $r . $dir . '/';
+      }
+    }
+    return $r;
+  }
+  
+  static function getScriptURI() {
+    if (isset($_SERVER) && (isset($_SERVER['SERVER_NAME']) || isset($_SERVER['HTTP_HOST']))) {
+      $proto = preg_replace('/^([a-z]+)\/.*$/', '\\1', strtolower($_SERVER['SERVER_PROTOCOL']));
+      $port = $_SERVER['SERVER_PORT'];
+      $server = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
+      $script = $_SERVER['SCRIPT_NAME'];
+      /* https */
+      if (($proto == 'http') && $port == 443) {
+        $proto = 'https';
+        $port = 80;
+      }
+      return $proto . '://' . $server . ($port != 80 ? ':' . $port : '') . $script;
+    }
+    elseif (isset($_SERVER['SCRIPT_FILENAME'])) {
+      return 'file://' . realpath($_SERVER['SCRIPT_FILENAME']);
+    }
+    return 'http://localhost/unknown_path';
+  }
+
+  static function getRequestURI() {
+    if (isset($_SERVER) && isset($_SERVER['REQUEST_URI'])) {
+      return preg_replace('/^([a-z]+)\/.*$/', '\\1', strtolower($_SERVER['SERVER_PROTOCOL'])) . 
+        '://' . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']) .
+        ($_SERVER['SERVER_PORT'] != 80 ? ':' . $_SERVER['SERVER_PORT'] : '') .
+        $_SERVER['REQUEST_URI'];
+    }
+    return ARC2::getScriptURI();
+  }
+  
+  static function inc($f, $path = '') {
+    $prefix = 'ARC2';
+    if (preg_match('/^([^\_]+)\_(.*)$/', $f, $m)) {
+      $prefix = $m[1];
+      $f = $m[2];
+    }
+    $inc_path = $path ? $path : ARC2::getIncPath($f);
+    $path = $inc_path . $prefix . '_' . urlencode($f) . '.php';
+    if (file_exists($path)) return include_once($path);
+    /* safe-mode hack */
+    if (@include_once($path)) return 1;
+    /* try other path */
+    if ($prefix != 'ARC2') {
+      $path = $inc_path . strtolower($prefix) . '/' . $prefix . '_' . urlencode($f) . '.php';
+      if (file_exists($path)) return include_once($path);
+      /* safe-mode hack */
+      if (@include_once($path)) return 1;
+    }
+    return 0;
+  }
+  
+  /*  */
+
+  static function mtime(){
+	  return microtime(true);
+  }
+  
+  static function x($re, $v, $options = 'si') {
+    return preg_match("/^\s*" . $re . "(.*)$/" . $options, $v, $m) ? $m : false;
+  }
+
+  /*  */
+
+  static function getFormat($val, $mtype = '', $ext = '') {
+    ARC2::inc('getFormat');
+    return ARC2_getFormat($val, $mtype, $ext);
+  }
+  
+  static function getPreferredFormat($default = 'plain') {
+    ARC2::inc('getPreferredFormat');
+    return ARC2_getPreferredFormat($default);
+  }
+  
+  /*  */
+  
+  static function toUTF8($v) {
+    if (urlencode($v) === $v) return $v;
+    //if (utf8_decode($v) == $v) return $v;
+    $v = (strpos(utf8_decode(str_replace('?', '', $v)), '?') === false) ? utf8_decode($v) : $v;
+    /* custom hacks, mainly caused by bugs in PHP's json_decode */
+    $mappings = array(
+      '%18' => '‘',
+      '%19' => '’',
+      '%1C' => '“',
+      '%1D' => 'â€',
+      '%1E' => '„',
+      '%10' => 'â€',
+      '%12' => '−',
+      '%13' => '–',
+      '%14' => '—',
+      '%26' => '&',
+    );
+    $froms = array_keys($mappings);
+    $tos = array_values($mappings);
+    foreach ($froms as $i => $from) $froms[$i] = urldecode($from);
+    $v = str_replace($froms, $tos, $v);
+    /* utf8 tweaks */
+    return preg_replace_callback('/([\x00-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xf7][\x80-\xbf]{3}|[\xf8-\xfb][\x80-\xbf]{4}|[\xfc-\xfd][\x80-\xbf]{5}|[^\x00-\x7f])/', array('ARC2', 'getUTF8Char'), $v);
+  }
+  
+  static function getUTF8Char($v) {
+    $val = $v[1];
+    if (strlen(trim($val)) === 1) return utf8_encode($val);
+    if (preg_match('/^([\x00-\x7f])(.+)/', $val, $m)) return $m[1] . ARC2::toUTF8($m[2]);
+    return $val;
+  }
+
+  /*  */
+
+  static function splitURI($v) {
+    /* the following namespaces may lead to conflated URIs,
+     * we have to set the split position manually
+    */
+    if (strpos($v, 'www.w3.org')) {
+      $specials = array(
+        'http://www.w3.org/XML/1998/namespace',
+        'http://www.w3.org/2005/Atom',
+        'http://www.w3.org/1999/xhtml',
+      );
+      foreach ($specials as $ns) {
+        if (strpos($v, $ns) === 0) {
+          $local_part = substr($v, strlen($ns));
+          if (!preg_match('/^[\/\#]/', $local_part)) {
+            return array($ns, $local_part);
+          }
+        }
+      }
+    }
+    /* auto-splitting on / or # */
+    //$re = '^(.*?)([A-Z_a-z][-A-Z_a-z0-9.]*)$';
+    if (preg_match('/^(.*[\/\#])([^\/\#]+)$/', $v, $m)) return array($m[1], $m[2]);
+    /* auto-splitting on last special char, e.g. urn:foo:bar */
+    if (preg_match('/^(.*[\:\/])([^\:\/]+)$/', $v, $m)) return array($m[1], $m[2]);
+    return array($v, '');
+  }
+  
+  /*  */
+
+  static function getSimpleIndex($triples, $flatten_objects = 1, $vals = '') {
+    $r = array();
+    foreach ($triples as $t) {
+      $skip_t = 0;
+      foreach (array('s', 'p', 'o') as $term) {
+        $$term = $t[$term];
+        /* template var */
+        if (isset($t[$term . '_type']) && ($t[$term . '_type'] == 'var')) {
+          $val = isset($vals[$$term]) ? $vals[$$term] : '';
+          $skip_t = isset($vals[$$term]) ? $skip_t : 1;
+          $type = '';
+          $type = !$type && isset($vals[$$term . ' type']) ? $vals[$$term . ' type'] : $type;
+          $type = !$type && preg_match('/^\_\:/', $val) ? 'bnode' : $type;
+          if ($term == 'o') {
+            $type = !$type && (preg_match('/\s/s', $val) || !preg_match('/\:/', $val)) ? 'literal' : $type;
+            $type = !$type && !preg_match('/[\/]/', $val) ? 'literal' : $type;
+          }
+          $type = !$type ? 'uri' : $type;
+          $t[$term . '_type'] =  $type;
+          $$term = $val;
+        }
+      }
+      if ($skip_t) {
+        continue;
+      }
+      if (!isset($r[$s])) $r[$s] = array();
+      if (!isset($r[$s][$p])) $r[$s][$p] = array();
+      if ($flatten_objects) {
+        if (!in_array($o, $r[$s][$p])) $r[$s][$p][] = $o;
+      }
+      else {
+        $o = array('value' => $o);
+        foreach (array('lang', 'type', 'datatype') as $suffix) {
+          if (isset($t['o_' . $suffix]) && $t['o_' . $suffix]) {
+            $o[$suffix] = $t['o_' . $suffix];
+          }
+          elseif (isset($t['o ' . $suffix]) && $t['o ' . $suffix]) {
+            $o[$suffix] = $t['o ' . $suffix];
+          }
+        }
+        if (!in_array($o, $r[$s][$p])) {
+          $r[$s][$p][] = $o;
+        }
+      }
+    }
+    return $r;
+  }
+  
+  static function getTriplesFromIndex($index) {
+    $r = array();
+    foreach ($index as $s => $ps) {
+      foreach ($ps as $p => $os) {
+        foreach ($os as $o) {
+          $r[] = array(
+            's' => $s,
+            'p' => $p,
+            'o' => $o['value'],
+            's_type' => preg_match('/^\_\:/', $s) ? 'bnode' : 'uri',
+            'o_type' => $o['type'],
+            'o_datatype' => isset($o['datatype']) ? $o['datatype'] : '',
+            'o_lang' => isset($o['lang']) ? $o['lang'] : '',
+          );
+        }
+      }
+    }
+    return $r;
+  }
+
+  static function getMergedIndex() {
+    $r = array();
+    foreach (func_get_args() as $index) {
+      foreach ($index as $s => $ps) {
+        if (!isset($r[$s])) $r[$s] = array();
+        foreach ($ps as $p => $os) {
+          if (!isset($r[$s][$p])) $r[$s][$p] = array();
+          foreach ($os as $o) {
+            if (!in_array($o, $r[$s][$p])) {
+              $r[$s][$p][] = $o;
+            }
+          }
+        }
+      }
+    }
+    return $r;
+  }
+  
+  static function getCleanedIndex() {/* removes triples from a given index */
+    $indexes = func_get_args();
+    $r = $indexes[0];
+    for ($i = 1, $i_max = count($indexes); $i < $i_max; $i++) {
+      $index = $indexes[$i];
+      foreach ($index as $s => $ps) {
+        if (!isset($r[$s])) continue;
+        foreach ($ps as $p => $os) {
+          if (!isset($r[$s][$p])) continue;
+          $r_os = $r[$s][$p];
+          $new_os = array();
+          foreach ($r_os as $r_o) {
+            $r_o_val = is_array($r_o) ? $r_o['value'] : $r_o;
+            $keep = 1;
+            foreach ($os as $o) {
+              $del_o_val = is_array($o) ? $o['value'] : $o;
+              if ($del_o_val == $r_o_val) {
+                $keep = 0;
+                break;
+              }
+            }
+            if ($keep) {
+              $new_os[] = $r_o;
+            }
+          }
+          if ($new_os) {
+            $r[$s][$p] = $new_os;
+          }
+          else {
+            unset($r[$s][$p]);
+          }
+        }
+      }
+    }
+    /* check r */
+    $has_data = 0;
+    foreach ($r as $s => $ps) {
+      if ($ps) {
+        $has_data = 1;
+        break;
+      }
+    }
+    return $has_data ? $r : array();
+  }
+  
+  /*  */
+
+  static function getStructType($v) {
+    /* string */
+    if (is_string($v)) return 'string';
+    /* flat array, numeric keys */
+    if (in_array(0, array_keys($v))) {/* numeric keys */
+      /* simple array */
+      if (!is_array($v[0])) return 'array';
+      /* triples */
+      //if (isset($v[0]) && isset($v[0]['s']) && isset($v[0]['p'])) return 'triples';
+      if (in_array('p', array_keys($v[0]))) return 'triples';
+    }
+    /* associative array */
+    else {
+      /* index */
+      foreach ($v as $s => $ps) {
+        if (!is_array($ps)) break;
+        foreach ($ps as $p => $os) {
+          if (!is_array($os) || !is_array($os[0])) break;
+          if (in_array('value', array_keys($os[0]))) return 'index';
+        }
+      }
+    }
+    /* array */
+    return 'array';
+  }
+
+  /*  */
+
+  static function getComponent($name, $a = '', $caller = '') {
+    ARC2::inc($name);
+    $prefix = 'ARC2';
+    if (preg_match('/^([^\_]+)\_(.+)$/', $name, $m)) {
+      $prefix = $m[1];
+      $name = $m[2];
+    }
+    $cls = $prefix . '_' . $name;
+    if (!$caller) $caller = new stdClass();
+    return new $cls($a, $caller);
+  }
+  
+  /* graph */
+
+  static function getGraph($a = '') {
+    return ARC2::getComponent('Graph', $a);
+  }
+
+  /* resource */
+
+  static function getResource($a = '') {
+    return ARC2::getComponent('Resource', $a);
+  }
+
+  /* reader */
+
+  static function getReader($a = '') {
+    return ARC2::getComponent('Reader', $a);
+  }
+
+  /* parsers */
+
+  static function getParser($prefix, $a = '') {
+    return ARC2::getComponent($prefix . 'Parser', $a);
+  }
+
+  static function getRDFParser($a = '') {
+    return ARC2::getParser('RDF', $a);
+  }
+
+  static function getRDFXMLParser($a = '') {
+    return ARC2::getParser('RDFXML', $a);
+  }
+
+  static function getTurtleParser($a = '') {
+    return ARC2::getParser('Turtle', $a);
+  }
+
+  static function getRSSParser($a = '') {
+    return ARC2::getParser('RSS', $a);
+  }
+
+  static function getSemHTMLParser($a = '') {
+    return ARC2::getParser('SemHTML', $a);
+  }
+
+  static function getSPARQLParser($a = '') {
+    return ARC2::getComponent('SPARQLParser', $a);
+  }
+
+  static function getSPARQLPlusParser($a = '') {
+    return ARC2::getParser('SPARQLPlus', $a);
+  }
+
+  static function getSPARQLXMLResultParser($a = '') {
+    return ARC2::getParser('SPARQLXMLResult', $a);
+  }
+
+  static function getJSONParser($a = '') {
+    return ARC2::getParser('JSON', $a);
+  }
+
+  static function getSGAJSONParser($a = '') {
+    return ARC2::getParser('SGAJSON', $a);
+  }
+
+  static function getCBJSONParser($a = '') {
+    return ARC2::getParser('CBJSON', $a);
+  }
+
+  static function getSPARQLScriptParser($a = '') {
+    return ARC2::getParser('SPARQLScript', $a);
+  }
+
+  /* store */
+
+  static function getStore($a = '', $caller = '') {
+    return ARC2::getComponent('Store', $a, $caller);
+  }
+
+  static function getStoreEndpoint($a = '', $caller = '') {
+    return ARC2::getComponent('StoreEndpoint', $a, $caller);
+  }
+
+  static function getRemoteStore($a = '', $caller = '') {
+    return ARC2::getComponent('RemoteStore', $a, $caller);
+  }
+
+  static function getMemStore($a = '') {
+    return ARC2::getComponent('MemStore', $a);
+  }
+  
+  /* serializers */
+
+  static function getSer($prefix, $a = '') {
+    return ARC2::getComponent($prefix . 'Serializer', $a);
+  }
+
+  static function getTurtleSerializer($a = '') {
+    return ARC2::getSer('Turtle', $a);
+  }
+
+  static function getRDFXMLSerializer($a = '') {
+    return ARC2::getSer('RDFXML', $a);
+  }
+
+  static function getNTriplesSerializer($a = '') {
+    return ARC2::getSer('NTriples', $a);
+  }
+
+  static function getRDFJSONSerializer($a = '') {
+    return ARC2::getSer('RDFJSON', $a);
+  }
+
+  static function getPOSHRDFSerializer($a = '') {/* deprecated */
+    return ARC2::getSer('POSHRDF', $a);
+  }
+
+  static function getMicroRDFSerializer($a = '') {
+    return ARC2::getSer('MicroRDF', $a);
+  }
+
+  static function getRSS10Serializer($a = '') {
+    return ARC2::getSer('RSS10', $a);
+  }
+
+  /* sparqlscript */
+
+  static function getSPARQLScriptProcessor($a = '') {
+    return ARC2::getComponent('SPARQLScriptProcessor', $a);
+  }
+
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/ARC2_Class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,533 @@
+<?php
+/**
+ * ARC2 base class
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ */
+
+class ARC2_Class {
+  
+  function __construct($a, &$caller) {
+    $this->a = is_array($a) ? $a : array();
+    $this->caller = $caller;
+    $this->__init();
+  }
+  
+  function __init() {/* base, time_limit */
+    if (!$_POST && isset($GLOBALS['HTTP_RAW_POST_DATA'])) parse_str($GLOBALS['HTTP_RAW_POST_DATA'], $_POST); /* php5 bug */
+    $this->inc_path = ARC2::getIncPath();
+    $this->ns_count = 0;
+    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->nsp = array($rdf => 'rdf');
+    $this->used_ns = array($rdf);
+    $this->ns = array_merge(array('rdf' => $rdf), $this->v('ns', array(), $this->a));
+
+    $this->base = $this->v('base', ARC2::getRequestURI(), $this->a);
+    $this->errors = array();
+    $this->warnings = array();
+    $this->adjust_utf8 = $this->v('adjust_utf8', 0, $this->a);
+    $this->max_errors = $this->v('max_errors', 25, $this->a);
+    $this->has_pcre_unicode = @preg_match('/\pL/u', 'test');/* \pL = block/point which is a Letter */
+  }
+
+  /*  */
+  
+  function v($name, $default = false, $o = false) {/* value if set */
+    if ($o === false) $o = $this;
+    if (is_array($o)) {
+      return isset($o[$name]) ? $o[$name] : $default;
+    }
+    return isset($o->$name) ? $o->$name : $default;
+  }
+  
+  function v1($name, $default = false, $o = false) {/* value if 1 (= not empty) */
+    if ($o === false) $o = $this;
+    if (is_array($o)) {
+      return (isset($o[$name]) && $o[$name]) ? $o[$name] : $default;
+    }
+    return (isset($o->$name) && $o->$name) ? $o->$name : $default;
+  }
+  
+  function m($name, $a = false, $default = false, $o = false) {/* call method */
+    if ($o === false) $o = $this;
+    return method_exists($o, $name) ? $o->$name($a) : $default;
+  }
+
+  /*  */
+
+  function camelCase($v, $lc_first = 0, $keep_boundaries = 0) {
+    $r = ucfirst($v);
+    while (preg_match('/^(.*)[^a-z0-9](.*)$/si', $r, $m)) {
+      /* don't fuse 2 upper-case chars */
+      if ($keep_boundaries && $m[1]) {
+        $boundary = substr($m[1], -1);
+        if (strtoupper($boundary) == $boundary) $m[1] .= 'CAMELCASEBOUNDARY';
+      }
+      $r = $m[1] . ucfirst($m[2]);
+    }
+    $r = str_replace('CAMELCASEBOUNDARY', '_', $r);
+    if ((strlen($r) > 1) && $lc_first && !preg_match('/[A-Z]/', $r[1])) $r = strtolower($r[0]) . substr($r, 1);
+    return $r;
+  }
+
+  function deCamelCase($v, $uc_first = 0) {
+    $r = str_replace('_', ' ', $v);
+    $r = preg_replace('/([a-z0-9])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
+    return $uc_first ? ucfirst($r) : $r;
+  }
+
+  /**
+   * Tries to extract a somewhat human-readable label from a URI.
+   */
+
+  function extractTermLabel($uri, $loops = 0) {
+    list($ns, $r) = $this->splitURI($uri);
+    /* encode apostrophe + s */
+    $r = str_replace('%27s', '_apostrophes_', $r);
+    /* normalize */
+    $r = $this->deCamelCase($this->camelCase($r, 1, 1));
+    /* decode apostrophe + s */
+    $r = str_replace(' apostrophes ', "'s ", $r);
+    /* typical RDF non-info URI */
+    if (($loops < 1) && preg_match('/^(self|it|this|me)$/i', $r)) {
+      return $this->extractTermLabel(preg_replace('/\#.+$/', '', $uri), $loops + 1);
+    }
+    /* trailing hash or slash */
+    if ($uri && !$r && ($loops < 2)) {
+      return $this->extractTermLabel(preg_replace('/[\#\/]$/', '', $uri), $loops + 1);
+    }
+    /* a de-camel-cased URL (will look like "www example com") */
+    if (preg_match('/^www (.+ [a-z]{2,4})$/', $r, $m)) {
+      return $this->getPrettyURL($uri);
+    }
+    return $r;
+  }
+
+  /**
+   * Generates a less ugly in-your-face URL.
+   */
+
+  function getPrettyURL($r) {
+    $r = rtrim($r, '/');
+    $r = preg_replace('/^https?\:\/\/(www\.)?/', '', $r);
+    return $r;
+  }
+
+  /*  */
+  
+  function addError($v) {
+    if (!in_array($v, $this->errors)) {
+      $this->errors[] = $v;
+    }
+    if ($this->caller && method_exists($this->caller, 'addError')) {
+      $glue = strpos($v, ' in ') ? ' via ' : ' in ';
+      $this->caller->addError($v . $glue . get_class($this));
+    }
+    if (count($this->errors) > $this->max_errors) {
+      die('Too many errors (limit: ' . $this->max_errors . '): ' . print_r($this->errors, 1));
+    }
+    return false;
+  }
+  
+  function getErrors() {
+    return $this->errors;
+  }
+  
+  function getWarnings() {
+    return $this->warnings;
+  }
+
+  function resetErrors() {
+    $this->errors = array();
+    if ($this->caller && method_exists($this->caller, 'resetErrors')) {
+      $this->caller->resetErrors();
+    }
+  }
+  
+  /*  */
+  
+  function splitURI($v) {
+    return ARC2::splitURI($v);
+  }
+
+  /*  */
+
+  function getPName($v, $connector = ':') {
+    /* is already a pname */
+    $ns = $this->getPNameNamespace($v, $connector);
+    if ($ns) {
+      if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
+      return $v;
+    }
+    /* new pname */
+    $parts = $this->splitURI($v);
+    if ($parts) {
+      /* known prefix */
+      foreach ($this->ns as $prefix => $ns) {
+        if ($parts[0] == $ns) {
+          if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
+          return $prefix . $connector . $parts[1];
+        }
+      }
+      /* new prefix */
+      $prefix = $this->getPrefix($parts[0]);
+      return $prefix . $connector . $parts[1];
+    }
+    return $v;
+  }
+
+  function getPNameNamespace($v, $connector = ':') {
+    $re = '/^([a-z0-9\_\-]+)\:([a-z0-9\_\-\.\%]+)$/i';
+    if ($connector != ':') {
+      $connectors = array('\:', '\-', '\_', '\.');
+      $chars = join('', array_diff($connectors, array($connector)));
+      $re = '/^([a-z0-9' . $chars . ']+)\\' . $connector . '([a-z0-9\_\-\.\%]+)$/i';
+    }
+    if (!preg_match($re, $v, $m)) return 0;
+    if (!isset($this->ns[$m[1]])) return 0;
+    return $this->ns[$m[1]];
+  }
+
+  function setPrefix($prefix, $ns) {
+	 $this->ns[$prefix] = $ns;
+	 $this->nsp[$ns] = $prefix;
+	 return $this;
+  }
+  
+  function getPrefix($ns) {
+    if (!isset($this->nsp[$ns])) {
+      $this->ns['ns' . $this->ns_count] = $ns;
+      $this->nsp[$ns] = 'ns' . $this->ns_count;
+      $this->ns_count++;
+    }
+    if (!in_array($ns, $this->used_ns)) $this->used_ns[] = $ns;
+    return $this->nsp[$ns];
+  }
+
+  function expandPName($v, $connector = ':') {
+    $re = '/^([a-z0-9\_\-]+)\:([a-z0-9\_\-\.\%]+)$/i';
+    if ($connector != ':') {
+      $connectors = array(':', '-', '_', '.');
+      $chars = '\\' . join('\\', array_diff($connectors, array($connector)));
+      $re = '/^([a-z0-9' . $chars . ']+)\\' . $connector . '([a-z0-9\_\-\.\%]+)$/Ui';
+    }
+    if (preg_match($re, $v, $m) && isset($this->ns[$m[1]])) {
+      return $this->ns[$m[1]] . $m[2];
+    }
+    return $v;
+  }
+
+  function expandPNames($index) {
+    $r = array();
+    foreach ($index as $s => $ps) {
+      $s = $this->expandPName($s);
+      $r[$s] = array();
+      foreach ($ps as $p => $os) {
+        $p = $this->expandPName($p);
+        if (!is_array($os)) $os = array($os);
+        foreach ($os as $i => $o) {
+          if (!is_array($o)) {
+            $o_val = $this->expandPName($o);
+            $o_type = preg_match('/^[a-z]+\:[^\s\<\>]+$/si', $o_val) ? 'uri' : 'literal';
+            $o = array('value' => $o_val, 'type' => $o_type);
+          }
+          $os[$i] = $o;
+        }
+        $r[$s][$p] = $os;
+      }
+    }
+    return $r;
+  }
+
+  /*  */
+  
+  function calcURI($path, $base = "") {
+    /* quick check */
+    if (preg_match("/^[a-z0-9\_]+\:/i", $path)) {/* abs path or bnode */
+      return $path;
+    }
+    if (preg_match('/^\$\{.*\}/', $path)) {/* placeholder, assume abs URI */
+      return $path;
+    }
+    if (preg_match("/^\/\//", $path)) {/* net path, assume http */
+      return 'http:' . $path;
+    }
+    /* other URIs */
+    $base = $base ? $base : $this->base;
+    $base = preg_replace('/\#.*$/', '', $base);
+    if ($path === true) {/* empty (but valid) URIref via turtle parser: <> */
+      return $base;
+    }
+    $path = preg_replace("/^\.\//", '', $path);
+    $root = preg_match('/(^[a-z0-9]+\:[\/]{1,3}[^\/]+)[\/|$]/i', $base, $m) ? $m[1] : $base; /* w/o trailing slash */
+    $base .= ($base == $root) ? '/' : '';
+    if (preg_match('/^\//', $path)) {/* leading slash */
+      return $root . $path;
+    }
+    if (!$path) {
+      return $base;
+    }
+    if (preg_match('/^([\#\?])/', $path, $m)) {
+      return preg_replace('/\\' .$m[1]. '.*$/', '', $base) . $path;
+    }
+    if (preg_match('/^(\&)(.*)$/', $path, $m)) {/* not perfect yet */
+      return preg_match('/\?/', $base) ? $base . $m[1] . $m[2] : $base . '?' . $m[2];
+    }
+    if (preg_match("/^[a-z0-9]+\:/i", $path)) {/* abs path */
+      return $path;
+    }
+    /* rel path: remove stuff after last slash */
+    $base = substr($base, 0, strrpos($base, '/')+1);
+    /* resolve ../ */
+    while (preg_match('/^(\.\.\/)(.*)$/', $path, $m)) {
+      $path = $m[2];
+      $base = ($base == $root.'/') ? $base : preg_replace('/^(.*\/)[^\/]+\/$/', '\\1', $base);
+    }
+    return $base . $path;
+  }
+  
+  /*  */
+  
+  function calcBase($path) {
+    $r = $path;
+    $r = preg_replace('/\#.*$/', '', $r);/* remove hash */
+    $r = preg_replace('/^\/\//', 'http://', $r);/* net path (//), assume http */
+    if (preg_match('/^[a-z0-9]+\:/', $r)) {/* scheme, abs path */
+      while (preg_match('/^(.+\/)(\.\.\/.*)$/U', $r, $m)) {
+        $r = $this->calcURI($m[1], $m[2]);
+      }
+      return $r;
+    }
+    return 'file://' . realpath($r);/* real path */
+  }
+
+  /*  */
+
+  function getResource($uri, $store_or_props = '') {
+    $res = ARC2::getResource($this->a);
+    $res->setURI($uri);
+    if (is_array($store_or_props)) {
+      $res->setProps($store_or_props);
+    }
+    else {
+      $res->setStore($store_or_props);
+    }
+    return $res;
+  }
+  
+  function toIndex($v) {
+    if (is_array($v)) {
+      if (isset($v[0]) && isset($v[0]['s'])) return ARC2::getSimpleIndex($v, 0);
+      return $v;
+    }
+    $parser = ARC2::getRDFParser($this->a);
+    if ($v && !preg_match('/\s/', $v)) {/* assume graph URI */
+      $parser->parse($v);
+    }
+    else {
+      $parser->parse('', $v);
+    }
+    return $parser->getSimpleIndex(0);
+  }
+
+  function toTriples($v) {
+    if (is_array($v)) {
+      if (isset($v[0]) && isset($v[0]['s'])) return $v;
+      return ARC2::getTriplesFromIndex($v);
+    }
+    $parser = ARC2::getRDFParser($this->a);
+    if ($v && !preg_match('/\s/', $v)) {/* assume graph URI */
+      $parser->parse($v);
+    }
+    else {
+      $parser->parse('', $v);
+    }
+    return $parser->getTriples();
+  }
+
+  /*  */
+
+  function toNTriples($v, $ns = '', $raw = 0) {
+    ARC2::inc('NTriplesSerializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $ser = new ARC2_NTriplesSerializer(array_merge($this->a, array('ns' => $ns)), $this);
+    return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
+  }
+  
+  function toTurtle($v, $ns = '', $raw = 0) {
+    ARC2::inc('TurtleSerializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $ser = new ARC2_TurtleSerializer(array_merge($this->a, array('ns' => $ns)), $this);
+    return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
+  }
+  
+  function toRDFXML($v, $ns = '', $raw = 0) {
+    ARC2::inc('RDFXMLSerializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $ser = new ARC2_RDFXMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
+    return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v, $raw) : $ser->getSerializedIndex($v, $raw);
+  }
+
+  function toRDFJSON($v, $ns = '') {
+    ARC2::inc('RDFJSONSerializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $ser = new ARC2_RDFJSONSerializer(array_merge($this->a, array('ns' => $ns)), $this);
+    return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
+  }
+
+  function toRSS10($v, $ns = '') {
+    ARC2::inc('RSS10Serializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $ser = new ARC2_RSS10Serializer(array_merge($this->a, array('ns' => $ns)), $this);
+    return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
+  }
+
+  function toLegacyXML($v, $ns = '') {
+    ARC2::inc('LegacyXMLSerializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $ser = new ARC2_LegacyXMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
+    return $ser->getSerializedArray($v);
+  }
+
+  function toLegacyJSON($v, $ns = '') {
+    ARC2::inc('LegacyJSONSerializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $ser = new ARC2_LegacyJSONSerializer(array_merge($this->a, array('ns' => $ns)), $this);
+    return $ser->getSerializedArray($v);
+  }
+
+  function toLegacyHTML($v, $ns = '') {
+    ARC2::inc('LegacyHTMLSerializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $ser = new ARC2_LegacyHTMLSerializer(array_merge($this->a, array('ns' => $ns)), $this);
+    return $ser->getSerializedArray($v);
+  }
+
+  function toHTML($v, $ns = '', $label_store = '') {
+    ARC2::inc('MicroRDFSerializer');
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $conf = array_merge($this->a, array('ns' => $ns));
+    if ($label_store) $conf['label_store'] = $label_store;
+    $ser = new ARC2_MicroRDFSerializer($conf, $this);
+    return (isset($v[0]) && isset($v[0]['s'])) ? $ser->getSerializedTriples($v) : $ser->getSerializedIndex($v);
+  }
+
+  /*  */
+
+  function getFilledTemplate($t, $vals, $g = '') {
+    $parser = ARC2::getTurtleParser();
+    $parser->parse($g, $this->getTurtleHead() . $t);
+    return $parser->getSimpleIndex(0, $vals);
+  }
+  
+  function getTurtleHead() {
+    $r = '';
+    $ns = $this->v('ns', array(), $this->a);
+    foreach ($ns as $k => $v) {
+      $r .= "@prefix " . $k . ": <" .$v. "> .\n";
+    }
+    return $r;
+  }
+  
+  function completeQuery($q, $ns = '') {
+    if (!$ns) $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $added_prefixes = array();
+    $prologue = '';
+    foreach ($ns as $k => $v) {
+      $k = rtrim($k, ':');
+      if (in_array($k, $added_prefixes)) continue;
+      if (preg_match('/(^|\s)' . $k . ':/s', $q) && !preg_match('/PREFIX\s+' . $k . '\:/is', $q)) {
+        $prologue .= "\n" . 'PREFIX ' . $k . ': <' . $v . '>';
+      }
+      $added_prefixes[] = $k;
+    }
+    return $prologue . "\n" . $q;
+  }
+
+  /*  */
+
+  function toUTF8($str) {
+    return $this->adjust_utf8 ? ARC2::toUTF8($str) : $str;
+  }
+
+  function toDataURI($str) {
+    return 'data:text/plain;charset=utf-8,' . rawurlencode($str);
+  }
+
+  function fromDataURI($str) {
+    return str_replace('data:text/plain;charset=utf-8,', '', rawurldecode($str));
+  }
+
+  /* prevent SQL injections via SPARQL REGEX */
+
+  function checkRegex($str) {
+    return addslashes($str); // @@todo extend
+  }
+  
+  /* Microdata methods */
+
+  function getMicrodataAttrs($id, $type = '') {
+    $type = $type ? $this->expandPName($type) : $this->expandPName('owl:Thing');
+    return 'itemscope="" itemtype="' . htmlspecialchars($type) . '" itemid="' . htmlspecialchars($id) . '"';
+  }
+
+  function mdAttrs($id, $type = '') {
+    return $this->getMicrodataAttrs($id, $type);
+  }
+
+  /* central DB query hook */
+
+  function queryDB($sql, $con, $log_errors = 0) {
+    $t1 = ARC2::mtime();
+    $r = mysql_query($sql, $con);
+    if (0) {
+      $t2 = ARC2::mtime() - $t1;
+      $call_obj = $this;
+      $call_path = '';
+      while ($call_obj) {
+        $call_path = get_class($call_obj) . ' / ' . $call_path;
+        $call_obj = isset($call_obj->caller) ? $call_obj->caller : false;
+      }
+      echo "\n" . $call_path . " needed " . $t2 . ' secs for ' . str_replace("\n" , ' ', $sql);;
+    }
+    if ($log_errors && ($er = mysql_error($con))) $this->addError($er);
+    return $r;
+  }
+
+  /**
+   * Shortcut method to create an RDF/XML backup dump from an RDF Store object.
+   */
+  function backupStoreData($store, $target_path, $offset = 0) {
+    $limit = 10;
+    $q = '
+      SELECT DISTINCT ?s WHERE {
+        ?s ?p ?o .
+      }
+      ORDER BY ?s
+      LIMIT ' . $limit . '
+      ' . ($offset ? 'OFFSET ' . $offset : '') . '
+    ';
+    $rows = $store->query($q, 'rows');
+    $tc = count($rows);
+    $full_tc = $tc + $offset;
+    $mode = $offset ? 'ab' : 'wb';
+    $fp = fopen($target_path, $mode);
+    foreach ($rows as $row) {
+      $index = $store->query('DESCRIBE <' . $row['s'] . '>', 'raw');
+      if ($index) {
+        $doc = $this->toRDFXML($index);
+        fwrite($fp, $doc . "\n\n");
+      }
+    }
+    fclose($fp);
+    if ($tc == 10) {
+      set_time_limit(300);
+      $this->backupStoreData($store, $target_path, $offset + $limit);
+    }
+    return $full_tc;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/ARC2_Graph.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,178 @@
+<?php
+/**
+ * ARC2 Graph object
+ *
+ * @author Benjamin Nowack <mail@bnowack.de>
+ * @license W3C Software License
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+*/
+
+ARC2::inc('Class');
+
+class ARC2_Graph extends ARC2_Class {
+	
+	protected $index;
+
+	function __construct($a, &$caller) {
+		parent::__construct($a, $caller);
+	}
+  
+	function __init() {
+		parent::__init();
+		$this->index = array();
+	}
+  
+	function setIndex($index) {
+		$this->index = $index;
+		return $this;
+	}
+
+	function getIndex() {
+		return $this->index;
+	}
+	
+	function addIndex($index) {
+		$this->index = ARC2::getMergedIndex($this->index, $index);
+		return $this;
+	}
+	
+	function addGraph($graph) {
+		// namespaces
+		foreach ($graph->ns as $prefix => $ns) {
+			$this->setPrefix($prefix, $ns);
+		}
+		// index
+		$this->addIndex($graph->getIndex());
+		return $this;
+	}
+	
+	function addRdf($data, $format = null) {
+		if ($format == 'json') {
+			return $this->addIndex(json_decode($data, true));
+		}
+		else {// parse any other rdf format
+			return $this->addIndex($this->toIndex($data));
+		}
+	}
+	
+	function hasSubject($s) {
+		return isset($this->index[$s]);
+	}
+		
+	function hasTriple($s, $p, $o) {
+		if (!is_array($o)) {
+			return $this->hasLiteralTriple($s, $p, $o) || $this->hasLinkTriple($s, $p, $o);
+		}
+		if (!isset($this->index[$s])) return false;
+		$p = $this->expandPName($p);
+		if (!isset($this->index[$s][$p])) return false;
+		return in_array($o, $this->index[$s][$p]);
+	}
+	
+	function hasLiteralTriple($s, $p, $o) {
+		if (!isset($this->index[$s])) return false;
+		$p = $this->expandPName($p);
+		if (!isset($this->index[$s][$p])) return false;
+		$os = $this->getObjects($s, $p, false);
+		foreach ($os as $object) {
+			if ($object['value'] == $o && $object['type'] == 'literal') {
+				return true;
+			}
+		}
+		return false;
+	}
+  
+	function hasLinkTriple($s, $p, $o) {
+		if (!isset($this->index[$s])) return false;
+		$p = $this->expandPName($p);
+		if (!isset($this->index[$s][$p])) return false;
+		$os = $this->getObjects($s, $p, false);
+		foreach ($os as $object) {
+			if ($object['value'] == $o && ($object['type'] == 'uri' || $object['type'] == 'bnode')) {
+				return true;
+			}
+		}
+		return false;
+	}
+  
+	function addTriple($s, $p, $o, $oType = 'literal') {
+		$p = $this->expandPName($p);
+		if (!is_array($o)) $o = array('value' => $o, 'type' => $oType);
+		if ($this->hasTriple($s, $p, $o)) return;
+		if (!isset($this->index[$s])) $this->index[$s] = array();
+		if (!isset($this->index[$s][$p])) $this->index[$s][$p] = array();
+		$this->index[$s][$p][] = $o;
+		return $this;
+	}
+	
+	function getSubjects($p = null, $o = null) {
+		if (!$p && !$o) return array_keys($this->index);
+		$result = array();
+		foreach ($this->index as $s => $ps) {
+			foreach ($ps as $predicate => $os) {
+				if ($p && $predicate != $p) continue;
+				foreach ($os as $object) {
+					if (!$o) {
+						$result[] = $s;
+						break;
+					}
+					else if (is_array($o) && $object == $o) {
+						$result[] = $s;
+						break;
+					}
+					else if ($o && $object['value'] == $o) {
+						$result[] = $s;
+						break;
+					}
+				}
+			}
+		}
+		return array_unique($result);
+	}
+	
+	function getPredicates($s = null) {
+		$result = array();
+		$index = $s ? (array($s => isset($this->index[$s]) ? $this->index[$s] : array())) : $this->index;
+		foreach ($index as $subject => $ps) {
+			if ($s && $s != $subject) continue;
+			$result = array_merge($result, array_keys($ps));
+		}
+		return array_unique($result);
+	}
+	
+	function getObjects($s, $p, $plain = false) {
+		if (!isset($this->index[$s])) return array();
+		$p = $this->expandPName($p);
+		if (!isset($this->index[$s][$p])) return array();
+		$os = $this->index[$s][$p];
+		if ($plain) {
+			array_walk($os, function(&$o) {
+				$o = $o['value'];
+			});
+		}
+		return $os;
+	}
+	
+	function getObject($s, $p, $plain = false, $default = null) {
+		$os = $this->getObjects($s, $p, $plain);
+		return empty($os) ? $default : $os[0];
+	}
+
+	function getNTriples() {
+		return parent::toNTriples($this->index, $this->ns);
+	}
+
+	function getTurtle() {
+		return parent::toTurtle($this->index, $this->ns);
+	}
+
+	function getRDFXML() {
+		return parent::toRDFXML($this->index, $this->ns);
+	}
+
+	function getJSON() {
+		return json_encode($this->index);
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/ARC2_Reader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,420 @@
+<?php
+/**
+ * ARC2 Web Client
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_Reader extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* inc_path, proxy_host, proxy_port, proxy_skip, http_accept_header, http_user_agent_header, max_redirects */
+    parent::__init();
+    $this->http_method = $this->v('http_method', 'GET', $this->a);
+    $this->message_body = $this->v('message_body', '', $this->a);;
+    $this->http_accept_header = $this->v('http_accept_header', 'Accept: application/rdf+xml; q=0.9, text/turtle; q=0.8, */*; q=0.1', $this->a);
+    $this->http_user_agent_header = $this->v('http_user_agent_header', 'User-Agent: ARC Reader (http://arc.semsol.org/)', $this->a);
+    $this->http_custom_headers = $this->v('http_custom_headers', '', $this->a);
+    $this->max_redirects = $this->v('max_redirects', 3, $this->a);
+    $this->format = $this->v('format', false, $this->a);
+    $this->redirects = array();
+    $this->stream_id = '';
+    $this->timeout = $this->v('reader_timeout', 30, $this->a);
+    $this->response_headers = array();
+    $this->digest_auth = 0;
+    $this->auth_infos = $this->v('reader_auth_infos', array(), $this->a);
+  }
+
+  /*  */
+  
+  function setHTTPMethod($v) {
+    $this->http_method = $v;
+  }
+
+  function setMessageBody($v) {
+    $this->message_body = $v;
+  }
+
+  function setAcceptHeader($v) {
+    $this->http_accept_header = $v;
+  }
+
+  function setCustomHeaders($v) {
+    $this->http_custom_headers = $v;
+  }
+
+  function addCustomHeaders($v) {
+    if ($this->http_custom_headers) $this->http_custom_headers .= "\r\n";
+    $this->http_custom_headers .= $v;
+  }
+
+  /*  */
+
+  function activate($path, $data = '', $ping_only = 0, $timeout = 0) {
+    $this->setCredentials($path);
+    $this->ping_only = $ping_only;
+    if ($timeout) $this->timeout = $timeout;
+    $id = md5($path . ' ' . $data);
+    if ($this->stream_id != $id) {
+      $this->stream_id = $id;
+      /* data uri? */
+      if (!$data && preg_match('/^data\:([^\,]+)\,(.*)$/', $path, $m)) {
+        $path = '';
+        $data = preg_match('/base64/', $m[1]) ? base64_decode($m[2]) : rawurldecode($m[2]);
+      }
+      $this->base = $this->calcBase($path);
+      $this->uri = $this->calcURI($path, $this->base);
+      $this->stream = ($data) ? $this->getDataStream($data) : $this->getSocketStream($this->base, $ping_only);
+      if ($this->stream && !$this->ping_only) {
+        $this->getFormat();
+      }
+    }
+  }
+
+  /*
+   * HTTP Basic/Digest + Proxy authorization can be defined in the
+   * arc_reader_credentials config setting:
+
+        'arc_reader_credentials' => array(
+          'http://basic.example.com/' => 'user:pass', // shortcut for type=basic
+          'http://digest.example.com/' => 'user::pass', // shortcut for type=digest
+          'http://proxy.example.com/' => array('type' => 'basic', 'proxy', 'user' => 'user', 'pass' => 'pass'),
+        ),
+
+   */
+
+  function setCredentials($url) {
+    if (!$creds = $this->v('arc_reader_credentials', array(), $this->a))  return 0;
+    foreach ($creds as $pattern => $creds) {
+      /* digest shortcut (user::pass) */
+      if (!is_array($creds) && preg_match('/^(.+)\:\:(.+)$/', $creds, $m)) {
+        $creds = array('type' => 'digest', 'user' => $m[1], 'pass' => $m[2]);
+      }
+      /* basic shortcut (user:pass) */
+      if (!is_array($creds) && preg_match('/^(.+)\:(.+)$/', $creds, $m)) {
+        $creds = array('type' => 'basic', 'user' => $m[1], 'pass' => $m[2]);
+      }
+      if (!is_array($creds)) return 0;
+      $regex = '/' . preg_replace('/([\:\/\.\?])/', '\\\\\1', $pattern) . '/';
+      if (!preg_match($regex, $url)) continue;
+      $mthd = 'set' . $this->camelCase($creds['type']) . 'AuthCredentials';
+      if (method_exists($this, $mthd)) $this->$mthd($creds, $url);
+    }
+  }
+
+  function setBasicAuthCredentials($creds) {
+    $auth = 'Basic ' . base64_encode($creds['user'] . ':' . $creds['pass']);
+    $h = in_array('proxy', $creds) ? 'Proxy-Authorization' : 'Authorization';
+    $this->addCustomHeaders($h . ': ' . $auth);
+    //echo $h . ': ' . $auth . print_r($creds, 1);
+  }
+
+  function setDigestAuthCredentials($creds, $url) {
+    $path = $this->v1('path', '/', parse_url($url));
+    $auth = '';
+    $hs = $this->getResponseHeaders();
+    /* initial 401 */
+    $h = $this->v('www-authenticate', '', $hs);
+    if ($h && preg_match('/Digest/i', $h)) {
+      $auth = 'Digest ';
+      /* Digest realm="$realm", nonce="$nonce", qop="auth", opaque="$opaque" */
+      $ks = array('realm', 'nonce', 'opaque');/* skipping qop, assuming "auth" */
+      foreach ($ks as $i => $k) {
+        $$k = preg_match('/' . $k . '=\"?([^\"]+)\"?/i', $h, $m) ? $m[1] : '';
+        $auth .= ($i ? ', ' : '') . $k . '="' . $$k . '"';
+        $this->auth_infos[$k] = $$k;
+      }
+      $this->auth_infos['auth'] = $auth;
+      $this->auth_infos['request_count'] = 1;
+    }
+    /* initial 401 or repeated request */
+    if ($this->v('auth', 0, $this->auth_infos)) {
+      $qop = 'auth';
+      $auth = $this->auth_infos['auth'];
+      $rc = $this->auth_infos['request_count'];
+      $realm = $this->auth_infos['realm'];
+      $nonce = $this->auth_infos['nonce'];
+      $ha1 = md5($creds['user'] . ':' . $realm . ':' . $creds['pass']);
+      $ha2 = md5($this->http_method . ':' . $path);
+      $nc = dechex($rc);
+      $cnonce = dechex($rc * 2);
+      $resp = md5($ha1 . ':' . $nonce . ':' . $nc . ':' . $cnonce . ':' . $qop . ':' . $ha2);
+      $auth .= ', username="' . $creds['user'] . '"' .
+        ', uri="' . $path . '"' .
+        ', qop=' . $qop . '' .
+        ', nc=' . $nc .
+        ', cnonce="' . $cnonce . '"' .
+        ', uri="' . $path . '"' .
+        ', response="' . $resp . '"' .
+      '';
+      $this->auth_infos['request_count'] = $rc + 1;
+    }
+    if (!$auth) return 0;
+    $h = in_array('proxy', $creds) ? 'Proxy-Authorization' : 'Authorization';
+    $this->addCustomHeaders($h . ': ' . $auth);
+  }
+
+  /*  */
+
+  function useProxy($url) {
+    if (!$this->v1('proxy_host', 0, $this->a)) {
+      return false;
+    }
+    $skips = $this->v1('proxy_skip', array(), $this->a);
+    foreach ($skips as $skip) {
+      if (strpos($url, $skip) !== false) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /*  */
+  
+  function createStream($path, $data = '') {
+    $this->base = $this->calcBase($path);
+    $this->stream = ($data) ? $this->getDataStream($data) : $this->getSocketStream($this->base);
+  }
+
+  function getDataStream($data) {
+    return array('type' => 'data', 'pos' => 0, 'headers' => array(), 'size' => strlen($data), 'data' => $data, 'buffer' => '');
+  }
+  
+  function getSocketStream($url) {
+    if ($url == 'file://') {
+      return $this->addError('Error: file does not exists or is not accessible');
+    }
+    $parts = parse_url($url);
+    $mappings = array('file' => 'File', 'http' => 'HTTP', 'https' => 'HTTP');
+    if ($scheme = $this->v(strtolower($parts['scheme']), '', $mappings)) {
+      return $this->m('get' . $scheme . 'Socket', $url, $this->getDataStream(''));
+    }
+  }
+  
+  function getFileSocket($url) {
+    $parts = parse_url($url);
+    $s = file_exists($parts['path']) ? @fopen($parts['path'], 'rb') : false;
+    if (!$s) {
+      return $this->addError('Socket error: Could not open "' . $parts['path'] . '"');
+    }
+    return array('type' => 'socket', 'socket' =>& $s, 'headers' => array(), 'pos' => 0, 'size' => filesize($parts['path']), 'buffer' => '');
+  }
+  
+  function getHTTPSocket($url, $redirs = 0, $prev_parts = '') {
+    $parts = parse_url($url);
+    /* relative redirect */
+    if (!isset($parts['scheme']) && $prev_parts) $parts['scheme'] = $prev_parts['scheme'];
+    if (!isset($parts['host']) && $prev_parts) $parts['host'] = $prev_parts['host'];
+    /* no scheme */
+    if (!$this->v('scheme', '', $parts)) return $this->addError('Socket error: Missing URI scheme.');
+    /* port tweaks */
+    $parts['port'] = ($parts['scheme'] == 'https') ? $this->v1('port', 443, $parts) : $this->v1('port', 80, $parts);
+    $nl = "\r\n";
+    $http_mthd = strtoupper($this->http_method);
+    if ($this->v1('user', 0, $parts) || $this->useProxy($url)) {
+      $h_code = $http_mthd . ' ' . $url;
+    }
+    else {
+      $h_code = $http_mthd . ' ' . $this->v1('path', '/', $parts) . (($v = $this->v1('query', 0, $parts)) ? '?' . $v : '') . (($v = $this->v1('fragment', 0, $parts)) ? '#' . $v : '');
+    }
+    $scheme_default_port = ($parts['scheme'] == 'https') ? 443 : 80;
+    $port_code = ($parts['port'] != $scheme_default_port) ? ':' . $parts['port'] : '';
+    $h_code .= ' HTTP/1.0' . $nl.
+      'Host: ' . $parts['host'] . $port_code . $nl .
+      (($v = $this->http_accept_header) ? $v . $nl : '') .
+      (($v = $this->http_user_agent_header) && !preg_match('/User\-Agent\:/', $this->http_custom_headers) ? $v . $nl : '') .
+      (($http_mthd == 'POST') ? 'Content-Length: ' . strlen($this->message_body) . $nl : '') .
+      ($this->http_custom_headers ? trim($this->http_custom_headers) . $nl : '') .
+      $nl .
+    '';
+    /* post body */
+    if ($http_mthd == 'POST') {
+      $h_code .= $this->message_body . $nl;
+    }
+    /* connect */
+    if ($this->useProxy($url)) {
+      $s = @fsockopen($this->a['proxy_host'], $this->a['proxy_port'], $errno, $errstr, $this->timeout);
+    }
+    elseif (($parts['scheme'] == 'https') && function_exists('stream_socket_client')) {
+      // SSL options via config array, code by Hannes Muehleisen (muehleis@informatik.hu-berlin.de)
+  	  $context = stream_context_create();
+      foreach ($this->a as $k => $v) {
+        if (preg_match('/^arc_reader_ssl_(.+)$/', $k, $m)) {
+          stream_context_set_option($context, 'ssl', $m[1], $v);
+        }
+      }
+      $s = stream_socket_client('ssl://' . $parts['host'] . ":" . $parts['port'], $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context);
+    }
+    elseif ($parts['scheme'] == 'https') {
+      $s = @fsockopen('ssl://' . $parts['host'], $parts['port'], $errno, $errstr, $this->timeout);
+    }
+    elseif ($parts['scheme'] == 'http') {
+      $s = @fsockopen($parts['host'], $parts['port'], $errno, $errstr, $this->timeout);
+    }
+    if (!$s) {
+      return $this->addError('Socket error: Could not connect to "' . $url . '" (proxy: ' . ($this->useProxy($url) ? '1' : '0') . '): ' . $errstr);
+    }
+    /* request */
+    fwrite($s, $h_code);
+    /* timeout */
+    if ($this->timeout) {
+      //stream_set_blocking($s, false);
+      stream_set_timeout($s, $this->timeout);
+    }
+    /* response headers */
+    $h = array();
+    $this->response_headers = $h;
+    if (!$this->ping_only) {
+      do {
+        $line = trim(fgets($s, 4096));
+        $info = stream_get_meta_data($s);
+        if (preg_match("/^HTTP[^\s]+\s+([0-9]{1})([0-9]{2})(.*)$/i", $line, $m)) {/* response code */
+          $error = in_array($m[1], array('4', '5')) ? $m[1] . $m[2] . ' ' . $m[3] : '';
+          $error = ($m[1].$m[2] == '304') ? '304 '.$m[3] : $error;
+          $h['response-code'] = $m[1] . $m[2];
+          $h['error'] = $error;
+          $h['redirect'] = ($m[1] == '3') ? true : false;
+        }
+        elseif (preg_match('/^([^\:]+)\:\s*(.*)$/', $line, $m)) {/* header */
+          $h_name = strtolower($m[1]);
+          if (!isset($h[$h_name])) {/* 1st value */
+            $h[$h_name] = trim($m[2]);
+          }
+          elseif (!is_array($h[$h_name])) {/* 2nd value */
+            $h[$h_name] = array($h[$h_name], trim($m[2]));
+          }
+          else {/* more values */
+            $h[$h_name][] = trim($m[2]);
+          }
+        }
+      } while(!$info['timed_out'] && !feof($s) && $line);
+      $h['format'] = strtolower(preg_replace('/^([^\s]+).*$/', '\\1', $this->v('content-type', '', $h)));
+      $h['encoding'] = preg_match('/(utf\-8|iso\-8859\-1|us\-ascii)/', $this->v('content-type', '', $h), $m) ? strtoupper($m[1]) : '';
+      $h['encoding'] = preg_match('/charset=\s*([^\s]+)/si', $this->v('content-type', '', $h), $m) ? strtoupper($m[1]) : $h['encoding'];
+      $this->response_headers = $h;
+      /* result */
+      if ($info['timed_out']) {
+        return $this->addError('Connection timed out after ' . $this->timeout . ' seconds');
+      }
+      /* error */
+      if ($v = $this->v('error', 0, $h)) {
+        /* digest auth */
+        /* 401 received */
+        if (preg_match('/Digest/i', $this->v('www-authenticate', '', $h)) && !$this->digest_auth) {
+          $this->setCredentials($url);
+          $this->digest_auth = 1;
+          return $this->getHTTPSocket($url);
+        }
+        return $this->addError($error . ' "' . (!feof($s) ? trim(strip_tags(fread($s, 128))) . '..."' : ''));
+      }
+      /* redirect */
+      if ($this->v('redirect', 0, $h) && ($new_url = $this->v1('location', 0, $h))) {
+        fclose($s);
+        $this->redirects[$url] = $new_url;
+        $this->base = $new_url;
+        if ($redirs > $this->max_redirects) {
+          return $this->addError('Max numbers of redirects exceeded.');
+        }
+        return $this->getHTTPSocket($new_url, $redirs+1, $parts);
+      }
+    }
+    if ($this->timeout) {
+      stream_set_blocking($s, true);
+    }
+    return array('type' => 'socket', 'url' => $url, 'socket' =>& $s, 'headers' => $h, 'pos' => 0, 'size' => $this->v('content-length', 0, $h), 'buffer' => '');
+  }
+
+  function readStream($buffer_xml = true, $d_size = 1024) {
+    //if (!$s = $this->v('stream')) return '';
+    if (!$s = $this->v('stream')) return $this->addError('missing stream in "readStream" ' . $this->uri);
+    $s_type = $this->v('type', '', $s);
+    $r = $s['buffer'];
+    $s['buffer'] = '';
+    if ($s['size']) $d_size = min($d_size, $s['size'] - $s['pos']);
+    /* data */
+    if ($s_type == 'data') {
+      $d = ($d_size > 0) ? substr($s['data'], $s['pos'], $d_size) : '';
+    }
+    /* socket */
+    elseif ($s_type == 'socket') {
+      $d = ($d_size > 0) && !feof($s['socket']) ? fread($s['socket'], $d_size) : '';
+    }
+    $eof = $d ? false : true;
+    /* chunked despite HTTP 1.0 request */
+    if (isset($s['headers']) && isset($s['headers']['transfer-encoding']) && ($s['headers']['transfer-encoding'] == 'chunked')) {
+      $d = preg_replace('/(^|[\r\n]+)[0-9a-f]{1,4}[\r\n]+/', '', $d);
+    }
+    $s['pos'] += strlen($d);
+    if ($buffer_xml) {/* stop after last closing xml tag (if available) */
+      if (preg_match('/^(.*\>)([^\>]*)$/s', $d, $m)) {
+        $d = $m[1];
+        $s['buffer'] = $m[2];
+      }
+      elseif (!$eof) {
+        $s['buffer'] = $r . $d;
+        $this->stream = $s;
+        return $this->readStream(true, $d_size);
+      }
+    }
+    $this->stream = $s;
+    return $r . $d;
+  }
+  
+  function closeStream() {
+    if (isset($this->stream)) {
+      if ($this->v('type', 0, $this->stream) == 'socket' && !empty($this->stream['socket'])) {
+        @fclose($this->stream['socket']);
+      }
+      unset($this->stream);
+    }
+  }
+  
+  /*  */
+  
+  function getFormat() {
+    if (!$this->format) {
+      if (!$this->v('stream')) {
+        return $this->addError('missing stream in "getFormat"');
+      }
+      $v = $this->readStream(false);
+      $mtype = $this->v('format', '', $this->stream['headers']);
+      $this->stream['buffer'] = $v . $this->stream['buffer'];
+      $ext = preg_match('/\.([^\.]+)$/', $this->uri, $m) ? $m[1] : '';
+      $this->format = ARC2::getFormat($v, $mtype, $ext);
+    }
+    return $this->format;
+  }
+    
+  /*  */
+
+  function getResponseHeaders() {
+    if (isset($this->stream) && isset($this->stream['headers'])) {
+      return $this->stream['headers'];
+    }
+    return $this->response_headers;
+  }
+  
+  function getEncoding($default = 'UTF-8') {
+    return $this->v1('encoding', $default, $this->stream['headers']);
+  }
+
+  function getRedirects() {
+    return $this->redirects;
+  }
+
+  function getAuthInfos() {
+    return $this->auth_infos;
+  }
+  
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/ARC2_Resource.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,150 @@
+<?php
+/**
+ * ARC2 Resource object
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2011-01-19
+*/
+
+ARC2::inc('Class');
+
+class ARC2_Resource extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->uri = '';
+    $this->index = array();
+    $this->fetched = array();
+    $this->store = '';
+  }
+
+  /*  */
+  
+  function setURI($uri) {
+    $this->uri = $uri;
+  }
+
+  function setIndex($index) {
+    $this->index = $index;
+  }
+
+  function getIndex($index) {
+    return $this->index;
+  }
+
+  function setProps($props, $s = '') {
+    if (!$s) $s = $this->uri;
+    $this->index[$s] = $props;
+  }
+
+  function setProp($p, $os, $s = '') {
+    if (!$s) $s = $this->uri;
+    /* single plain value */
+    if (!is_array($os)) $os = array('value' => $os, 'type' => 'literal');
+    /* single array value */
+    if (isset($os['value'])) $os = array($os);
+    /* list of values */
+    foreach ($os as $i => $o) {
+      if (!is_array($o)) $os[$i] = array('value' => $o, 'type' => 'literal');
+    }
+    $this->index[$s][$this->expandPName($p)] = $os;
+  }
+
+  /* add a relation to a URI. Allows for instance $res->setRel('rdf:type', 'doap:Project') */
+  function setRel($p, $r, $s = '') {
+    if(!is_array($r)) {
+      $uri = array (
+		    'type' => 'uri',
+		    'value' => $this->expandPName($r));
+      $this->setProp($p, $uri, $s);
+    } else {
+      if (!$s) $s = $this->uri;
+      foreach($r as $i => $x) {
+	if(!is_array($x)) {
+	  $uri = array (
+			'type' => 'uri',
+			'value' => $this->expandPName($x));
+	  $r[$i] = $uri;
+	}
+      }
+      $this->index[$s][$this->expandPName($p)] = $r;
+    }
+  }
+
+  /* Specialize setProp to set an xsd:dateTime typed literal. Example : $res->setPropXSDdateTime('dcterms:created', date('c')) */
+  function setPropXSDdateTime($p, $dt, $s = '') {
+	$datecreated=array('value' => $dt,
+		'type' => 'literal',
+		'datatype' => 'http://www.w3.org/2001/XMLSchema#dateTime');
+	$this->setProp($p, $datecreated, $s);
+  }
+
+  function setStore($store) {
+    $this->store = $store;
+  }
+
+  /*  */
+
+  function fetchData($uri = '') {
+    if (!$uri) $uri = $this->uri;
+    if (!$uri) return 0;
+    if (in_array($uri, $this->fetched)) return 0;
+    $this->index[$uri] = array();
+    if ($this->store) {
+      $index = $this->store->query('CONSTRUCT { <' . $uri . '> ?p ?o . } WHERE { <' . $uri . '> ?p ?o . } ', 'raw');
+    }
+    else {
+      $index = $this->toIndex($uri);
+    }
+    $this->index = ARC2::getMergedIndex($this->index, $index);
+    $this->fetched[] = $uri;
+  }
+
+  /*  */
+  
+  function getProps($p = '', $s = '') {
+    if (!$s) $s = $this->uri;
+    if (!$s) return array();
+    if (!isset($this->index[$s])) $this->fetchData($s);
+    if (!$p) return $this->index[$s];
+    return $this->v($this->expandPName($p), array(), $this->index[$s]);
+  }
+
+  function getProp($p, $s = '') {
+    $props = $this->getProps($p, $s);
+    return $props ? $props[0] : '';
+  }
+
+  function getPropValue($p, $s = '') {
+    $prop = $this->getProp($p, $s);
+    return $prop ? $prop['value'] : '';
+  }
+
+  function getPropValues($p, $s = '') {
+    $r = array();
+    $props = $this->getProps($p, $s);
+    foreach ($props as $prop) {
+      $r[] = $prop['value'];
+    }
+    return $r;
+  }
+
+  function hasPropValue($p, $o, $s = '') {
+    $props = $this->getProps($p, $s);
+    $o = $this->expandPName($o);
+    foreach ($props as $prop) {
+      if ($prop['value'] == $o) return 1;
+    }
+    return 0;
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/ARC2_getFormat.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+/**
+ * ARC2 format detection function
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+function ARC2_getFormat($v, $mtype = '', $ext = '') {
+  $r = false;
+  /* mtype check (atom, rdf/xml, turtle, n3, mp3, jpg) */
+  $r = (!$r && preg_match('/\/atom\+xml/', $mtype)) ? 'atom' : $r;
+  $r = (!$r && preg_match('/\/rdf\+xml/', $mtype)) ? 'rdfxml' : $r;
+  $r = (!$r && preg_match('/\/(x\-)?turtle/', $mtype)) ? 'turtle' : $r;
+  $r = (!$r && preg_match('/\/rdf\+n3/', $mtype)) ? 'n3' : $r;
+  $r = (!$r && preg_match('/\/sparql-results\+xml/', $mtype)) ? 'sparqlxml' : $r;
+  /* xml sniffing */
+  if (
+    !$r &&
+    /* starts with angle brackets */
+    preg_match('/^\s*\<[^\s]/s', $v) &&
+    /* has an xmlns:* declaration or a matching pair of tags */
+    (preg_match('/\sxmlns\:?/', $v) || preg_match('/\<([^\s]+).+\<\/\\1\>/s', $v)) // &&
+  ) {
+    while (preg_match('/^\s*\<\?xml[^\r\n]+\?\>\s*/s', $v)) {
+      $v = preg_replace('/^\s*\<\?xml[^\r\n]+\?\>\s*/s', '', $v);
+    }
+    while (preg_match('/^\s*\<\!--.+?--\>\s*/s', $v)) {
+      $v = preg_replace('/^\s*\<\!--.+?--\>\s*/s', '', $v);
+    }
+    /* doctype checks (html, rdf) */
+    $r = (!$r && preg_match('/^\s*\<\!DOCTYPE\s+html[\s|\>]/is', $v)) ? 'html' : $r;
+    $r = (!$r && preg_match('/^\s*\<\!DOCTYPE\s+[a-z0-9\_\-]\:RDF\s/is', $v)) ? 'rdfxml' : $r;
+    /* markup checks */
+    $v = preg_replace('/^\s*\<\!DOCTYPE\s.*\]\>/is', '', $v);
+    $r = (!$r && preg_match('/^\s*\<rss\s+[^\>]*version/s', $v)) ? 'rss' : $r;
+    $r = (!$r && preg_match('/^\s*\<feed\s+[^\>]+http\:\/\/www\.w3\.org\/2005\/Atom/s', $v)) ? 'atom' : $r;
+    $r = (!$r && preg_match('/^\s*\<opml\s/s', $v)) ? 'opml' : $r;
+    $r = (!$r && preg_match('/^\s*\<html[\s|\>]/is', $v)) ? 'html' : $r;
+    $r = (!$r && preg_match('/^\s*\<sparql\s+[^\>]+http\:\/\/www\.w3\.org\/2005\/sparql\-results\#/s', $v)) ? 'sparqlxml' : $r;
+    $r = (!$r && preg_match('/^\s*\<[^\>]+http\:\/\/www\.w3\.org\/2005\/sparql\-results#/s', $v)) ? 'srx' : $r;
+    $r = (!$r && preg_match('/^\s*\<[^\s]*RDF[\s\>]/s', $v)) ? 'rdfxml' : $r;
+    $r = (!$r && preg_match('/^\s*\<[^\>]+http\:\/\/www\.w3\.org\/1999\/02\/22\-rdf/s', $v)) ? 'rdfxml' : $r;
+    
+    $r = !$r ? 'xml' : $r;
+  }
+  /* json|jsonp */
+  if (!$r && preg_match('/^[a-z0-9\.\(]*\s*[\{\[].*/s', trim($v))) {
+    /* google social graph api */
+    $r = (!$r && preg_match('/\"canonical_mapping\"/', $v)) ? 'sgajson' : $r;
+    /* crunchbase api */
+    $r = (!$r && preg_match('/\"permalink\"/', $v)) ? 'cbjson' : $r;
+
+    $r = !$r ? 'json' : $r;
+  }
+  /* turtle/n3 */
+  $r = (!$r && preg_match('/\@(prefix|base)/i', $v)) ? 'turtle' : $r;
+  $r = (!$r && preg_match('/^(ttl)$/', $ext)) ? 'turtle' : $r;
+  $r = (!$r && preg_match('/^(n3)$/', $ext)) ? 'n3' : $r;
+  /* ntriples */
+  $r = (!$r && preg_match('/^\s*(_:|<).+?\s+<[^>]+?>\s+\S.+?\s*\.\s*$/sm', $v)) ? 'ntriples' : $r;
+  $r = (!$r && preg_match('/^(nt)$/', $ext)) ? 'ntriples' : $r;
+  return $r;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/ARC2_getPreferredFormat.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,50 @@
+<?php
+/**
+ * ARC2 result format detection
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+function ARC2_getPreferredFormat($default = 'plain') {
+  $formats = array(
+    'html' => 'HTML', 'text/html' => 'HTML', 'xhtml+xml' => 'HTML', 
+    'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML',
+    'ntriples' => 'NTriples', 
+    'rdf+n3' => 'Turtle', 'x-turtle' => 'Turtle', 'turtle' => 'Turtle', 'text/turtle' => 'Turtle',
+    'rdfjson' => 'RDFJSON', 'json' => 'RDFJSON',
+    'xml' => 'XML',
+    'legacyjson' => 'LegacyJSON'
+  );
+  $prefs = array();
+  $o_vals = array();
+  /* accept header */
+  $vals = explode(',', $_SERVER['HTTP_ACCEPT']);
+  if ($vals) {
+    foreach ($vals as $val) {
+      if (preg_match('/(rdf\+n3|(x\-|text\/)turtle|rdf\+xml|text\/html|xhtml\+xml|xml|json)/', $val, $m)) {
+        $o_vals[$m[1]] = 1;
+        if (preg_match('/\;q\=([0-9\.]+)/', $val, $sub_m)) {
+          $o_vals[$m[1]] = 1 * $sub_m[1];
+        }
+      }
+    }
+  }
+  /* arg */
+  if (isset($_GET['format'])) $o_vals[$_GET['format']] = 1.1;
+  /* rank */
+  arsort($o_vals);
+  foreach ($o_vals as $val => $prio) {
+    $prefs[] = $val;
+  }
+  /* default */
+  $prefs[] = $default;
+  foreach ($prefs as $pref) {
+    if (isset($formats[$pref])) {
+      return $formats[$pref];
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/README.md	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,8 @@
+ARC2
+====
+
+ARC2 is a PHP 5.3 library for working with RDF.
+It also provides a MySQL-based triplestore with SPARQL support.
+
+Feature-wise, ARC2 is now in a stable state with no further feature additions planned. 
+Issues are still being fixed and Pull Requests are welcome, though.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/build.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project default="run-tests" name="arc2" basedir=".">
+
+	<property environment="env" />
+	<property name="tests-dir" location="${basedir}/tests"/>
+	<property name="coverage-dir" location="${tests-dir}/coverage"/>
+
+	<target name="run-tests" depends="run-unit-tests, run-functional-tests"/>
+	
+	<target name="run-unit-tests">
+		<exec dir="${tests-dir}/unit" executable="phpunit" failonerror="true">
+			<arg line="--coverage-html ${coverage-dir} --filter Test ." />
+		</exec>
+	</target>
+
+	<target name="run-functional-tests">
+		<exec dir="${tests-dir}/functional" executable="phpunit" failonerror="true">
+			<arg line="--filter Test ." />
+		</exec>
+	</target>
+
+</project>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/composer.json	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,21 @@
+{
+    "name": "semsol/arc2",
+	"type": "library",
+    "description": "Semsol's ARC2 RDF library",
+	"keywords": ["rdf","sparql"],
+	"homepage": "https://github.com/semsol/arc2",
+    "license": "W3C",
+    "authors": [
+        {
+            "name": "Benji Nowack",
+            "email": "mail@bnowack.de",
+			"homepage": "http://bnowack.de/"
+        }
+    ],
+    "require": {
+		"php": ">=5.3.0"
+    },
+     "autoload": {
+        "classmap": ["./","parsers/","serializers/"]
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/extractors/ARC2_DcExtractor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,80 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 DC Extractor
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('RDFExtractor');
+
+class ARC2_DcExtractor extends ARC2_RDFExtractor {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->a['ns']['dc'] = 'http://purl.org/dc/elements/1.1/';
+  }
+
+  /*  */
+  
+  function extractRDF() {
+    $t_vals = array();
+    $t = '';
+    foreach ($this->nodes as $n) {
+      foreach (array('title', 'link', 'meta') as $tag) {
+        if ($n['tag'] == $tag) {
+          $m = 'extract' . ucfirst($tag);
+          list ($t_vals, $t) = $this->$m($n, $t_vals, $t);
+        }
+      }
+    }
+    if ($t) {
+      $doc = $this->getFilledTemplate($t, $t_vals, $n['doc_base']);
+      $this->addTs(ARC2::getTriplesFromIndex($doc));
+    }
+  }
+  
+  /*  */
+
+  function extractTitle($n, $t_vals, $t) {
+    if ($t_vals['title'] = $this->getPlainContent($n)) {
+      $t .= '<' . $n['doc_url'] . '> dc:title ?title . ';
+    }
+    return array($t_vals, $t);
+  }
+  
+  /*  */
+
+  function extractLink($n, $t_vals, $t) {
+    if ($this->hasRel($n, 'alternate') || $this->hasRel($n, 'meta')) {
+      if ($href = $this->v('href uri', '', $n['a'])) {
+        $t .= '<' . $n['doc_url'] . '> rdfs:seeAlso <' . $href . '> . ';
+        if ($v = $this->v('type', '', $n['a'])) {
+          $t .= '<' .$href. '> dc:format "' . $v . '" . ';
+        }
+        if ($v = $this->v('title', '', $n['a'])) {
+          $t .= '<' .$href. '> dc:title "' . $v . '" . ';
+        }
+      }
+    }
+    return array($t_vals, $t);
+  }
+  
+  function extractMeta($n, $t_vals, $t) {
+    if ($this->hasAttribute('http-equiv', $n, 'Content-Type') || $this->hasAttribute('http-equiv', $n, 'content-type')) {
+      if ($v = $this->v('content', '', $n['a'])) {
+        $t .= '<' . $n['doc_url'] . '> dc:format "' . $v . '" . ';
+      }
+    }
+    return array($t_vals, $t);
+  }
+  
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/extractors/ARC2_ErdfExtractor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,284 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 eRDF Extractor (w/o link title generation)
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('RDFExtractor');
+
+class ARC2_ErdfExtractor extends ARC2_RDFExtractor {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function extractRDF() {
+    if (!isset($this->caller->detected_formats['erdf'])) return 0;
+    $root_node = $this->getRootNode();
+    $base = $this->getDocBase();
+    $ns = $this->getNamespaces();
+    $context = array(
+      'base' => $base,
+      'prev_res' => $base,
+      'cur_res' => $base,
+      'ns' => $ns,
+      'lang' => '',
+    );
+    $this->processNode($root_node, $context);
+  }
+  
+  /*  */
+  
+  function getRootNode() {
+    foreach ($this->nodes as $id => $node) {
+      if ($node['tag'] == 'html') {
+        return $node;
+      }
+    }
+    return $this->nodes[0];
+  }
+  
+  function getNamespaces() {
+    $r = array(
+      'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+      'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#'
+    );
+    foreach ($this->nodes as $id => $node) {
+      if (preg_match('/^(link|a)$/', $node['tag']) && isset($node['a']['rel']) && preg_match('/schema\.([^\s]+)/is', $node['a']['rel'], $m) && isset($node['a']['href uri'])) {
+        $r[$m[1]] = $node['a']['href uri'];
+      }
+    }
+    return $r;
+  }
+
+  /*  */
+  
+  function processNode($n, $ct) {
+    /* context */
+    //$ct['lang'] = $this->v('xml:lang', $ct['lang'], $n['a']);
+    $ct['lang'] = '';
+    $ct['prop_uris'] = $this->getPropertyURIs($n, $ct);
+    $ct['prev_res'] = $ct['cur_res'];
+    $ct['cur_res'] = $this->getCurrentResourceURI($n, $ct);
+    $ct['cur_obj_id'] = $this->getCurrentObjectID($n, $ct);
+    $ct['cur_obj_literal'] = $this->getCurrentObjectLiteral($n, $ct);
+    /* triple production (http://research.talis.com/2005/erdf/wiki/Main/SummaryOfTripleProductionRules) */
+    foreach ($ct['prop_uris'] as $type => $uris) {
+      foreach ($uris as $uri) {
+        $rdf_type = preg_match('/^ /', $uri) ? 1 : 0;
+        /* meta + name */
+        if (($type == 'name') && ($n['tag'] == 'meta')) {
+          $t = array(
+            's' => $ct['cur_res'],
+            's_type' => 'uri',
+            'p' => $uri, 
+            'o' => $ct['cur_obj_literal']['value'],
+            'o_type' => 'literal',
+            'o_lang' => $ct['cur_obj_literal']['datatype'] ? '' : $ct['cur_obj_literal']['lang'],
+            'o_datatype' => $ct['cur_obj_literal']['datatype'],
+          );
+          $this->addT($t);
+        }
+        /* class */
+        if ($type == 'class') {
+          if ($rdf_type) {
+            $s = $this->v('href uri', $ct['cur_res'], $n['a']);
+            $s = $this->v('src uri', $s, $n['a']);
+            $t = array(
+              's' => $s,
+              's_type' => 'uri',
+              'p' => $ct['ns']['rdf'] . 'type', 
+              'o' => trim($uri),
+              'o_type' => 'uri',
+              'o_lang' => '',
+              'o_datatype' => '',
+            );
+          }
+          elseif (isset($n['a']['id'])) {/* used as object */
+            $t = array(
+              's' => $ct['prev_res'],
+              's_type' => 'uri',
+              'p' => $uri, 
+              'o' => $ct['cur_res'],
+              'o_type' => 'uri',
+              'o_lang' => '',
+              'o_datatype' => '',
+            );
+          }
+          else {
+            $t = array(
+              's' => $ct['cur_res'],
+              's_type' => 'uri',
+              'p' => $uri, 
+              'o' => $ct['cur_obj_literal']['value'],
+              'o_type' => 'literal',
+              'o_lang' => $ct['cur_obj_literal']['datatype'] ? '' : $ct['cur_obj_literal']['lang'],
+              'o_datatype' => $ct['cur_obj_literal']['datatype'],
+            );
+            if (($o = $this->v('src uri', '', $n['a'])) || ($o = $this->v('href uri', '', $n['a']))) {
+              if (!$ct['prop_uris']['rel'] && !$ct['prop_uris']['rev']) {
+                $t['o'] = $o;
+                $t['o_type'] = 'uri';
+                $t['o_lang'] = '';
+                $t['o_datatype'] = '';
+              }
+            }
+          }
+          $this->addT($t);
+        }
+        /* rel */
+        if ($type == 'rel') {
+          if (($o = $this->v('src uri', '', $n['a'])) || ($o = $this->v('href uri', '', $n['a']))) {
+            $t = array(
+              's' => $ct['cur_res'],
+              's_type' => 'uri',
+              'p' => $uri, 
+              'o' => $o,
+              'o_type' => 'uri',
+              'o_lang' => '',
+              'o_datatype' => '',
+            );
+            $this->addT($t);
+          }
+        }
+        /* rev */
+        if ($type == 'rev') {
+          if (($s = $this->v('src uri', '', $n['a'])) || ($s = $this->v('href uri', '', $n['a']))) {
+            $t = array(
+              's' => $s,
+              's_type' => 'uri',
+              'p' => $uri, 
+              'o' => $ct['cur_res'],
+              'o_type' => 'uri',
+              'o_lang' => '',
+              'o_datatype' => '',
+            );
+            $this->addT($t);
+          }
+        }
+      }
+    }
+    /* imgs */
+    if ($n['tag'] == 'img') {
+      if (($s = $this->v('src uri', '', $n['a'])) && $ct['cur_obj_literal']['value']) {
+        $t = array(
+          's' => $s,
+          's_type' => 'uri',
+          'p' => $ct['ns']['rdfs'] . 'label', 
+          'o' => $ct['cur_obj_literal']['value'],
+          'o_type' => 'literal',
+          'o_lang' => $ct['cur_obj_literal']['datatype'] ? '' : $ct['cur_obj_literal']['lang'],
+          'o_datatype' => $ct['cur_obj_literal']['datatype'],
+        );
+        $this->addT($t);
+      }
+    }
+    /* anchors */
+    if ($n['tag'] == 'a') {
+      if (($s = $this->v('href uri', '', $n['a'])) && $ct['cur_obj_literal']['value']) {
+        $t = array(
+          's' => $s,
+          's_type' => 'uri',
+          'p' => $ct['ns']['rdfs'] . 'label', 
+          'o' => $ct['cur_obj_literal']['value'],
+          'o_type' => 'literal',
+          'o_lang' => $ct['cur_obj_literal']['datatype'] ? '' : $ct['cur_obj_literal']['lang'],
+          'o_datatype' => $ct['cur_obj_literal']['datatype'],
+        );
+        $this->addT($t);
+      }
+    }
+    /* recurse */
+    if ($n['tag'] == 'a') {
+      $ct['cur_res'] = $ct['cur_obj_id'];
+    }
+    $sub_nodes = $this->getSubNodes($n);
+    foreach ($sub_nodes as $sub_node) {
+      $this->processNode($sub_node, $ct);
+    }
+  }
+
+  /*  */
+  
+  function getPropertyURIs($n, $ct) {
+    $r = array();
+    foreach (array('rel', 'rev', 'class', 'name', 'src') as $type) {
+      $r[$type] = array();
+      $vals = $this->v($type . ' m', array(), $n['a']);
+      foreach ($vals as $val) {
+        if (!trim($val)) continue;
+        list($uri, $sub_v) = $this->xQname(trim($val, '- '), $ct['base'], $ct['ns'], $type);
+        if (!$uri) continue;
+        $rdf_type = preg_match('/^-/', trim($val)) ? 1 : 0;
+        $r[$type][] = $rdf_type ? ' ' . $uri : $uri;
+      }
+    }
+    return $r;
+  }
+
+  function getCurrentResourceURI($n, $ct) {
+    if (isset($n['a']['id'])) {
+      list($r, $sub_v) = $this->xURI('#' . $n['a']['id'], $ct['base'], $ct['ns']);
+      return $r;
+    }
+    return $ct['cur_res'];
+  }
+  
+  function getCurrentObjectID($n, $ct) {
+    foreach (array('href', 'src') as $a) {
+      if (isset($n['a'][$a])) {
+        list($r, $sub_v) = $this->xURI($n['a'][$a], $ct['base'], $ct['ns']);
+        return $r;
+      }
+    }
+    return $this->createBnodeID();
+  }
+
+  function getCurrentObjectLiteral($n, $ct) {
+    $r = array('value' => '', 'lang' => $ct['lang'], 'datatype' => '');
+    if (isset($n['a']['content'])) {
+      $r['value'] = $n['a']['content'];
+    }
+    elseif (isset($n['a']['title'])) {
+      $r['value'] = $n['a']['title'];
+    }
+    else {
+      $r['value'] = $this->getPlainContent($n);
+    }
+    return $r;
+  }
+  
+  /*  */
+  
+  function xURI($v, $base, $ns, $attr_type = '') {
+    if ((list($sub_r, $sub_v) = $this->xQname($v, $base, $ns)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    if (preg_match('/^(rel|rev|class|name)$/', $attr_type) && preg_match('/^[a-z0-9]+$/', $v)) {
+      return array(0, $v);
+    }
+    return array($this->calcURI($v, $base), '');
+  }
+  
+  function xQname($v, $base, $ns) {
+    if ($sub_r = $this->x('([a-z0-9\-\_]+)[\-\.]([a-z0-9\-\_]+)', $v)) {
+      if (isset($ns[$sub_r[1]])) {
+        return array($ns[$sub_r[1]] . $sub_r[2], '');
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/extractors/ARC2_MicroformatsExtractor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,178 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 microformats Extractor
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('ARC2_PoshRdfExtractor');
+
+class ARC2_MicroformatsExtractor extends ARC2_PoshRdfExtractor {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->terms = $this->getTerms();
+    $this->ns_prefix = 'mf';
+    $this->a['ns']['mf'] = 'http://poshrdf.org/ns/mf#';
+    $this->caller->detected_formats['posh-rdf'] = 1;
+  }
+
+  /*  */
+  
+  function preProcessNode($n) {
+    if (!$n) return $n;
+    /* remove existing poshRDF hooks */
+    if (!is_array($n['a'])) $n['a'] = array();
+    $n['a']['class'] = isset($n['a']['class']) ? preg_replace('/\s?rdf\-(s|p|o|o-xml)/', '', $n['a']['class']): '';
+    if (!isset($n['a']['rel'])) $n['a']['rel'] = '';
+    /* inject poshRDF hooks */
+    foreach ($this->terms as $term => $infos) {
+      if ((!in_array('rel', $infos) && $this->hasClass($n, $term)) || $this->hasRel($n, $term)) {
+        if ($this->v('scope', '', $infos)) $infos[] = 'p';
+        foreach (array('s', 'p', 'o', 'o-xml') as $type) {
+          if (in_array($type, $infos)) {
+            $n['a']['class'] .= ' rdf-' . $type;
+            $n['a']['class'] = preg_replace('/(^|\s)' . $term . '(\s|$)/s', '\\1mf-' . $term . '\\2', $n['a']['class']);
+            $n['a']['rel'] = preg_replace('/(^|\s)' . $term . '(\s|$)/s', '\\1mf-' . $term . '\\2', $n['a']['rel']);
+          }
+        }
+      }
+    }
+    $n['a']['class m'] = preg_split('/ /', $n['a']['class']);
+    $n['a']['rel m'] = preg_split('/ /', $n['a']['rel']);
+    return $n;
+  }
+  
+  function getPredicates($n, $ns) {
+    $ns = array('mf' => $ns['mf']);
+    return parent::getPredicates($n, $ns);
+  }
+  
+  function tweakObject($o, $p, $ct) {
+    $ns = $ct['ns']['mf'];
+    /* rel-tag, skill => extract from URL */
+    if (in_array($p, array($ns . 'tag', $ns . 'skill'))) {
+      $o = preg_replace('/^.*\/([^\/]+)/', '\\1', trim($o, '/'));
+      $o = urldecode(rawurldecode($o));
+    }
+    return $o;
+  }
+  
+  /*  */
+  
+  function getTerms() {
+    /* no need to define 'p' if scope is not empty */
+    return array(
+      'acquaintance' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'additional-name' => array('o', 'scope' => array('n')),
+      'adr' => array('s', 'o', 'scope' => array('_doc', 'vcard')),
+      'affiliation' => array('s', 'o', 'scope' => array('hresume')),
+      'author' => array('s', 'o', 'scope' => array('hentry')),
+      'bday' => array('o', 'scope' => array('vcard')),
+      'bio' => array('o', 'scope' => array('vcard')),
+      'best' => array('o', 'scope' => array('hreview')),
+      'bookmark' => array('o', 'scope' => array('_doc', 'hentry', 'hreview')),
+      'class' => array('o', 'scope' => array('vcard', 'vevent')),
+      'category' => array('o', 's', 'scope' => array('vcard', 'vevent')),
+      'child' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'co-resident' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'co-worker' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'colleague' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'contact' => array('o', 'scope' => array('_doc', 'hresume', 'hentry')),
+      'country-name' => array('o', 'scope' => array('adr')),
+      'crush' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'date' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'description' => array('o', 'scope' => array('vevent', 'hreview', 'xfolkentry')),
+      'directory' => array('o', 'rel', 'scope' => array('_doc', 'hfeed', 'hentry', 'hreview')),
+      'dtend' => array('o', 'scope' => array('vevent')),
+      'dtreviewed' => array('o', 'scope' => array('hreview')),
+      'dtstamp' => array('o', 'scope' => array('vevent')),
+      'dtstart' => array('o', 'scope' => array('vevent')),
+      'duration' => array('o', 'scope' => array('vevent')),
+      'education' => array('s', 'o', 'scope' => array('hresume')),
+      'email' => array('s', 'o', 'scope' => array('vcard')),
+      'entry-title' => array('o', 'scope' => array('hentry')),
+      'entry-content' => array('o-xml', 'scope' => array('hentry')),
+      'entry-summary' => array('o', 'scope' => array('hentry')),
+      'experience' => array('s', 'o', 'scope' => array('hresume')),
+      'extended-address' => array('o', 'scope' => array('adr')),
+      'family-name' => array('o', 'scope' => array('n')),
+      'fn' => array('o', 'plain', 'scope' => array('vcard', 'item')),
+      'friend' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'geo' => array('s', 'scope' => array('_doc', 'vcard', 'vevent')),
+      'given-name' => array('o', 'scope' => array('n')),
+      'hentry' => array('s', 'o', 'scope' => array('_doc', 'hfeed')),
+      'hfeed' => array('s', 'scope' => array('_doc')),
+      'honorific-prefix' => array('o', 'scope' => array('n')),
+      'honorific-suffix' => array('o', 'scope' => array('n')),
+      'hresume' => array('s', 'scope' => array('_doc')),
+      'hreview' => array('s', 'scope' => array('_doc')),
+      'item' => array('s', 'scope' => array('hreview')),
+      'key' => array('o', 'scope' => array('vcard')),
+      'kin' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'label' => array('o', 'scope' => array('vcard')),
+      'last-modified' => array('o', 'scope' => array('vevent')),
+      'latitude' => array('o', 'scope' => array('geo')),
+      'license' => array('o', 'rel', 'scope' => array('_doc', 'hfeed', 'hentry', 'hreview')),
+      'locality' => array('o', 'scope' => array('adr')),
+      'location' => array('o', 'scope' => array('vevent')),
+      'logo' => array('o', 'scope' => array('vcard')),
+      'longitude' => array('o', 'scope' => array('geo')),
+      'mailer' => array('o', 'scope' => array('vcard')),
+      'me' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'met' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'muse' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'n' => array('s', 'o', 'scope' => array('vcard')),
+      'neighbor' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'nickname' => array('o', 'plain', 'scope' => array('vcard')),
+      'nofollow' => array('o', 'rel', 'scope' => array('_doc')),
+      'note' => array('o', 'scope' => array('vcard')),
+      'org' => array('o', 'xplain', 'scope' => array('vcard')),
+      'parent' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'permalink' => array('o', 'scope' => array('hreview')),
+      'photo' => array('o', 'scope' => array('vcard', 'item')),
+      'post-office-box' => array('o', 'scope' => array('adr')),
+      'postal-code' => array('o', 'scope' => array('adr')),
+      'publication' => array('s', 'o', 'scope' => array('hresume')),
+      'published' => array('o', 'scope' => array('hentry')),
+      'rating' => array('o', 'scope' => array('hreview')),
+      'region' => array('o', 'scope' => array('adr')),
+      'rev' => array('o', 'scope' => array('vcard')),
+      'reviewer' => array('s', 'o', 'scope' => array('hreview')),
+      'role' => array('o', 'plain', 'scope' => array('vcard')),
+      'sibling' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'skill' => array('o', 'scope' => array('hresume')),
+      'sort-string' => array('o', 'scope' => array('vcard')),
+      'sound' => array('o', 'scope' => array('vcard')),
+      'spouse' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'status' => array('o', 'plain', 'scope' => array('vevent')),
+      'street-address' => array('o', 'scope' => array('adr')),
+      'summary' => array('o', 'scope' => array('vevent', 'hreview', 'hresume')),
+      'sweetheart' => array('o', 'rel', 'scope' => array('_doc', 'hentry')),
+      'tag' => array('o', 'rel', 'scope' => array('_doc', 'category', 'hfeed', 'hentry', 'skill', 'hreview', 'xfolkentry')),
+      'taggedlink' => array('o', 'scope' => array('xfolkentry')),
+      'title' => array('o', 'scope' => array('vcard')),
+      'type' => array('o', 'scope' => array('adr', 'email', 'hreview', 'tel')),
+      'tz' => array('o', 'scope' => array('vcard')),
+      'uid' => array('o', 'scope' => array('vcard', 'vevent')),
+      'updated' => array('o', 'scope' => array('hentry')),
+      'url' => array('o', 'scope' => array('vcard', 'vevent', 'item')),
+      'value' => array('o', 'scope' => array('email', 'adr', 'tel')),
+      'vcard' => array('s', 'scope' => array('author', 'reviewer', 'affiliation', 'contact')),
+      'version' => array('o', 'scope' => array('hreview')),
+      'vevent' => array('s', 'scope' => array('_doc')),
+      'worst' => array('o', 'scope' => array('hreview')),
+      'xfolkentry' => array('s', 'scope' => array('_doc')),
+    );
+  }
+
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/extractors/ARC2_OpenidExtractor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,62 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 foaf:openid Extractor
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('RDFExtractor');
+
+class ARC2_OpenidExtractor extends ARC2_RDFExtractor {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->a['ns']['foaf'] = 'http://xmlns.com/foaf/0.1/';
+  }
+
+  /*  */
+  
+  function extractRDF() {
+    $t_vals = array();
+    $t = '';
+    foreach ($this->nodes as $n) {
+      if (isset($n['tag']) && $n['tag'] == 'link') {
+        $m = 'extract' . ucfirst($n['tag']);
+        list ($t_vals, $t) = $this->$m($n, $t_vals, $t);
+      }
+    }
+    if ($t) {
+      $doc = $this->getFilledTemplate($t, $t_vals, $n['doc_base']);
+      $this->addTs(ARC2::getTriplesFromIndex($doc));
+    }
+  }
+  
+  /*  */
+
+  function extractLink($n, $t_vals, $t) {
+    if ($this->hasRel($n, 'openid.server')) {
+      if ($href = $this->v('href uri', '', $n['a'])) {
+        $t_vals['doc_owner'] = $this->getDocOwnerID($n);
+        $t_vals['doc_id'] = $this->getDocID($n);
+        $t .= '?doc_owner foaf:homepage ?doc_id ; foaf:openid ?doc_id . ';
+      }
+    }
+    if ($this->hasRel($n, 'openid.delegate')) {
+      if ($href = $this->v('href uri', '', $n['a'])) {
+        $t_vals['doc_owner'] = $this->getDocOwnerID($n);
+        $t .= '?doc_owner foaf:homepage <' . $href . '> ; foaf:openid <' . $href . '> . ';
+      }
+    }
+    return array($t_vals, $t);
+  }
+  
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/extractors/ARC2_PoshRdfExtractor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,254 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 poshRDF Extractor
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('ARC2_RDFExtractor');
+
+class ARC2_PoshRdfExtractor extends ARC2_RDFExtractor {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->terms = $this->v('posh_terms', array(), $this->a);
+    $this->ns_prefix = 'posh';
+    $this->a['ns'] += array(
+      'an' => 'http://www.w3.org/2000/10/annotation-ns#',
+      'content' => 'http://purl.org/rss/1.0/modules/content/',
+      'dc' => 'http://purl.org/dc/elements/1.1/',
+      'dct' => 'http://purl.org/dc/terms/',
+      'foaf' => 'http://xmlns.com/foaf/0.1/',
+      'geo' => 'http://www.w3.org/2003/01/geo/wgs84_pos#',
+      'ical' => 'http://www.w3.org/2002/12/cal/icaltzd#',
+      'owl' => 'http://www.w3.org/2002/07/owl#',
+      'posh' => 'http://poshrdf.org/ns/posh/',
+      'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+      'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
+      'rev' => 'http://www.purl.org/stuff/rev#',
+      'rss' => 'http://purl.org/rss/1.0/',
+      'sioc' => 'http://rdfs.org/sioc/ns#',
+      'skos' => 'http://www.w3.org/2008/05/skos#',
+      'uri' => 'http://www.w3.org/2006/uri#',
+      'vcard' => 'http://www.w3.org/2006/vcard/ns#',
+      'xfn' => 'http://gmpg.org/xfn/11#',
+      'xml' => 'http://www.w3.org/XML/1998/namespace',
+      'xsd' => 'http://www.w3.org/2001/XMLSchema#',
+    );
+  }
+
+  /*  */
+  
+  function extractRDF() {
+    if (!isset($this->caller->detected_formats['posh-rdf'])) return 0;
+    $n = $this->getRootNode();
+    $base = $this->getDocBase();
+    $context = array(
+      'id' => $n['id'],
+      'tag' => $n['tag'],
+      'base' => $base,
+      's' => array(array('_doc', $base)),
+      'next_s' => array('_doc', $base),
+      'ps' => array(),
+      'ns' => $this->a['ns'],
+      'lang' => '',
+      'rpointer' => '',
+    );
+    $ct = $this->processNode($n, $context, 0, 1);
+  }
+  
+  /*  */
+
+  function getRootNode() {
+    foreach ($this->nodes as $id => $node) {
+      if ($node['tag'] == 'html') {
+        return $node;
+      }
+    }
+    return $this->nodes[0];
+  }
+  
+  /*  */
+
+  function processNode($n, $ct, $level, $pos) {
+    $n = $this->preProcessNode($n);
+    /* local context */
+    $lct = array_merge($ct, array(
+      'ns' => array_merge($ct['ns'], $this->v('xmlns', array(), $n['a'])),
+      'rpointer' => isset($n['a']['id']) ? $n['a']['id'] : ($n['tag'] == 'cdata' ? '' : $ct['rpointer'] . '/' . $pos),
+      'tag' => $n['tag'],
+      'id' => $n['id'],
+      'lang' => $this->v('xml:lang', $ct['lang'], $n['a']),
+    ));
+    /* s stack */
+    $next_s_key = $lct['next_s'][0];
+    $next_s_val = $lct['next_s'][1];
+    if ($lct['s'][0][0] != $next_s_key) {
+      $lct['s'] = array_merge(array($lct['next_s']), $lct['s']);
+    }
+    else {
+      $lct['s'][0][1] = $next_s_val;
+    }
+    /* new s */
+    if ($this->hasClass($n, 'rdf-s')) {
+      $lct['next_s'] = array($n['a']['class'], $this->getSubject($n, $lct));
+      //echo "\ns: " . print_r($lct['next_s'], 1);
+    }
+    /* p */
+    if ($this->hasClass($n, 'rdf-p') || $this->hasRel($n, 'rdf-p')) {
+      if ($ps = $this->getPredicates($n, $lct['ns'])) {
+        $lct['ps'] = $ps;
+        $this->addPoshTypes($lct);
+      }
+    }
+    /* o */
+    $cls = $this->v('class', '', $n['a']);
+    if ($lct['ps'] && preg_match('/(^|\s)rdf\-(o|o\-(xml|dateTime|float|integer|boolean))($|\s)/s', $cls, $m)) {
+      $this->addTriples($n, $lct, $m[3]);
+    }
+    /* sub-nodes */
+    if ($sub_nodes = $this->getSubNodes($n)) {
+      $cur_ct = $lct;
+      $sub_pos = 1;
+      foreach ($sub_nodes as $i => $sub_node) {
+        if (in_array($sub_node['tag'], array('cdata', 'comment'))) continue;
+        $sub_ct = $this->processNode($sub_node, $cur_ct, $level + 1, $sub_pos);
+        $sub_pos++;
+        $cur_ct['next_s'] = $sub_ct['next_s'];
+        $cur_ct['ps'] = $sub_ct['ps'];
+      }
+    }
+    return $lct;
+  }
+  
+  /*  */
+  
+  function getSubject($n, $ct) {
+    foreach (array('href uri', 'src uri', 'title', 'value') as $k) {
+      if (isset($n['a'][$k])) return $n['a'][$k];
+    }
+    /* rpointer */
+    return $ct['base'] . '#resource(' . $ct['rpointer'] . ')';
+  }
+  
+  function getPredicates($n, $ns) {
+    $r = array();
+    /* try pnames */
+    $vals = array_merge($this->v('class m', array(), $n['a']), $this->v('rel m', array(), $n['a']));
+    foreach ($vals as $val) {
+      if (!preg_match('/^([a-z0-9]+)\-([a-z0-9\-\_]+)$/i', $val, $m)) continue;
+      if (!isset($ns[$m[1]])) continue;
+      if (preg_match('/^rdf-(s|p|o|o-(xml|dateTime|float|integer|boolean))$/', $val)) continue;
+      $r[] = $ns[$m[1]] . $m[2];
+    }
+    /* try other attributes */
+    if (!$r) {
+      foreach (array('href uri', 'title') as $k) {
+        if (isset($n['a'][$k])) {
+          $r[] = $n['a'][$k];
+          break;
+        }
+      }
+    }
+    return $r;
+  }
+
+  function addTriples($n, $ct, $o_type) {
+    foreach (array('href uri', 'src uri', 'title', 'value') as $k) {
+      if (isset($n['a'][$k])) {
+        $node_o = $n['a'][$k];
+        break;
+      }
+    }
+    if (!isset($node_o) && $this->hasClass($n, 'rdf-s')) {
+      $node_o = $ct['next_s'][1];
+    }
+    $lit_o = ($o_type == 'xml') ? $this->getContent($n) : $this->getPlainContent($n);
+    $posh_ns = $ct['ns'][$this->ns_prefix];
+    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $xsd = 'http://www.w3.org/2001/XMLSchema#';
+    foreach ($ct['ps'] as $p) {
+      $p_key = str_replace($posh_ns, '', $p);
+      /* dt or obj */
+      $o = $this->isDatatypeProperty($p_key) ? $lit_o : (isset($node_o) ? $node_o : $lit_o);
+      if (!$o) continue;
+      if (!$s = $this->getContainerSubject($ct, $p_key)) continue;
+      $lang = (($o == $lit_o) && !$o_type) ? $ct['lang'] : '';
+      $o = $this->tweakObject($o, $p, $ct);
+      $this->addT(array(
+        's' => $this->getContainerSubject($ct, $p_key),
+        's_type' => preg_match('/^\_\:/', $s) ? 'bnode' : 'uri',
+        'p' => $p, 
+        'o' => $o,
+        'o_type' => $this->getObjectType($o, $p_key),
+        'o_lang' => $lang,
+        'o_datatype' => ($o_type == 'xml') ? $rdf . 'XMLLiteral' : ($o_type ? $xsd . $o_type : ''),
+      ));
+    }
+  }
+
+  function addPoshTypes($ct) {
+    $posh_ns = $ct['ns'][$this->ns_prefix];
+    foreach ($ct['ps'] as $p) {
+      $p_key = str_replace($posh_ns, '', $p);
+      if (!$this->isSubject($p_key)) continue;
+      $s = $ct['next_s'][1];
+      $this->addT(array(
+        's' => $s,
+        's_type' => preg_match('/^\_\:/', $s) ? 'bnode' : 'uri',
+        'p' => $ct['ns']['rdf'] . 'type', 
+        'o' => $posh_ns . ucfirst($p_key),
+        'o_type' => 'uri',
+        'o_lang' => '',
+        'o_datatype' => '',
+      ));
+    }
+  }
+  
+  /*  */
+  
+  function preProcessNode($n) {
+    return $n;
+  }
+  
+  function getContainerSubject($ct, $term) {
+    if (!isset($this->terms[$term])) return $ct['s'][0][1];
+    $scope = $this->v('scope', array(), $this->terms[$term]);
+    if (!$scope) return $ct['s'][0][1];
+    $scope_re = join('|', $scope);
+    foreach ($ct['s'] as $s) {
+      if (preg_match('/(^|\s)(' . $scope_re. ')($|\s)/s', str_replace($this->ns_prefix . '-', '', $s[0]))) return $s[1];
+    }
+    return 0;
+  }
+  
+  function isSubject($term) {
+    if (!isset($this->terms[$term])) return 0;
+    return in_array('s', $this->terms[$term]);
+  }
+  
+  function isDatatypeProperty($term) {
+    if (!isset($this->terms[$term])) return 0;
+    return in_array('plain', $this->terms[$term]);
+  }
+  
+  function getObjectType($o, $term) {
+    if ($this->isDatatypeProperty($term)) return 'literal';
+    if (strpos($o, ' ')) return 'literal';
+    return preg_match('/^([a-z0-9\_]+)\:[^\s]+$/s', $o, $m) ? ($m[1] == '_' ? 'bnode' : 'uri') : 'literal';
+  }
+  
+  function tweakObject($o, $p, $ct) {
+    return $o;
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/extractors/ARC2_RDFExtractor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,237 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 RDF Extractor
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_RDFExtractor extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->nodes = $this->caller->getNodes();
+    $this->index = $this->caller->getNodeIndex();
+    $this->bnode_prefix = $this->v('bnode_prefix', 'arc' . substr(md5(uniqid(rand())), 0, 4) . 'b', $this->a);
+    $this->bnode_id = 0;
+    $this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
+    if (!isset($this->a['ns'])) $this->a['ns'] = array('rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
+  }
+
+  /*  */
+  
+  function x($re, $v, $options = 'si') {
+    return ARC2::x($re, $v, $options);
+  }
+
+  function createBnodeID(){
+    $this->bnode_id++;
+    return '_:' . $this->bnode_prefix . $this->bnode_id;
+  }
+
+  /*  */
+  
+  function extractRDF() {
+  }
+
+  /*  */
+  
+  function addTs($ts) {
+    foreach ($ts as $t) {
+      $this->caller->addT($t);
+    }
+  }
+  
+  function addT($t) {
+    return $this->caller->addT($t);
+  }
+  
+  /*  */
+  
+  function getSubNodes($n) {
+    return $this->v($n['id'], array(), $this->index);
+  }
+  
+  function getParentNode($n) {
+    return isset($this->nodes[$n['p_id']]) ? $this->nodes[$n['p_id']] : 0;
+  }
+
+  /*  */
+  
+  function getSubNodesByClass($n, $cls, $skip_self = 0) {
+    if (!$skip_self && $this->hasClass($n, $cls)) {
+      return array($n);
+    }
+    $r = array();
+    $sns = $this->getSubNodes($n);
+    foreach ($sns as $sn) {
+      if ($sub_r = $this->getSubNodesByClass($sn, $cls, 0)) {
+        $r = array_merge($r, $sub_r);
+      }
+    }
+    return $r;
+  }
+  
+  function getSubNodeByClass($n, $cls, $skip_self = 0) {
+    if (!$skip_self && $this->hasClass($n, $cls)) {
+      return $n;
+    }
+    $sns = $this->getSubNodes($n);
+    foreach ($sns as $sn) {
+      if ($sub_r = $this->getSubNodeByClass($sn, $cls, 0)) {
+        return $sub_r;
+      }
+    }
+    return 0;
+  }
+  
+  function getParentNodeByClass($n, $cls, $skip_self = 0) {
+    if (!$skip_self && $this->hasClass($n, $cls)) {
+      return $n;
+    }
+    if ($pn = $this->getParentNode($n)) {
+      if ($sub_r = $this->getParentNodeByClass($pn, $cls, 0)) {
+        return $sub_r;
+      }
+    }
+    return 0;
+  }
+  
+  /*  */
+  
+  function hasAttribute($a, $n, $v) {
+    $vs = is_array($v) ? $v : array($v);
+    $a_vs = $this->v($a . ' m', array(), $n['a']);
+    return array_intersect($vs, $a_vs) ? 1 : 0;
+  }
+  
+  function hasClass($n, $v) {
+    return $this->hasAttribute('class', $n, $v);
+  }
+
+  function hasRel($n, $v) {
+    return $this->hasAttribute('rel', $n, $v);
+  }
+
+  /*  */
+
+  function getDocBase() {
+    $root_node = $this->getRootNode();
+    $r = $root_node['doc_base'];
+    foreach ($this->getSubNodes($root_node) as $root_child) {
+      if ($root_child['tag'] == 'head') {
+        foreach ($this->getSubNodes($root_child) as $head_child) {
+          if ($head_child['tag'] == 'base') {
+            $r = $head_child['a']['href'];
+            break;
+          }
+        }
+      }
+    }
+    return $r;
+  }
+  
+  /*  */
+  
+  function getPlainContent($n, $trim = 1, $use_img_alt = 1) {
+    if ($n['tag'] == 'comment') {
+      $r = '';
+    }
+    elseif ($n['tag'] == 'cdata') {
+      $r = $n['a']['value'];
+    }
+    elseif (trim($this->v('cdata', '', $n))) {
+      $r = $n['cdata'];
+      $sub_nodes = $this->getSubNodes($n);
+      foreach ($sub_nodes as $sub_n) {
+        $r .= $this->getPlainContent($sub_n, 0, $use_img_alt);
+      }
+    }
+    elseif (($n['tag'] == 'img') && $use_img_alt && isset($n['a']['alt'])) {
+      $r = $n['a']['alt'];
+    }
+    else {
+      $r = '';
+      $sub_nodes = $this->getSubNodes($n);
+      foreach ($sub_nodes as $sub_n) {
+        $r .= $this->getPlainContent($sub_n, 0, $use_img_alt);
+      }
+    }
+    $r = preg_replace('/\s/s', ' ', $r);
+    $r = preg_replace('/\s\s*/s', ' ', $r);
+    return $trim ? trim($r) : $r;
+  }
+  
+  function getContent($n, $outer = 0, $trim = 1) {
+    //echo '<pre>' . htmlspecialchars(print_r($n, 1)) . '</pre>';
+    if ($n['tag'] == 'comment') {
+      $r = '<!-- ' . $n['a']['value'] . ' -->';
+    }
+    elseif ($n['tag'] == 'cdata') {
+      $r = $n['a']['value'];
+    }
+    else {
+      $r = '';
+      if ($outer) {
+        $r .= '<' . $n['tag'];
+        asort($n['a']);
+        if (isset($n['a']['xmlns']) && $n['a']['xmlns']['']) {
+          $r .= ' xmlns="' . $n['a']['xmlns'][''] . '"';
+        }
+        foreach ($n['a'] as $a => $val) {
+          if (!is_array($val) && isset($n['a'][$a . ' uri'])) $val = $n['a'][$a . ' uri'];
+          $r .= preg_match('/^[^\s]+$/', $a) && !is_array($val) ? ' ' . $a . '="' . addslashes($val) . '"' : '';
+        }
+        $r .= $n['empty'] ? '/>' : '>';
+      }
+      if (!$n['empty']) {
+        $r .= $this->v('cdata', '', $n);
+        $sub_nodes = $this->getSubNodes($n);
+        foreach ($sub_nodes as $sub_n) {
+          $r .= $this->getContent($sub_n, 1, 0);
+        }
+        if ($outer) {
+          $r .= '</' . $n['tag'] . '>';
+        }
+      }
+    }
+    return ($trim && !$this->keep_cdata_ws) ? trim($r) : $r;
+  }
+  
+  /*  */
+  
+  function getDocID($n) {
+    $id = $n['id'];
+    $k = 'doc_' . $id;
+    if (!isset($this->caller->cache[$k])) {
+      $this->caller->cache[$k] = $n['doc_url'];
+    }
+    return $this->caller->cache[$k];
+  }
+
+  function getDocOwnerID($n) {
+    return '_:owner_of_' . $this->normalize($this->getDocID($n));
+  }
+  
+  /*  */
+
+  function normalize($v) {
+    $v = preg_replace('/[\W\s]+/is', '_', strip_tags(strtolower($v)));
+    $v = preg_replace('/http/', '', $v);
+    $v = preg_replace('/[\_]+/', '_', $v);
+    //$v = substr($v, 0, 30);
+    $v = trim($v, '_');
+    return $v;
+  }
+
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/extractors/ARC2_RdfaExtractor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,385 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 RDFa Extractor
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('RDFExtractor');
+
+class ARC2_RdfaExtractor extends ARC2_RDFExtractor {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function extractRDF() {
+    //echo '<pre>' . htmlspecialchars(print_r($this->nodes, 1)) . '</pre>';
+    if (!isset($this->caller->detected_formats['rdfa'])) return 0;
+    $root_node = $this->getRootNode();
+    //$base = $this->v('xml:base', $this->getDocBase(), $root_node['a']);
+    $base = $this->getDocBase();
+    $context = array(
+      'base' => $base,
+      'p_s' => $base,
+      'p_o' => '',
+      'ns' => array(),
+      'inco_ts' => array(),
+      'lang' => '',
+    );
+    $this->processNode($root_node, $context, 0);
+  }
+  
+  /*  */
+  
+  function getRootNode() {
+    foreach ($this->nodes as $id => $node) {
+      if ($node['tag'] == 'html') {
+        return $node;
+      }
+    }
+    return $this->nodes[0];
+  }
+  
+  /*  */
+
+  function processNode($n, $ct, $level) {
+    if ($n['tag']=='cdata' || $n['tag']=='comment') return null; /* patch by tobyink */
+    $ts_added = 0;
+    /* step 1 */
+    $lct = array();
+    $lct['prev_s'] = $this->v('prev_s', $this->v('p_s', '', $ct), $ct);
+    $lct['recurse'] = 1;
+    $lct['skip'] = 0;
+    $lct['new_s'] = '';
+    $lct['cur_o_res'] = '';
+    $lct['inco_ts'] = array();
+    $lct['base'] = $ct['base'];
+    //$lct['base'] = $this->v('xml:base', $ct['base'], $n['a']);
+    /* step 2 */
+    $lct['ns'] = array_merge($ct['ns'], $this->v('xmlns', array(), $n['a']));
+    /* step 3 */
+    $lct['lang'] = $this->v('xml:lang', $ct['lang'], $n['a']);
+    /* step 4 */
+    $rel_uris = $this->getAttributeURIs($n, $ct, $lct, 'rel');
+    $rev_uris = $this->getAttributeURIs($n, $ct, $lct, 'rev');
+    if (!$rel_uris && !$rev_uris) {
+      foreach (array('about', 'src', 'resource', 'href') as $attr) {
+        if (isset($n['a'][$attr]) && (list($uri, $sub_v) = $this->xURI($n['a'][$attr], $lct['base'], $lct['ns'], '', $lct)) && $uri) {
+          $lct['new_s'] = $uri;
+          break;
+        }
+      }
+      if (!$lct['new_s']) {
+        if (preg_match('/(head|body)/i', $n['tag'])) {
+          $lct['new_s'] = $lct['base'];
+        }
+        elseif ($this->getAttributeURIs($n, $ct, $lct, 'typeof')) {
+          $lct['new_s'] = $this->createBnodeID();
+        }
+        elseif ($ct['p_o']) {
+          $lct['new_s'] = $ct['p_o'];
+          //$lct['skip'] = 1;
+          if(!isset($n['a']['property'])) $lct['skip'] = 1;/* patch by masaka */
+        }
+      }
+    }
+    /* step 5 */
+    else {
+      foreach (array('about', 'src') as $attr) {
+        if (isset($n['a'][$attr]) && (list($uri, $sub_v) = $this->xURI($n['a'][$attr], $lct['base'], $lct['ns'], '', $lct)) && $uri) {
+          $lct['new_s'] = $uri;
+          break;
+        }
+      }
+      if (!$lct['new_s']) {
+        if (preg_match('/(head|body)/i', $n['tag'])) {
+          $lct['new_s'] = $lct['base'];
+        }
+        elseif ($this->getAttributeURIs($n, $ct, $lct, 'typeof')) {
+          $lct['new_s'] = $this->createBnodeID();
+        }
+        elseif ($ct['p_o']) {
+          $lct['new_s'] = $ct['p_o'];
+        }
+      }
+      foreach (array('resource', 'href') as $attr) {
+        if (isset($n['a'][$attr]) && (list($uri, $sub_v) = $this->xURI($n['a'][$attr], $lct['base'], $lct['ns'], '', $lct)) && $uri) {
+          $lct['cur_o_res'] = $uri;
+          break;
+        }
+      }
+    }
+    /* step 6 */
+    if ($lct['new_s']) {
+      if ($uris = $this->getAttributeURIs($n, $ct, $lct, 'typeof')) {
+        foreach ($uris as $uri) {
+          $this->addT(array(
+            's' => $lct['new_s'],
+            's_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
+            'p' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', 
+            'o' => $uri,
+            'o_type' => 'uri',
+            'o_lang' => '',
+            'o_datatype' => '',
+          ));
+          $ts_added = 1;
+        }
+      }
+      /* step 7 */
+      if ($lct['cur_o_res']) {
+        if ($rel_uris) {
+          foreach ($rel_uris as $uri) {
+            $this->addT(array(
+              's' => $lct['new_s'],
+              's_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
+              'p' => $uri, 
+              'o' => $lct['cur_o_res'],
+              'o_type' => preg_match('/^\_\:/', $lct['cur_o_res']) ? 'bnode' : 'uri',
+              'o_lang' => '',
+              'o_datatype' => '',
+            ));
+            $ts_added = 1;
+          }
+        }
+        if ($rev_uris) {
+          foreach ($rev_uris as $uri) {
+            $this->addT(array(
+              's' => $lct['cur_o_res'],
+              's_type' => preg_match('/^\_\:/', $lct['cur_o_res']) ? 'bnode' : 'uri',
+              'p' => $uri, 
+              'o' => $lct['new_s'],
+              'o_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
+              'o_lang' => '',
+              'o_datatype' => '',
+            ));
+            $ts_added = 1;
+          }
+        }
+      }
+    }
+    /* step 8 */
+    if (!$lct['cur_o_res']) {
+      if ($rel_uris || $rev_uris) {
+        $lct['cur_o_res'] = $this->createBnodeID();
+        foreach ($rel_uris as $uri) {
+          $lct['inco_ts'][] = array('p' => $uri, 'dir' => 'fwd');
+        }
+        foreach ($rev_uris as $uri) {
+          $lct['inco_ts'][] = array('p' => $uri, 'dir' => 'rev');
+        }
+      }
+    }
+    /* step 10 */
+    if (!$lct['skip'] && ($new_s = $lct['new_s'])) {
+    //if ($new_s = $lct['new_s']) {
+      if ($uris = $this->getAttributeURIs($n, $ct, $lct, 'property')) {
+        foreach ($uris as $uri) {
+          $lct['cur_o_lit'] = $this->getCurrentObjectLiteral($n, $lct, $ct);
+          $this->addT(array(
+            's' => $lct['new_s'],
+            's_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
+            'p' => $uri, 
+            'o' => $lct['cur_o_lit']['value'],
+            'o_type' => 'literal',
+            'o_lang' => $lct['cur_o_lit']['lang'],
+            'o_datatype' => $lct['cur_o_lit']['datatype'],
+          ));
+          $ts_added = 1;
+          if ($lct['cur_o_lit']['datatype'] == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') {
+            $lct['recurse'] = 0;
+          }
+        }
+      }
+    }
+    /* step 11 (10) */
+    $complete_triples = 0;
+    if ($lct['recurse']) {
+      if ($lct['skip']) {
+        $new_ct = array_merge($ct, array('base' => $lct['base'], 'lang' => $lct['lang'], 'ns' => $lct['ns']));
+      }
+      else {
+        $new_ct = array(
+          'base' => $lct['base'],
+          'p_s' => $lct['new_s'] ? $lct['new_s'] : $ct['p_s'],
+          'p_o' => $lct['cur_o_res'] ? $lct['cur_o_res'] : ($lct['new_s'] ? $lct['new_s'] : $ct['p_s']),
+          'ns' => $lct['ns'],
+          'inco_ts' => $lct['inco_ts'],
+          'lang' => $lct['lang']
+        );
+      }
+      $sub_nodes = $this->getSubNodes($n);
+      foreach ($sub_nodes as $sub_node) {
+        if ($this->processNode($sub_node, $new_ct, $level+1)) {
+          $complete_triples = 1;
+        }
+      }
+    }
+    /* step 12 (11) */
+    $other = 0;
+    if ($ts_added || $complete_triples || ($lct['new_s'] && !preg_match('/^\_\:/', $lct['new_s'])) || ($other == 1)) {
+    //if (!$lct['skip'] && ($complete_triples || ($lct['new_s'] && !preg_match('/^\_\:/', $lct['new_s'])))) {
+      foreach ($ct['inco_ts'] as $inco_t) {
+        if ($inco_t['dir'] == 'fwd') {
+          $this->addT(array(
+            's' => $ct['p_s'],
+            's_type' => preg_match('/^\_\:/', $ct['p_s']) ? 'bnode' : 'uri',
+            'p' => $inco_t['p'],
+            'o' => $lct['new_s'],
+            'o_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
+            'o_lang' => '',
+            'o_datatype' => '',
+          ));
+        }
+        elseif ($inco_t['dir'] == 'rev') {
+          $this->addT(array(
+            's' => $lct['new_s'],
+            's_type' => preg_match('/^\_\:/', $lct['new_s']) ? 'bnode' : 'uri',
+            'p' => $inco_t['p'], 
+            'o' => $ct['p_s'],
+            'o_type' => preg_match('/^\_\:/', $ct['p_s']) ? 'bnode' : 'uri',
+            'o_lang' => '',
+            'o_datatype' => '',
+          ));
+        }
+      }
+    }
+    /* step 13 (12) (result flag) */
+    if ($ts_added) return 1;
+    if ($lct['new_s'] && !preg_match('/^\_\:/', $lct['new_s'])) return 1;
+    if ($complete_triples) return 1;
+    return 0;
+  }
+  
+  /*  */
+
+  function getAttributeURIs($n, $ct, $lct, $attr) {
+    $vals = ($val = $this->v($attr, '', $n['a'])) ? explode(' ', $val) : array();
+    $r = array();
+    foreach ($vals as $val) {
+      if(!trim($val)) continue;
+      if ((list($uri, $sub_v) = $this->xURI(trim($val), $lct['base'], $lct['ns'], $attr, $lct)) && $uri) {
+        $r[] = $uri;
+      }
+    }
+    return $r;
+  }
+  
+  /*  */
+
+  function getCurrentObjectLiteral($n, $lct, $ct) {
+    $xml_val = $this->getContent($n);
+    $plain_val = $this->getPlainContent($n, 0, 0);
+    if (function_exists('html_entity_decode')) {
+      $plain_val = html_entity_decode($plain_val, ENT_QUOTES);
+    }
+    $dt = $this->v('datatype', '', $n['a']);
+    list($dt_uri, $sub_v) = $this->xURI($dt, $lct['base'], $lct['ns'], '', $lct);
+    $dt = $dt ? $dt_uri : $dt;
+    $r = array('value' => '', 'lang' => $lct['lang'], 'datatype' => $dt);
+    if (isset($n['a']['content'])) {
+      $r['value'] = $n['a']['content'];
+      if (function_exists('html_entity_decode')) {
+        $r['value'] = html_entity_decode($r['value'], ENT_QUOTES);
+      }
+    }
+    elseif ($xml_val == $plain_val) {
+      $r['value'] = $plain_val;
+    }
+    elseif (!preg_match('/[\<\>]/', $xml_val)) {
+      $r['value'] = $xml_val;
+    }
+    elseif (isset($n['a']['datatype']) && ($dt != 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral')) {
+      $r['value'] = $plain_val;
+    }
+    elseif (!isset($n['a']['datatype']) || ($dt == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral')) {
+      $r['value'] = $this->injectXMLDeclarations($xml_val, $lct['ns'], $lct['lang']);
+      $r['datatype'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral';
+    }
+    return $r;
+  }
+  
+  function injectXMLDeclarations($val, $ns, $lang) {//@@todo proper node rebuilding */
+    $lang_code = $lang ? ' xml:lang="' . $lang . '"' : '';
+    /* ns */
+    $val = preg_replace('/<([a-z0-9]+)([\>\s])/is', '<\\1 xmlns="http://www.w3.org/1999/xhtml"' . $lang_code . '\\2', $val);
+    foreach ($ns as $prefix => $uri) {
+      if ($prefix && ($pos = strpos(' ' . $val, '<' . $prefix . ':'))) {
+        $val = substr($val, 0, $pos - 1) . preg_replace('/^(<' . $prefix . '\:[^\>\s]+)/', '\\1 xmlns:' . $prefix. '="' . $uri . '"' . $lang_code, substr($val, $pos - 1));
+      }
+    }
+    /* remove accidentally added xml:lang and xmlns= */
+    $val = preg_replace('/(\<[^\>]*)( xml\:lang[^\s\>]+)([^\>]*)(xml\:lang[^\s\>]+)/s', '\\1\\3\\4', $val);
+    $val = preg_replace('/(\<[^\>]*)( xmlns=[^\s\>]+)([^\>]*)(xmlns=[^\s\>]+)/s', '\\1\\3\\4', $val);
+    return $val;
+  }
+  
+  /*  */
+  
+  function xURI($v, $base, $ns, $attr_type = '', $lct = '') {
+    if ((list($sub_r, $sub_v) = $this->xBlankCURIE($v, $base, $ns)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    if ((list($sub_r, $sub_v) = $this->xSafeCURIE($v, $base, $ns, $lct)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    if ((list($sub_r, $sub_v) = $this->xCURIE($v, $base, $ns)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    if (preg_match('/^(rel|rev)$/', $attr_type) && preg_match('/^\s*(alternate|appendix|bookmark|cite|chapter|contents|copyright|glossary|help|icon|index|last|license|meta|next|p3pv1|prev|role|section|stylesheet|subsection|start|up)(\s|$)/is', $v, $m)) {
+      return array('http://www.w3.org/1999/xhtml/vocab#' . strtolower($m[1]), preg_replace('/^\s*' . $m[1]. '/is', '', $v));
+    }
+    if (preg_match('/^(rel|rev)$/', $attr_type) && preg_match('/^[a-z0-9\.]+$/i', $v)) {
+      return array(0, $v);
+    }
+    return array($this->calcURI($v, $base), '');
+  }
+  
+  function xBlankCURIE($v, $base, $ns) {
+    if ($sub_r = $this->x('\[\_\:\]', $v)) {
+      $this->empty_bnode = isset($this->empty_bnode) ? $this->empty_bnode : $this->createBnodeID();
+      return array($this->empty_bnode, '');
+    }
+    if ($sub_r = $this->x('\[?(\_\:[a-z0-9\_\-]+)\]?', $v)) {
+      return array($sub_r[1], '');
+    }
+    return array(0, $v);
+  }
+  
+  function xSafeCURIE($v, $base, $ns, $lct = '') {
+    /* empty */
+    if ($sub_r = $this->x('\[\]', $v)) {
+      $r = $lct ? $lct['prev_s'] : $base;/* should be current subject value */
+      return $sub_r[1] ? array($r, $sub_r[1]) : array($r, '');
+    }
+    if ($sub_r = $this->x('\[([^\:]*)\:([^\]]*)\]', $v)) {
+      if (!$sub_r[1]) return array('http://www.w3.org/1999/xhtml/vocab#' . $sub_r[2], '');
+      if (isset($ns[$sub_r[1]])) {
+        return array($ns[$sub_r[1]] . $sub_r[2], '');
+      }
+    }
+    return array(0, $v);
+  }
+  
+  function xCURIE($v, $base, $ns) {
+    if ($sub_r = $this->x('([a-z0-9\-\_]*)\:([^\s]+)', $v)) {
+      if (!$sub_r[1]) return array('http://www.w3.org/1999/xhtml/vocab#' . $sub_r[2], '');
+      if (isset($ns[$sub_r[1]])) {
+        return array($ns[$sub_r[1]] . $sub_r[2], '');
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/extractors/ARC2_TwitterProfilePicExtractor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,45 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Extractor
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('RDFExtractor');
+
+class ARC2_TwitterProfilePicExtractor extends ARC2_RDFExtractor {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->a['ns']['foaf'] = 'http://xmlns.com/foaf/0.1/';
+    $this->a['ns']['mf'] = 'http://poshrdf.org/ns/mf#';
+  }
+
+  /*  */
+  
+  function extractRDF() {
+    $t_vals = array();
+    $t = '';
+    foreach ($this->nodes as $n) {
+      if (isset($n['tag']) && ($n['tag'] == 'img') && ($this->v('id', '', $n['a']) == 'profile-image')) {
+        $t_vals['vcard_id'] = $this->getDocID($n) . '#resource(side/1/2/1)';
+        $t .= '?vcard_id mf:photo <' . $n['a']['src'] . '> . ';
+        break;
+      }
+    }
+    if ($t) {
+      $doc = $this->getFilledTemplate($t, $t_vals, $n['doc_base']);
+      $this->addTs(ARC2::getTriplesFromIndex($doc));
+    }
+  }
+
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_AtomParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,245 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Atom Parser
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('LegacyXMLParser');
+
+class ARC2_AtomParser extends ARC2_LegacyXMLParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->triples = array();
+    $this->target_encoding = '';
+    $this->t_count = 0;
+    $this->added_triples = array();
+    $this->skip_dupes = false;
+    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+    $this->bnode_id = 0;
+    $this->cache = array();
+    $this->allowCDataNodes = 0;
+  }
+  
+  /*  */
+  
+  function done() {
+    $this->extractRDF();
+  }
+  
+  /*  */
+  
+  function setReader(&$reader) {
+    $this->reader = $reader;
+  }
+  
+  function createBnodeID(){
+    $this->bnode_id++;
+    return '_:' . $this->bnode_prefix . $this->bnode_id;
+  }
+  
+  function addT($t) {
+    //if (!isset($t['o_datatype']))
+    if ($this->skip_dupes) {
+      //$h = md5(print_r($t, 1));
+      $h = md5(serialize($t));
+      if (!isset($this->added_triples[$h])) {
+        $this->triples[$this->t_count] = $t;
+        $this->t_count++;
+        $this->added_triples[$h] = true;
+      }
+    }
+    else {
+      $this->triples[$this->t_count] = $t;
+      $this->t_count++;
+    }
+  }
+
+  function getTriples() {
+    return $this->v('triples', array());
+  }
+
+  function countTriples() {
+    return $this->t_count;
+  }
+  
+  function getSimpleIndex($flatten_objects = 1, $vals = '') {
+    return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
+  }
+
+  /*  */
+
+  function extractRDF() {
+    $index = $this->getNodeIndex();
+    //print_r($index);
+    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->atom = 'http://www.w3.org/2005/Atom';
+    $this->rss = 'http://purl.org/rss/1.0/';
+    $this->dc = 'http://purl.org/dc/elements/1.1/';
+    $this->sioc = 'http://rdfs.org/sioc/ns#';
+    $this->dct = 'http://purl.org/dc/terms/';
+    $this->content = 'http://purl.org/rss/1.0/modules/content/';
+    $this->enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
+    $this->mappings = array(
+      'feed' => $this->rss . 'channel',
+      'entry' => $this->rss . 'item',
+      'title' => $this->rss . 'title',
+      'link' => $this->rss . 'link',
+      'summary' => $this->rss . 'description',
+      'content' => $this->content . 'encoded',
+      'id' => $this->dc . 'identifier',
+      'author' => $this->dc . 'creator',
+      'category' => $this->dc . 'subject',
+      'updated' => $this->dc . 'date',
+      'source' => $this->dc . 'source',
+    );
+    $this->dt_props = array(
+      $this->dc . 'identifier',
+      $this->rss . 'link'
+    );
+    foreach ($index as $p_id => $nodes) {
+      foreach ($nodes as $pos => $node) {
+        $tag = $this->v('tag', '', $node);
+        if ($tag == 'feed') {
+          $struct = $this->extractChannel($index[$node['id']]);
+          $triples = ARC2::getTriplesFromIndex($struct);
+          foreach ($triples as $t) {
+            $this->addT($t);
+          }
+        }
+        elseif ($tag == 'entry') {
+          $struct = $this->extractItem($index[$node['id']]);
+          $triples = ARC2::getTriplesFromIndex($struct);
+          foreach ($triples as $t) {
+            $this->addT($t);
+          }
+        }
+      }
+    }
+  }
+  
+  function extractChannel($els) {
+    list($props, $sub_index) = $this->extractProps($els, 'channel');
+    $uri = $props[$this->rss . 'link'][0]['value'];
+    return ARC2::getMergedIndex(array($uri => $props), $sub_index);
+  }
+  
+  function extractItem($els) {
+    list($props, $sub_index) = $this->extractProps($els, 'item');
+    $uri = $props[$this->rss . 'link'][0]['value'];
+    return ARC2::getMergedIndex(array($uri => $props), $sub_index);
+  }
+  
+  function extractProps($els, $container) {
+    $r = array($this->rdf . 'type' => array(array('value' => $this->rss . $container, 'type' => 'uri')));
+    $sub_index = array();
+    foreach ($els as $info) {
+      /* key */
+      $tag = $info['tag'];
+      if (!preg_match('/^[a-z0-9]+\:/i', $tag)) {
+        $k = isset($this->mappings[$tag]) ? $this->mappings[$tag] : '';
+      }
+      elseif (isset($this->mappings[$tag])) {
+        $k = $this->mappings[$tag];
+      }
+      else {/* qname */
+        $k = $this->expandPName($tag);
+      }
+      //echo $k . "\n";
+      if (($container == 'channel') && ($k == $this->rss . 'item')) continue;
+      /* val */
+      $v = trim($info['cdata']);
+      if (!$v) $v = $this->v('href uri', '', $info['a']);
+      /* prop */
+      if ($k) {
+        /* content handling */
+        if (in_array($k, array($this->rss . 'description', $this->content . 'encoded'))) {
+          $v = $this->getNodeContent($info);
+        }
+        /* source handling */
+        elseif ($k == $this->dc . 'source') {
+          $sub_nodes = $this->node_index[$info['id']];
+          foreach ($sub_nodes as $sub_pos => $sub_info) {
+            if ($sub_info['tag'] == 'id') {
+              $v = trim($sub_info['cdata']);
+            }
+          }
+        }
+        /* link handling */
+        elseif ($k == $this->rss . 'link') {
+          if ($link_type = $this->v('type', '', $info['a'])) {
+            $k2 = $this->dc . 'format';
+            if (!isset($sub_index[$v])) $sub_index[$v] = array();
+            if (!isset($sub_index[$v][$k2])) $sub_index[$v][$k2] = array();
+            $sub_index[$v][$k2][] = array('value' => $link_type, 'type' => 'literal');
+          }
+        }
+        /* author handling */
+        elseif ($k == $this->dc . 'creator') {
+          $sub_nodes = $this->node_index[$info['id']];
+          foreach ($sub_nodes as $sub_pos => $sub_info) {
+            if ($sub_info['tag'] == 'name') {
+              $v = trim($sub_info['cdata']);
+            }
+            if ($sub_info['tag'] == 'uri') {
+              $k2 = $this->sioc . 'has_creator';
+              $v2 = trim($sub_info['cdata']);
+              if (!isset($r[$k2])) $r[$k2] = array();
+              $r[$k2][] = array('value' => $v2, 'type' => 'uri');
+            }
+          }
+        }
+        /* date handling */
+        elseif (in_array($k, array($this->dc . 'date', $this->dct . 'modified'))) {
+          if (!preg_match('/^[0-9]{4}/', $v) && ($sub_v = strtotime($v)) && ($sub_v != -1)) {
+            $tz = date('Z', $sub_v); /* timezone offset */
+            $sub_v -= $tz; /* utc */
+            $v = date('Y-m-d\TH:i:s\Z', $sub_v);
+          }
+        }
+        /* tag handling */
+        elseif ($k == $this->dc . 'subject') {
+          $v = $this->v('term', '', $info['a']);
+        }
+        /* other attributes in closed tags */
+        elseif (!$v && ($info['state'] == 'closed') && $info['a']) {
+          foreach ($info['a'] as $sub_k => $sub_v) {
+            if (!preg_match('/(xmlns|\:|type)/', $sub_k)) {
+              $v = $sub_v;
+              break;
+            }
+          }
+        }
+        if (!isset($r[$k])) $r[$k] = array();
+        $r[$k][] = array('value' => $v, 'type' => in_array($k, $this->dt_props) || !preg_match('/^[a-z0-9]+\:[^\s]+$/is', $v) ? 'literal' : 'uri');
+      }
+    }
+    return array($r, $sub_index);
+  }
+  
+  function initXMLParser() {
+    if (!isset($this->xml_parser)) {
+      $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
+      $parser = xml_parser_create($enc);
+      xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+      xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+      xml_set_element_handler($parser, 'open', 'close');
+      xml_set_character_data_handler($parser, 'cData');
+      xml_set_start_namespace_decl_handler($parser, 'nsDecl');
+      xml_set_object($parser, $this);
+      $this->xml_parser = $parser;
+    }
+  }
+
+  /*  */
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_CBJSONParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,267 @@
+<?php
+/**
+ * ARC2 CrunchBase API JSON Parser
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('JSONParser');
+
+class ARC2_CBJSONParser extends ARC2_JSONParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->base = 'http://cb.semsol.org/';
+    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->default_ns = $this->base . 'ns#';
+    $this->nsp = array($this->rdf => 'rdf');
+  }
+  
+  /*  */
+
+  function done() {
+    $this->extractRDF();
+  }
+  
+  function extractRDF() {
+    $struct = $this->struct;
+    if ($type = $this->getStructType($struct)) {
+      $s = $this->getResourceID($struct, $type);
+      /* rdf:type */
+      $this->addT($s, $this->rdf . 'type', $this->default_ns . $this->camelCase($type), 'uri', 'uri');
+      /* explicit triples */
+      $this->extractResourceRDF($struct, $s);
+    }
+  }
+  
+  function getStructType($struct, $rel = '') {
+    /* url-based */
+    if ($url = $this->v('crunchbase_url', '', $struct)) {
+      return preg_replace('/^.*crunchbase\.com\/([^\/]+)\/.*$/', '\\1', $url);
+    }
+    /* rel-based */
+    if ($rel == 'person') return 'person';
+    if ($rel == 'company') return 'company';
+    if ($rel == 'acquiring_company') return 'company';
+    if ($rel == 'firm') return 'company';
+    if ($rel == 'provider') return 'service-provider';
+    /* struct-based */
+    if (isset($struct['_type'])) return $struct['_type'];
+    if (isset($struct['round_code'])) return 'funding_round';
+    if (isset($struct['products'])) return 'company';
+    if (isset($struct['first_name'])) return 'person';
+    if (isset($struct['investments'])) return 'financial-organization';
+    if (isset($struct['launched_year'])) return 'product';
+    if (isset($struct['providerships']) && is_array($struct['providerships'])) return 'service-provider';
+    return '';
+  }
+  
+  function getResourceID($struct, $type) {
+    if ($type && isset($struct['permalink'])) {
+      return $this->base . $type . '/' . $struct['permalink'] . '#self';
+    }
+    return $this->createBnodeID();
+  }
+  
+  function getPropertyURI($name, $ns = '') {
+    if (!$ns) $ns = $this->default_ns;
+    if (preg_match('/^(product|funding_round|investment|acquisition|.+ship|office|milestone|.+embed|.+link|degree|fund)s/', $name, $m)) $name = $m[1];
+    if ($name == 'tag_list') $name = 'tag';
+    if ($name == 'competitions') $name = 'competitor';
+    return $ns . $name;
+  }
+
+  function createSubURI($s, $k, $pos) {
+    $s = str_replace('#self', '/', $s);
+    if (preg_match('/(office|ship|investment|milestone|fund|embed|link)s$/', $k)) $k = substr($k, 0, -1);
+    return $s . $k . '-' . ($pos + 1) . '#self';
+  }
+  
+  /*  */
+  
+  function extractResourceRDF($struct, $s, $pos = 0) {
+    $s_type = preg_match('/^\_\:/', $s) ? 'bnode' : 'uri';
+    $date_prefixes = array();
+    foreach ($struct as $k => $v) {
+      if ($k == 'acquisition') $k = 'exit';
+      if (preg_match('/^(.*)\_(year|month|day)$/', $k, $m)) {
+        if (!in_array($m[1], $date_prefixes)) $date_prefixes[] = $m[1];
+      }
+      $sub_m = 'extract' . $this->camelCase($k) . 'RDF';
+      if (method_exists($this, $sub_m)) {
+        $this->$sub_m($s, $s_type, $v);
+        continue;
+      }
+      $p = $this->getPropertyURI($k);
+      if (!$v) continue;
+      /* simple, single v */
+      if (!is_array($v)) {
+        $o_type = preg_match('/^[a-z]+\:[^\s]+$/is', $v) ? 'uri' : 'literal';
+        $v = trim($v);
+        if (preg_match('/^https?\:\/\/[^\/]+$/', $v)) $v .= '/';
+        $this->addT($s, $p, $v, $s_type, $o_type);
+        /* rdfs:label */
+        if ($k == 'name') $this->addT($s, 'http://www.w3.org/2000/01/rdf-schema#label', $v, $s_type, $o_type);
+        /* dc:identifier */
+        //if ($k == 'permalink') $this->addT($s, 'http://purl.org/dc/elements/1.1/identifier', $v, $s_type, $o_type);
+      }
+      /* structured, single v */
+      elseif (!$this->isFlatArray($v)) {
+        if ($o_type = $this->getStructType($v, $k)) {/* known type */
+          $o = $this->getResourceID($v, $o_type);
+          $this->addT($s, $p, $o, $s_type, 'uri');
+          $this->addT($o, $this->rdf . 'type', $this->default_ns . $this->camelCase($o_type), 'uri', 'uri');
+        }
+        else {/* unknown type */
+          $o = $this->createSubURI($s, $k, $pos);
+          $this->addT($s, $p, $o, $s_type, 'uri');
+          $this->extractResourceRDF($v, $o);
+        }
+      }
+      /* value list */
+      else {
+        foreach ($v as $sub_pos => $sub_v) {
+          $this->extractResourceRDF(array($k => $sub_v), $s, $sub_pos);
+        }
+      }
+    }
+    /* infer XSD triples */
+    foreach ($date_prefixes as $prefix) {
+      $this->inferDate($prefix, $s, $struct);
+    }
+  }
+
+  function isFlatArray($v) {
+    foreach ($v as $k => $sub_v) {
+      return is_numeric($k) ? 1 : 0;
+    }
+  }
+  
+  /*  */
+  
+  function extractTagListRDF($s, $s_type,  $v) {
+    if (!$v) return 0;
+    $tags = preg_split('/\, /', $v);
+    foreach ($tags as $tag) {
+      if (!trim($tag)) continue;
+      $this->addT($s, $this->getPropertyURI('tag'), $tag, $s_type, 'literal');
+    }
+  }
+
+  function extractImageRDF($s, $s_type, $v, $rel = 'image') {
+    if (!$v) return 1;
+    $sizes = $v['available_sizes'];
+    foreach ($sizes as $size) {
+      $w = $size[0][0];
+      $h = $size[0][1];
+      $img = 'http://www.crunchbase.com/' . $size[1];
+      $this->addT($s, $this->getPropertyURI($rel), $img, $s_type, 'uri');
+      $this->addT($img, $this->getPropertyURI('width'), $w, 'uri', 'literal');
+      $this->addT($img, $this->getPropertyURI('height'), $h, 'uri', 'literal');
+    }
+  }
+
+  function extractScreenshotsRDF($s, $s_type, $v) {
+    if (!$v) return 1;
+    foreach ($v as $sub_v) {
+      $this->extractImageRDF($s, $s_type, $sub_v, 'screenshot');
+    }
+  }
+  
+  function extractProductsRDF($s, $s_type, $v) {
+    foreach ($v as $sub_v) {
+      $o = $this->getResourceID($sub_v, 'product');
+      $this->addT($s, $this->getPropertyURI('product'), $o, $s_type, 'uri');
+    }
+  }
+
+  function extractCompetitionsRDF($s, $s_type, $v) {
+    foreach ($v as $sub_v) {
+      $o = $this->getResourceID($sub_v['competitor'], 'company');
+      $this->addT($s, $this->getPropertyURI('competitor'), $o, $s_type, 'uri');
+    }
+  }
+
+  function extractFundingRoundsRDF($s, $s_type, $v) {
+    foreach ($v as $pos => $sub_v) {
+      $o = $this->createSubURI($s, 'funding_round', $pos);
+      $this->addT($s, $this->getPropertyURI('funding_round'), $o, $s_type, 'uri');
+      $this->extractResourceRDF($sub_v, $o, $pos);
+    }
+  }
+
+  function extractInvestmentsRDF($s, $s_type, $v) {
+    foreach ($v as $pos => $sub_v) {
+      /* incoming */
+      foreach (array('person' => 'person', 'company' => 'company', 'financial_org' => 'financial-organization') as $k => $type) {
+        if (isset($sub_v[$k])) $this->addT($s, $this->getPropertyURI('investment'), $this->getResourceID($sub_v[$k], $type), $s_type, 'uri');
+      }
+      /* outgoing */
+      if (isset($sub_v['funding_round'])) {
+        $o = $this->createSubURI($s, 'investment', $pos);
+        $this->addT($s, $this->getPropertyURI('investment'), $o, $s_type, 'uri');
+        $this->extractResourceRDF($sub_v['funding_round'], $o, $pos);
+      }
+    }
+  }
+  
+  function extractExternalLinksRDF($s, $s_type, $v) {
+    foreach ($v as $sub_v) {
+      $href = $sub_v['external_url'];
+      if (preg_match('/^https?\:\/\/[^\/]+$/', $href)) $href .= '/';
+      $this->addT($s, $this->getPropertyURI('external_link'), $href, $s_type, 'uri');
+      $this->addT($href, $this->getPropertyURI('title'), $sub_v['title'], $s_type, 'literal');
+    }
+  }
+
+  function extractWebPresencesRDF($s, $s_type, $v) {
+    foreach ($v as $sub_v) {
+      $href = $sub_v['external_url'];
+      if (preg_match('/^https?\:\/\/[^\/]+$/', $href)) $href .= '/';
+      $this->addT($s, $this->getPropertyURI('web_presence'), $href, $s_type, 'uri');
+      $this->addT($href, $this->getPropertyURI('title'), $sub_v['title'], $s_type, 'literal');
+    }
+  }
+
+  function extractCreatedAtRDF($s, $s_type,  $v) {
+    $v = $this->getAPIDateXSD($v);
+    $this->addT($s, $this->getPropertyURI('created_at'), $v, $s_type, 'literal');
+  }
+
+  function extractUpdatedAtRDF($s, $s_type,  $v) {
+    $v = $this->getAPIDateXSD($v);
+    $this->addT($s, $this->getPropertyURI('updated_at'), $v, $s_type, 'literal');
+  }
+
+  function getAPIDateXSD($val) {
+    //Fri Jan 16 21:11:48 UTC 2009
+    if (preg_match('/^[a-z]+ ([a-z]+) ([0-9]+) ([0-9]{2}\:[0-9]{2}\:[0-9]{2}) UTC ([0-9]{4})/i', $val, $m)) {
+      $months = array('Jan' => '01', 'Feb' => '02', 'Mar' =>'03', 'Apr' => '04', 'May' => '05', 'Jun' => '06', 'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12');
+      return $m[4] . '-' . $months[$m[1]] . '-' . $m[2] . 'T' . $m[3] . 'Z';
+    }
+    return '2000-01-01';
+  }
+
+  /*  */
+
+  function inferDate($prefix, $s, $struct) {
+    $s_type = preg_match('/^\_\:/', $s) ? 'bnode' : 'uri';
+    $r = '';
+    foreach (array('year', 'month', 'day') as $suffix) {
+      $val = $this->v1($prefix . '_' . $suffix, '00', $struct);
+      $r .= ($r ? '-' : '') . str_pad($val, 2, '0', STR_PAD_LEFT);
+    }
+    if ($r != '00-00-00') {
+      $this->addT($s, $this->getPropertyURI($prefix . '_date'), $r, $s_type, 'literal');
+    }
+  }
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_JSONParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,165 @@
+<?php
+/**
+ * ARC2 JSON Parser
+ * Does not extract triples, needs sub-class for RDF extraction
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('RDFParser');
+
+class ARC2_JSONParser extends ARC2_RDFParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+  
+  /*  */
+
+  function x($re, $v, $options = 'si') {
+    while (preg_match('/^\s*(\/\*.*\*\/)(.*)$/Usi', $v, $m)) {/* comment removal */
+      $v = $m[2];
+    }
+    $this->unparsed_code = (strlen($this->unparsed_code) > strlen($v)) ? $v : $this->unparsed_code;
+    return ARC2::x($re, $v, $options);
+  }
+
+  function parse($path, $data = '') {
+    $this->state = 0;
+    /* reader */
+    if (!$this->v('reader')) {
+      ARC2::inc('Reader');
+      $this->reader = new ARC2_Reader($this->a, $this);
+    }
+    $this->reader->setAcceptHeader('Accept: application/json; q=0.9, */*; q=0.1');
+    $this->reader->activate($path, $data);
+    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+    /* parse */
+    $doc = '';
+    while ($d = $this->reader->readStream()) {
+      $doc .= $d;
+    }
+    $this->reader->closeStream();
+    unset($this->reader);
+    $doc = preg_replace('/^[^\{]*(.*\})[^\}]*$/is', '\\1', $doc);
+    $this->unparsed_code = $doc;
+    list($this->struct, $rest) = $this->extractObject($doc);
+    return $this->done();
+  }
+  
+  /*  */
+  
+  function extractObject($v) {
+    if (function_exists('json_decode')) return array(json_decode($v, 1), '');
+    $r = array();
+    /* sub-object */
+    if ($sub_r = $this->x('\{', $v)) {
+      $v = $sub_r[1];
+      while ((list($sub_r, $v) = $this->extractEntry($v)) && $sub_r) {
+        $r[$sub_r['key']] = $sub_r['value'];
+      }
+      if ($sub_r = $this->x('\}', $v)) $v = $sub_r[1];
+    }
+    /* sub-list */
+    elseif ($sub_r = $this->x('\[', $v)) {
+      $v = $sub_r[1];
+      while ((list($sub_r, $v) = $this->extractObject($v)) && $sub_r) {
+        $r[] = $sub_r;
+        $v = ltrim($v, ',');
+      }
+      if ($sub_r = $this->x('\]', $v)) $v = $sub_r[1];
+    }
+    /* sub-value */
+    elseif ((list($sub_r, $v) = $this->extractValue($v)) && ($sub_r !== false)) {
+      $r = $sub_r;
+    }
+    return array($r, $v);
+  }
+  
+  function extractEntry($v) {
+    if ($r = $this->x('\,', $v)) $v = $r[1];
+    /* k */
+    if ($r = $this->x('\"([^\"]+)\"\s*\:', $v)) {
+      $k = $r[1];
+      $sub_v = $r[2];
+      if (list($sub_r, $sub_v) = $this->extractObject($sub_v)) {
+        return array(
+          array('key' => $k, 'value' => $sub_r),
+          $sub_v
+        );
+      }
+    }
+    return array(0, $v);
+  }
+  
+  function extractValue($v) {
+    if ($r = $this->x('\,', $v)) $v = $r[1];
+    if ($sub_r = $this->x('null', $v)) {
+      return array(null, $sub_r[1]);
+    }
+    if ($sub_r = $this->x('(true|false)', $v)) {
+      return array($sub_r[1], $sub_r[2]);
+    }
+    if ($sub_r = $this->x('([\-\+]?[0-9\.]+)', $v)) {
+      return array($sub_r[1], $sub_r[2]);
+    }
+    if ($sub_r = $this->x('\"', $v)) {
+      $rest = $sub_r[1];
+      if (preg_match('/^([^\x5c]*|.*[^\x5c]|.*\x5c{2})\"(.*)$/sU', $rest, $m)) {
+        $val = $m[1];
+        /* unescape chars (single-byte) */
+        $val = preg_replace('/\\\u(.{4})/e', 'chr(hexdec("\\1"))', $val);
+        //$val = preg_replace('/\\\u00(.{2})/e', 'rawurldecode("%\\1")', $val);
+        /* other escaped chars */
+        $from = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/');
+        $to = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
+        $val = str_replace($from, $to, $val);
+        return array($val, $m[2]);
+      }
+    }
+    return array(false, $v);
+  }
+  
+  /*  */
+
+  function getObject() {
+    return $this->v('struct', array());
+  }
+  
+  function getTriples() {
+    return $this->v('triples', array());
+  }
+  
+  function countTriples() {
+    return $this->t_count;
+  }
+
+  function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '') {
+    $o = $this->toUTF8($o);
+    //echo str_replace($this->base, '', "-----\n adding $s / $p / $o\n-----\n");
+    $t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang);
+    if ($this->skip_dupes) {
+      $h = md5(serialize($t));
+      if (!isset($this->added_triples[$h])) {
+        $this->triples[$this->t_count] = $t;
+        $this->t_count++;
+        $this->added_triples[$h] = true;
+      }
+    }
+    else {
+      $this->triples[$this->t_count] = $t;
+      $this->t_count++;
+    }
+  }
+
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_LegacyXMLParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,311 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Legaxy XML Parser
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_LegacyXMLParser extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->encoding = $this->v('encoding', false, $this->a);
+    $this->state = 0;
+    $this->x_base = $this->base;
+    $this->xml = 'http://www.w3.org/XML/1998/namespace';
+    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
+    $this->allowCDataNodes = 1;
+    $this->target_encoding = '';
+    $this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
+  }
+  
+  /*  */
+
+  function setReader(&$reader) {
+    $this->reader = $reader;
+  }
+
+  function parse($path, $data = '', $iso_fallback = false) {
+    $this->nodes = array();
+    $this->node_count = 0;
+    $this->level = 0;
+    /* reader */
+    if (!$this->v('reader')) {
+      ARC2::inc('Reader');
+      $this->reader = new ARC2_Reader($this->a, $this);
+    }
+    $this->reader->setAcceptHeader('Accept: application/xml; q=0.9, */*; q=0.1');
+    $this->reader->activate($path, $data);
+    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+    $this->base = $this->x_base;
+    $this->doc_url = $this->reader->base;
+    /* xml parser */
+    $this->initXMLParser();
+    /* parse */
+    $first = true;
+    while ($d = $this->reader->readStream(1)) {
+      if ($iso_fallback && $first) {
+        $d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
+      }
+      if (!xml_parse($this->xml_parser, $d, false)) {
+        $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
+        $line = xml_get_current_line_number($this->xml_parser);
+        if (!$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
+          xml_parser_free($this->xml_parser);
+          unset($this->xml_parser);
+          $this->reader->closeStream();
+          unset($this->reader);
+          $this->__init();
+          $this->encoding = 'ISO-8859-1';
+          $this->initXMLParser();
+          return $this->parse($path, $data, true);
+        }
+        else {
+          return $this->addError('XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')');
+        }
+      }
+      $first = false;
+    }
+    $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
+    xml_parser_free($this->xml_parser);
+    $this->reader->closeStream();
+    unset($this->reader);
+    return $this->done();
+  }
+  
+  /*  */
+  
+  function getEncoding($src = 'config') {
+    if ($src == 'parser') {
+      return $this->target_encoding;
+    }
+    elseif (($src == 'config') && $this->encoding) {
+      return $this->encoding;
+    }
+    return $this->reader->getEncoding();
+  }
+
+  /*  */
+  
+  function done() {
+  
+  }
+  
+  /*  */
+  
+  function getStructure() {
+    return array('nodes' => $this->v('nodes', array()));
+  }
+  
+  /*  */
+
+  function getNodeIndex(){
+    if (!isset($this->node_index)) {
+      /* index by parent */
+      $index = array();
+      for ($i = 0, $i_max = count($this->nodes); $i < $i_max; $i++) {
+        $node = $this->nodes[$i];
+        $node['id'] = $i;
+        $node['doc_base'] = $this->base;
+        if (isset($this->doc_url)) $node['doc_url'] = $this->doc_url;
+        $this->updateNode($node);
+        $p_id = $node['p_id'];
+        if (!isset($index[$p_id])) {
+          $index[$p_id] = array();
+        }
+        $index[$p_id][$node['pos']] = $node;
+      }
+      $this->node_index = $index;
+    }
+    return $this->node_index;
+  }
+
+  function getNodes() {
+    return $this->nodes;
+  }
+  
+  function getSubNodes($n) {
+    return $this->v($n['id'], array(), $this->getNodeIndex());
+  }
+  
+  function getNodeContent($n, $outer = 0, $trim = 1) {
+    //echo '<pre>' . htmlspecialchars(print_r($n, 1)) . '</pre>';
+    if ($n['tag'] == 'cdata') {
+      $r = $n['a']['value'];
+    }
+    else {
+      $r = '';
+      if ($outer) {
+        $r .= '<' . $n['tag'];
+        asort($n['a']);
+        if (isset($n['a']['xmlns']) && $n['a']['xmlns']['']) {
+          $r .= ' xmlns="' . $n['a']['xmlns'][''] . '"';
+        }
+        foreach ($n['a'] as $a => $val) {
+          $r .= preg_match('/^[^\s]+$/', $a) && !is_array($val) ? ' ' . $a . '="' . addslashes($val) . '"' : '';
+        }
+        $r .= $n['empty'] ? '/>' : '>';
+      }
+      if (!$n['empty']) {
+        $r .= $this->v('cdata', '', $n);
+        $sub_nodes = $this->getSubNodes($n);
+        foreach ($sub_nodes as $sub_n) {
+          $r .= $this->getNodeContent($sub_n, 1, 0);
+        }
+        if ($outer) {
+          $r .= '</' . $n['tag'] . '>';
+        }
+      }
+    }
+    return ($trim && !$this->keep_cdata_ws) ? trim($r) : $r;
+  }
+
+  /*  */
+  
+  function pushNode($n) {
+    $n['id'] = $this->node_count;
+    $this->nodes[$this->node_count] = $n;
+    $this->node_count++;
+  }
+  
+  function getCurNode($t = '') {
+    $i = 1;
+    do {
+      $r = $this->node_count ? $this->nodes[$this->node_count - $i] : 0;
+      $found = (!$t || ($r['tag'] == $t)) ? 1 : 0;
+      $i++;
+    } while (!$found && isset($this->nodes[$this->node_count - $i]));
+    return $r;
+  }
+  
+  function updateNode($node) {/* php4-save */
+    $this->nodes[$node['id']] = $node;
+  }
+
+  /*  */
+
+  function initXMLParser() {
+    if (!isset($this->xml_parser)) {
+      $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
+      $parser = xml_parser_create_ns($enc, '');
+      xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+      xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+      xml_set_element_handler($parser, 'open', 'close');
+      xml_set_character_data_handler($parser, 'cData');
+      xml_set_start_namespace_decl_handler($parser, 'nsDecl');
+      xml_set_object($parser, $this);
+      $this->xml_parser = $parser;
+    }
+  }
+
+  /*  */
+  
+  function open($p, $t, $a) {
+    $t_exact = $t;
+    //echo "<br />\n".'opening '.$t . ' ' . print_r($a, 1); flush();
+    //echo "<br />\n".'opening '.$t; flush();
+    $t = strpos($t, ':') ? $t : strtolower($t);
+    /* base check */
+    $base = '';
+    if (($t == 'base') && isset($a['href'])) {
+      $this->base = $a['href'];
+      $base = $a['href'];
+    }
+    /* URIs */
+    foreach (array('href', 'src', 'id') as $uri_a) {
+      if (isset($a[$uri_a])) {
+        $a[$uri_a . ' uri'] = ($uri_a == 'id') ? $this->calcURI('#'.$a[$uri_a]) : $this->calcURI($a[$uri_a]);
+      }
+    }
+    /* ns */
+    if ($a) {
+      foreach ($a as $k => $v) {
+        if (strpos($k, 'xmlns') === 0) {
+          $this->nsDecl($p, trim(substr($k, 5), ':'), $v);
+        }
+      }
+    }
+    /* node */
+    $node = array(
+      'tag' => $t,
+      'tag_exact' => $t_exact,
+      'a' => $a, 
+      'level' => $this->level, 
+      'pos' => 0,
+      'p_id' => $this->node_count-1,
+      'state' => 'open',
+      'empty' => 0,
+      'cdata' =>''
+    );
+    if ($base) {
+      $node['base'] = $base;
+    }
+    /* parent/sibling */
+    if ($this->node_count) {
+      $l = $this->level;
+      $prev_node = $this->getCurNode();
+      if ($prev_node['level'] == $l) {
+        $node['p_id'] = $prev_node['p_id'];
+        $node['pos'] = $prev_node['pos']+1;
+      }
+      elseif($prev_node['level'] > $l) {
+        while($prev_node['level'] > $l) {
+          if (!isset($this->nodes[$prev_node['p_id']])) {
+            //$this->addError('nesting mismatch: tag is ' . $t . ', level is ' . $l . ', prev_level is ' . $prev_node['level'] . ', prev_node p_id is ' . $prev_node['p_id']);
+            break;
+          }
+          $prev_node = $this->nodes[$prev_node['p_id']];
+        }
+        $node['p_id'] = $prev_node['p_id'];
+        $node['pos'] = $prev_node['pos']+1;
+      }
+    }
+    $this->pushNode($node);
+    $this->level++;
+    /* cdata */
+    $this->cur_cdata="";
+  }
+
+  function close($p, $t, $empty = 0) {
+    //echo "<br />\n".'closing '.$t; flush();
+    $node = $this->getCurNode($t);
+    $node['state'] = 'closed';
+    $node['empty'] = $empty;
+    $this->updateNode($node);
+    $this->level--;
+  }
+
+  function cData($p, $d) {
+    //echo trim($d) ? "<br />\n".'cdata: ' . $d : ''; flush();
+    $node = $this->getCurNode();
+    if($node['state'] == 'open') {
+      $node['cdata'] .= $d;
+      $this->updateNode($node);
+    }
+    else {/* cdata is sibling of node */
+      if ($this->allowCDataNodes) {
+        $this->open($p, 'cdata', array('value' => $d));
+        $this->close($p, 'cdata');
+      }
+    }
+  }
+  
+  function nsDecl($p, $prf, $uri) {
+    if (is_array($uri)) return 1;
+    $this->ns[$prf] = $uri;
+    $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
+  }
+
+  /*  */
+  
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_RDFParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,139 @@
+<?php
+/**
+ * ARC2 RDF Parser (generic)
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_RDFParser extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* proxy_host, proxy_port, proxy_skip, http_accept_header, http_user_agent_header, max_redirects, reader, skip_dupes */
+    parent::__init();
+    $this->a['format'] = $this->v('format', false, $this->a);
+    $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
+    $this->triples = array();
+    $this->t_count = 0;
+    $this->added_triples = array();
+    $this->skip_dupes = $this->v('skip_dupes', false, $this->a);
+    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+    $this->bnode_id = 0;
+    $this->format = '';
+  }
+
+  /*  */
+  
+  function setReader(&$reader) {
+    $this->reader = $reader;
+  }
+  
+  function parse($path, $data = '') {
+    /* reader */
+    if (!isset($this->reader)) {
+      ARC2::inc('Reader');
+      $this->reader = new ARC2_Reader($this->a, $this);
+    }
+    $this->reader->activate($path, $data) ;
+    /* format detection */
+    $mappings = array(
+      'rdfxml' => 'RDFXML', 
+      'turtle' => 'Turtle', 
+      'sparqlxml' => 'SPOG', 
+      'ntriples' => 'Turtle', 
+      'html' => 'SemHTML',
+      'rss' => 'RSS',
+      'atom' => 'Atom',
+      'sgajson' => 'SGAJSON',
+      'cbjson' => 'CBJSON'
+    );
+    $format = $this->reader->getFormat();
+    if (!$format || !isset($mappings[$format])) {
+      return $this->addError('No parser available for "' . $format . '".');
+    }
+    $this->format = $format;
+    /* format parser */
+    $suffix = $mappings[$format] . 'Parser';
+    ARC2::inc($suffix);
+    $cls = 'ARC2_' . $suffix;
+    $this->parser = new $cls($this->a, $this);
+    $this->parser->setReader($this->reader);
+    return $this->parser->parse($path, $data);
+  }
+  
+  function parseData($data) {
+    return $this->parse(ARC2::getScriptURI(), $data);
+  }
+  
+  /*  */
+
+  function done() {
+  }
+
+  /*  */
+  
+  function createBnodeID(){
+    $this->bnode_id++;
+    return '_:' . $this->bnode_prefix . $this->bnode_id;
+  }
+
+  function getTriples() {
+    return $this->v('parser') ? $this->m('getTriples', false, array(), $this->v('parser')) : array();
+  }
+  
+  function countTriples() {
+    return $this->v('parser') ? $this->m('countTriples', false, 0, $this->v('parser')) : 0;
+  }
+  
+  function getSimpleIndex($flatten_objects = 1, $vals = '') {
+    return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
+  }
+  
+  function reset() {
+    $this->__init();
+    if (isset($this->reader)) unset($this->reader);
+    if (isset($this->parser)) {
+      $this->parser->__init();
+      unset($this->parser);
+    }
+  }
+  
+  /*  */
+  
+  function extractRDF($formats = '') {
+    if (method_exists($this->parser, 'extractRDF')) {
+      return $this->parser->extractRDF($formats);
+    }
+  }
+  
+  /*  */
+  
+  function getEncoding($src = 'config') {
+    if (method_exists($this->parser, 'getEncoding')) {
+      return $this->parser->getEncoding($src);
+    }
+  }
+
+  /**
+   * returns the array of namespace prefixes encountered during parsing
+   * @return array (keys = namespace URI / values = prefix used)
+  */
+
+  function getParsedNamespacePrefixes() {
+    if (isset($this->parser)) {
+      return $this->v('nsp', array(), $this->parser);
+    }
+    return $this->v('nsp', array());
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_RDFXMLParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,640 @@
+<?php
+/**
+ * ARC2 RDF/XML Parser
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+*/
+
+ARC2::inc('RDFParser');
+
+class ARC2_RDFXMLParser extends ARC2_RDFParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->encoding = $this->v('encoding', false, $this->a);
+    $this->state = 0;
+    $this->x_lang = '';
+    $this->x_base = $this->base;
+    $this->xml = 'http://www.w3.org/XML/1998/namespace';
+    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
+    $this->s_stack = array();
+    $this->s_count = 0;
+    $this->target_encoding = '';
+  }
+  
+  /*  */
+
+  function parse($path, $data = '', $iso_fallback = false) {
+    /* reader */
+    if (!$this->v('reader')) {
+      ARC2::inc('Reader');
+      $this->reader = new ARC2_Reader($this->a, $this);
+    }
+    $this->reader->setAcceptHeader('Accept: application/rdf+xml; q=0.9, */*; q=0.1');
+    $this->reader->activate($path, $data);
+    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+    /* xml parser */
+    $this->initXMLParser();
+    /* parse */
+    $first = true;
+    while ($d = $this->reader->readStream()) {
+      if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 60, $this->a));
+      if ($iso_fallback && $first) {
+        $d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
+        $first = false;
+      }
+      if (!xml_parse($this->xml_parser, $d, false)) {
+        $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
+        $line = xml_get_current_line_number($this->xml_parser);
+        $this->tmp_error = 'XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')';
+        if (!$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
+          xml_parser_free($this->xml_parser);
+          unset($this->xml_parser);
+          $this->reader->closeStream();
+          $this->__init();
+          $this->encoding = 'ISO-8859-1';
+          unset($this->xml_parser);
+          unset($this->reader);
+          return $this->parse($path, $data, true);
+        }
+        else {
+          return $this->addError($this->tmp_error);
+        }
+      }
+    }
+    $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
+    xml_parser_free($this->xml_parser);
+    $this->reader->closeStream();
+    unset($this->reader);
+    return $this->done();
+  }
+  
+  /*  */
+  
+  function initXMLParser() {
+    if (!isset($this->xml_parser)) {
+      $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
+      $parser = xml_parser_create_ns($enc, '');
+      xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+      xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+      xml_set_element_handler($parser, 'open', 'close');
+      xml_set_character_data_handler($parser, 'cdata');
+      xml_set_start_namespace_decl_handler($parser, 'nsDecl');
+      xml_set_object($parser, $this);
+      $this->xml_parser = $parser;
+    }
+  }
+
+  /*  */
+  
+  function getEncoding($src = 'config') {
+    if ($src == 'parser') {
+      return $this->target_encoding;
+    }
+    elseif (($src == 'config') && $this->encoding) {
+      return $this->encoding;
+    }
+    return $this->reader->getEncoding();
+  }
+  
+  /*  */
+  
+  function getTriples() {
+    return $this->v('triples', array());
+  }
+  
+  function countTriples() {
+    return $this->t_count;
+  }
+
+  /*  */
+  
+  function pushS(&$s) {
+    $s['pos'] = $this->s_count;
+    $this->s_stack[$this->s_count] = $s;
+    $this->s_count++;
+  }
+  
+  function popS(){/* php 4.0.x-safe */
+    $r = array();
+    $this->s_count--;
+    for ($i = 0, $i_max = $this->s_count; $i < $i_max; $i++) {
+      $r[$i] = $this->s_stack[$i];
+    }
+    $this->s_stack = $r;
+  }
+  
+  function updateS($s) {
+    $this->s_stack[$s['pos']] = $s;
+  }
+  
+  function getParentS() {
+    return ($this->s_count && isset($this->s_stack[$this->s_count - 1])) ? $this->s_stack[$this->s_count - 1] : false;
+  }
+  
+  function getParentXBase() {
+    if ($p = $this->getParentS()) {
+      return isset($p['p_x_base']) && $p['p_x_base'] ? $p['p_x_base'] : (isset($p['x_base']) ? $p['x_base'] : '');
+    }
+    return $this->x_base;
+  }
+
+  function getParentXLang() {
+    if ($p = $this->getParentS()) {
+      return isset($p['p_x_lang']) && $p['p_x_lang'] ? $p['p_x_lang'] : (isset($p['x_lang']) ? $p['x_lang'] : '');
+    }
+    return $this->x_lang;
+  }
+
+  /*  */
+  
+  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
+    //echo "-----\nadding $s / $p / $o\n-----\n";
+    $t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang);
+    if ($this->skip_dupes) {
+      $h = md5(serialize($t));
+      if (!isset($this->added_triples[$h])) {
+        $this->triples[$this->t_count] = $t;
+        $this->t_count++;
+        $this->added_triples[$h] = true;
+      }
+    }
+    else {
+      $this->triples[$this->t_count] = $t;
+      $this->t_count++;
+    }
+  }
+
+  function reify($t, $s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
+    $this->addT($t, $this->rdf.'type', $this->rdf.'Statement', 'uri', 'uri');
+    $this->addT($t, $this->rdf.'subject', $s, 'uri', $s_type);
+    $this->addT($t, $this->rdf.'predicate', $p, 'uri', 'uri');
+    $this->addT($t, $this->rdf.'object', $o, 'uri', $o_type, $o_dt, $o_lang);
+  }
+  
+  /*  */
+  
+  function open($p, $t, $a) {
+    //echo "state is $this->state\n";
+    //echo "opening $t\n";
+    switch($this->state) {
+      case 0: return $this->h0Open($t, $a);
+      case 1: return $this->h1Open($t, $a);
+      case 2: return $this->h2Open($t, $a);
+      case 4: return $this->h4Open($t, $a);
+      case 5: return $this->h5Open($t, $a);
+      case 6: return $this->h6Open($t, $a);
+      default: $this->addError('open() called at state ' . $this->state . ' in '.$t);
+    }
+  }
+
+  function close($p, $t) {
+    //echo "state is $this->state\n";
+    //echo "closing $t\n";
+    switch($this->state){
+      case 1: return $this->h1Close($t);
+      case 2: return $this->h2Close($t);
+      case 3: return $this->h3Close($t);
+      case 4: return $this->h4Close($t);
+      case 5: return $this->h5Close($t);
+      case 6: return $this->h6Close($t);
+      default: $this->addError('close() called at state ' . $this->state . ' in '.$t);
+    }
+  }
+
+  function cdata($p, $d) {
+    //echo "state is $this->state\n";
+    //echo "cdata\n";
+    switch($this->state){
+      case 4: return $this->h4Cdata($d);
+      case 6: return $this->h6Cdata($d);
+      default: return false;
+    }
+  }
+  
+  function nsDecl($p, $prf, $uri) {
+    $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
+  }
+
+  /*  */
+  
+  function h0Open($t, $a) {
+    $this->x_lang = $this->v($this->xml.'lang', $this->x_lang, $a);
+    $this->x_base = $this->calcURI($this->v($this->xml.'base', $this->x_base, $a));
+    $this->state = 1;
+    if ($t !== $this->rdf.'RDF') {
+      $this->h1Open($t, $a);
+    }
+  }
+  
+  /*  */
+
+  function h1Open($t, $a) {
+    $s = array(
+      'x_base' => isset($a[$this->xml.'base']) ? $this->calcURI($a[$this->xml.'base']) : $this->getParentXBase(), 
+      'x_lang' => isset($a[$this->xml.'lang']) ? $a[$this->xml.'lang'] : $this->getParentXLang(),
+      'li_count' => 0,
+    );
+    /* ID */
+    if (isset($a[$this->rdf.'ID'])) {
+      $s['type'] = 'uri';
+      $s['value'] = $this->calcURI('#'.$a[$this->rdf.'ID'], $s['x_base']);
+    }
+    /* about */
+    elseif (isset($a[$this->rdf.'about'])) {
+      $s['type'] = 'uri';
+      $s['value'] = $this->calcURI($a[$this->rdf.'about'], $s['x_base']);
+    }
+    /* bnode */
+    else {
+      $s['type'] = 'bnode';
+      if (isset($a[$this->rdf.'nodeID'])) {
+        $s['value'] = '_:'.$a[$this->rdf.'nodeID'];
+      }
+      else {
+        $s['value'] = $this->createBnodeID();
+      }
+    }
+    /* sub-node */
+    if ($this->state === 4) {
+      $sup_s = $this->getParentS();
+      /* new collection */
+      if (isset($sup_s['o_is_coll']) && $sup_s['o_is_coll']) {
+        $coll = array('value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']);
+        $this->addT($sup_s['value'], $sup_s['p'], $coll['value'], $sup_s['type'], $coll['type']);
+        $this->addT($coll['value'], $this->rdf . 'first', $s['value'], $coll['type'], $s['type']);
+        $this->pushS($coll);
+      }
+      /* new entry in existing coll */
+      elseif (isset($sup_s['is_coll']) && $sup_s['is_coll']) {
+        $coll = array('value' => $this->createBnodeID(), 'type' => 'bnode', 'is_coll' => true, 'x_base' => $s['x_base'], 'x_lang' => $s['x_lang']);
+        $this->addT($sup_s['value'], $this->rdf . 'rest', $coll['value'], $sup_s['type'], $coll['type']);
+        $this->addT($coll['value'], $this->rdf . 'first', $s['value'], $coll['type'], $s['type']);
+        $this->pushS($coll);
+      }
+      /* normal sub-node */
+      elseif(isset($sup_s['p']) && $sup_s['p']) {
+        $this->addT($sup_s['value'], $sup_s['p'], $s['value'], $sup_s['type'], $s['type']);
+      }
+    }
+    /* typed node */
+    if ($t !== $this->rdf.'Description') {
+      $this->addT($s['value'], $this->rdf.'type', $t, $s['type'], 'uri');
+    }
+    /* (additional) typing attr */
+    if (isset($a[$this->rdf.'type'])) {
+      $this->addT($s['value'], $this->rdf.'type', $a[$this->rdf.'type'], $s['type'], 'uri');
+    }
+    /* Seq|Bag|Alt */
+    if (in_array($t, array($this->rdf.'Seq', $this->rdf.'Bag', $this->rdf.'Alt'))) {
+      $s['is_con'] = true;
+    }
+    /* any other attrs (skip rdf and xml, except rdf:_, rdf:value, rdf:Seq) */
+    foreach($a as $k => $v) {
+      if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) || preg_match('/(\_[0-9]+|value|Seq|Bag|Alt|Statement|Property|List)$/', $k)) {
+        if (strpos($k, ':')) {
+          $this->addT($s['value'], $k, $v, $s['type'], 'literal', '', $s['x_lang']);
+        }
+      }
+    }
+    $this->pushS($s);
+    $this->state = 2;
+  }
+
+  /*  */
+
+  function h2Open($t, $a) {
+    $s = $this->getParentS();
+    foreach (array('p_x_base', 'p_x_lang', 'p_id', 'o_is_coll') as $k) {
+      unset($s[$k]);
+    }
+    /* base */
+    if (isset($a[$this->xml.'base'])) {
+      $s['p_x_base'] = $this->calcURI($a[$this->xml.'base'], $s['x_base']);
+    }
+    $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : $s['x_base'];
+    /* lang */
+    if (isset($a[$this->xml.'lang'])) {
+      $s['p_x_lang'] = $a[$this->xml.'lang'];
+    }
+    $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : $s['x_lang'];
+    /* adjust li */
+    if ($t === $this->rdf.'li') {
+      $s['li_count']++;
+      $t = $this->rdf.'_'.$s['li_count'];
+    }
+    /* set p */
+    $s['p'] = $t;
+		/* reification */
+    if (isset($a[$this->rdf.'ID'])) {
+      $s['p_id'] = $a[$this->rdf.'ID'];
+    }
+    $o = array('value' => '', 'type' => '', 'x_base' => $b, 'x_lang' => $l);
+    /* resource/rdf:resource */
+    if (isset($a['resource'])) {
+      $a[$this->rdf . 'resource'] = $a['resource'];
+      unset($a['resource']);
+    }
+    if (isset($a[$this->rdf.'resource'])) {
+      $o['value'] = $this->calcURI($a[$this->rdf.'resource'], $b);
+      $o['type'] = 'uri';
+      $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+      /* type */
+      if (isset($a[$this->rdf.'type'])) {
+        $this->addT($o['value'], $this->rdf.'type', $a[$this->rdf.'type'], 'uri', 'uri');
+      }
+      /* reification */
+      if (isset($s['p_id'])) {
+        $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+        unset($s['p_id']);
+      }
+      $this->state = 3;
+    }
+    /* named bnode */
+    elseif (isset($a[$this->rdf.'nodeID'])) {
+      $o['value'] = '_:' . $a[$this->rdf.'nodeID'];
+      $o['type'] = 'bnode';
+      $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+      $this->state = 3;
+      /* reification */
+      if (isset($s['p_id'])) {
+        $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+      }
+    }
+    /* parseType */
+    elseif (isset($a[$this->rdf.'parseType'])) {
+      if ($a[$this->rdf.'parseType'] === 'Literal') {
+        $s['o_xml_level'] = 0;
+        $s['o_xml_data'] = '';
+        $s['p_xml_literal_level'] = 0;
+        $s['ns'] = array();
+        $this->state = 6;
+      }
+      elseif ($a[$this->rdf.'parseType'] === 'Resource') {
+        $o['value'] = $this->createBnodeID();
+        $o['type'] = 'bnode';
+        $o['has_closing_tag'] = 0;
+        $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+        $this->pushS($o);
+        /* reification */
+        if (isset($s['p_id'])) {
+          $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+          unset($s['p_id']);
+        }
+        $this->state = 2;
+      }
+      elseif ($a[$this->rdf.'parseType'] === 'Collection') {
+        $s['o_is_coll'] = true;
+        $this->state = 4;
+      }
+    }
+    /* sub-node or literal */
+    else {
+      $s['o_cdata'] = '';
+      if (isset($a[$this->rdf.'datatype'])) {
+        $s['o_datatype'] = $a[$this->rdf.'datatype'];
+      }
+      $this->state = 4;
+    }
+    /* any other attrs (skip rdf and xml) */
+    foreach($a as $k => $v) {
+      if (((strpos($k, $this->xml) === false) && (strpos($k, $this->rdf) === false)) || preg_match('/(\_[0-9]+|value)$/', $k)) {
+        if (strpos($k, ':')) {
+          if (!$o['value']) {
+            $o['value'] = $this->createBnodeID();
+            $o['type'] = 'bnode';
+            $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+          }
+          /* reification */
+          if (isset($s['p_id'])) {
+            $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type']);
+            unset($s['p_id']);
+          }
+          $this->addT($o['value'], $k, $v, $o['type'], 'literal');
+          $this->state = 3;
+        }
+      }
+    }
+    $this->updateS($s);
+  }
+
+  /*  */
+
+  function h4Open($t, $a) {
+    return $this->h1Open($t, $a);
+  }
+  
+  /*  */
+
+  function h5Open($t, $a) {
+    $this->state = 4;
+    return $this->h4Open($t, $a);
+  }
+  
+  /*  */
+  
+  function h6Open($t, $a) {
+    $s = $this->getParentS();
+    $data = isset($s['o_xml_data']) ? $s['o_xml_data'] : '';
+    $ns = isset($s['ns']) ? $s['ns'] : array();
+    $parts = $this->splitURI($t);
+    if ((count($parts) === 1) || empty($parts[1])) {
+      $data .= '<'.$t;
+    }
+    else {
+      $ns_uri = $parts[0];
+      $name = $parts[1];
+      if (!isset($this->nsp[$ns_uri])) {
+        foreach ($this->nsp as $tmp1 => $tmp2) {
+          if (strpos($t, $tmp1) === 0) {
+            $ns_uri = $tmp1;
+            $name = substr($t, strlen($tmp1));
+            break;
+          }
+        }
+      }
+      $nsp = $this->nsp[$ns_uri];
+      $data .= $nsp ? '<' . $nsp . ':' . $name : '<' . $name;
+      /* ns */
+      if (!isset($ns[$nsp.'='.$ns_uri]) || !$ns[$nsp.'='.$ns_uri]) {
+        $data .= $nsp ? ' xmlns:'.$nsp.'="'.$ns_uri.'"' : ' xmlns="'.$ns_uri.'"';
+        $ns[$nsp.'='.$ns_uri] = true;
+        $s['ns'] = $ns;
+      }
+    }
+    foreach ($a as $k => $v) {
+      $parts = $this->splitURI($k);
+      if (count($parts) === 1) {
+        $data .= ' '.$k.'="'.$v.'"';
+      }
+      else {
+        $ns_uri = $parts[0];
+        $name = $parts[1];
+        $nsp = $this->v($ns_uri, '', $this->nsp);
+        $data .= $nsp ? ' '.$nsp.':'.$name.'="'.$v.'"' : ' '.$name.'="'.$v.'"' ;
+      }
+    }
+    $data .= '>';
+    $s['o_xml_data'] = $data;
+    $s['o_xml_level'] = isset($s['o_xml_level']) ? $s['o_xml_level'] + 1 : 1;
+    if ($t == $s['p']) {/* xml container prop */
+      $s['p_xml_literal_level'] = isset($s['p_xml_literal_level']) ? $s['p_xml_literal_level'] + 1 : 1;
+    }
+    $this->updateS($s);
+  }
+
+  /*  */
+
+  function h1Close($t) {/* end of doc */
+    $this->state = 0;
+  }
+  
+  /*  */
+  
+  function h2Close($t) {/* expecting a prop, getting a close */
+    if ($s = $this->getParentS()) {
+      $has_closing_tag = (isset($s['has_closing_tag']) && !$s['has_closing_tag']) ? 0 : 1;
+      $this->popS();
+      $this->state = 5;
+      if ($s = $this->getParentS()) {/* new s */
+        if (!isset($s['p']) || !$s['p']) {/* p close after collection|parseType=Resource|node close after p close */
+          $this->state = $this->s_count ? 4 : 1;
+          if (!$has_closing_tag) {
+            $this->state = 2;
+          }
+        }
+        elseif (!$has_closing_tag) {
+          $this->state = 2;
+        }
+      }
+    }
+  }
+  
+  /*  */
+  
+  function h3Close($t) {/* p close */
+    $this->state = 2;
+  }
+  
+  /*  */
+  
+  function h4Close($t) {/* empty p | pClose after cdata | pClose after collection */
+    if ($s = $this->getParentS()) {
+      $b = isset($s['p_x_base']) && $s['p_x_base'] ? $s['p_x_base'] : (isset($s['x_base']) ? $s['x_base'] : '');
+      if (isset($s['is_coll']) && $s['is_coll']) {
+        $this->addT($s['value'], $this->rdf . 'rest', $this->rdf . 'nil', $s['type'], 'uri');
+        /* back to collection start */
+        while ((!isset($s['p']) || ($s['p'] != $t))) {
+          $sub_s = $s;
+          $this->popS();
+          $s = $this->getParentS();
+        }
+        /* reification */
+        if (isset($s['p_id']) && $s['p_id']) {
+          $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $sub_s['value'], $s['type'], $sub_s['type']);
+        }
+        unset($s['p']);
+        $this->updateS($s);
+      }
+      else {
+        $dt = isset($s['o_datatype']) ? $s['o_datatype'] : '';
+        $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
+        $o = array('type' => 'literal', 'value' => $s['o_cdata']);
+        $this->addT($s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
+        /* reification */
+        if (isset($s['p_id']) && $s['p_id']) {
+          $this->reify($this->calcURI('#'.$s['p_id'], $b), $s['value'], $s['p'], $o['value'], $s['type'], $o['type'], $dt, $l);
+        }
+        unset($s['o_cdata']);
+        unset($s['o_datatype']);
+        unset($s['p']);
+        $this->updateS($s);
+      }
+      $this->state = 2;
+    }
+  }
+  
+  /*  */
+  
+  function h5Close($t) {/* p close */
+    if ($s = $this->getParentS()) {
+      unset($s['p']);
+      $this->updateS($s);
+      $this->state = 2;
+    }
+  }
+
+  /*  */
+
+  function h6Close($t) {
+    if ($s = $this->getParentS()) {
+      $l = isset($s['p_x_lang']) && $s['p_x_lang'] ? $s['p_x_lang'] : (isset($s['x_lang']) ? $s['x_lang'] : '');
+      $data = $s['o_xml_data'];
+      $level = $s['o_xml_level'];
+      if ($level === 0) {/* pClose */
+        $this->addT($s['value'], $s['p'], trim($data, ' '), $s['type'], 'literal', $this->rdf.'XMLLiteral', $l);
+        unset($s['o_xml_data']);
+        $this->state = 2;
+      }
+      else {
+        $parts = $this->splitURI($t);
+        if ((count($parts) === 1) || empty($parts[1])) {
+          $data .= '</'.$t.'>';
+        }
+        else {
+          $ns_uri = $parts[0];
+          $name = $parts[1];
+          if (!isset($this->nsp[$ns_uri])) {
+            foreach ($this->nsp as $tmp1 => $tmp2) {
+              if (strpos($t, $tmp1) === 0) {
+                $ns_uri = $tmp1;
+                $name = substr($t, strlen($tmp1));
+                break;
+              }
+            }
+          }
+          $nsp = $this->nsp[$ns_uri];
+          $data .= $nsp ? '</'.$nsp.':'.$name.'>' : '</'.$name.'>';
+        }
+        $s['o_xml_data'] = $data;
+        $s['o_xml_level'] = $level - 1;
+        if ($t == $s['p']) {/* xml container prop */
+          $s['p_xml_literal_level']--;
+        }
+      }
+      $this->updateS($s);
+    }
+  }
+  
+  /*  */
+  
+  function h4Cdata($d) {
+    if ($s = $this->getParentS()) {
+      $s['o_cdata'] = isset($s['o_cdata']) ? $s['o_cdata'] . $d : $d;
+      $this->updateS($s);
+    }
+  }
+  
+  /*  */
+
+  function h6Cdata($d) {
+    if ($s = $this->getParentS()) {
+      if (isset($s['o_xml_data']) || preg_match("/[\n\r]/", $d) || trim($d)) {
+        $d = htmlspecialchars($d, ENT_NOQUOTES);
+        $s['o_xml_data'] = isset($s['o_xml_data']) ? $s['o_xml_data'] . $d : $d;
+      }
+      $this->updateS($s);
+    }
+  }
+  
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_RSSParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,185 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 RSS Parser
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('LegacyXMLParser');
+
+class ARC2_RSSParser extends ARC2_LegacyXMLParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->triples = array();
+    $this->target_encoding = '';
+    $this->t_count = 0;
+    $this->added_triples = array();
+    $this->skip_dupes = false;
+    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+    $this->bnode_id = 0;
+    $this->cache = array();
+    $this->allowCDataNodes = 0;
+  }
+  
+  /*  */
+  
+  function done() {
+    $this->extractRDF();
+  }
+  
+  /*  */
+  
+  function setReader(&$reader) {
+    $this->reader = $reader;
+  }
+  
+  function createBnodeID(){
+    $this->bnode_id++;
+    return '_:' . $this->bnode_prefix . $this->bnode_id;
+  }
+  
+  function addT($t) {
+    //if (!isset($t['o_datatype']))
+    if ($this->skip_dupes) {
+      $h = md5(serialize($t));
+      if (!isset($this->added_triples[$h])) {
+        $this->triples[$this->t_count] = $t;
+        $this->t_count++;
+        $this->added_triples[$h] = true;
+      }
+    }
+    else {
+      $this->triples[$this->t_count] = $t;
+      $this->t_count++;
+    }
+  }
+
+  function getTriples() {
+    return $this->v('triples', array());
+  }
+
+  function countTriples() {
+    return $this->t_count;
+  }
+  
+  function getSimpleIndex($flatten_objects = 1, $vals = '') {
+    return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
+  }
+
+  /*  */
+
+  function extractRDF() {
+    $index = $this->getNodeIndex();
+    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->rss = 'http://purl.org/rss/1.0/';
+    $this->dc = 'http://purl.org/dc/elements/1.1/';
+    $this->dct = 'http://purl.org/dc/terms/';
+    $this->content = 'http://purl.org/rss/1.0/modules/content/';
+    $this->enc = 'http://purl.oclc.org/net/rss_2.0/enc#';
+    $this->mappings = array(
+      'channel' => $this->rss . 'channel',
+      'item' => $this->rss . 'item',
+      'title' => $this->rss . 'title',
+      'link' => $this->rss . 'link',
+      'description' => $this->rss . 'description',
+      'guid' => $this->dc . 'identifier',
+      'author' => $this->dc . 'creator',
+      'category' => $this->dc . 'subject',
+      'pubDate' => $this->dc . 'date',
+      'pubdate' => $this->dc . 'date',
+      'source' => $this->dc . 'source',
+      'enclosure' => $this->enc . 'enclosure',
+    );
+    $this->dt_props = array(
+      $this->dc . 'identifier',
+      $this->rss . 'link'
+    );
+    foreach ($index as $p_id => $nodes) {
+      foreach ($nodes as $pos => $node) {
+        $tag = $this->v('tag', '', $node);
+        if ($tag == 'channel') {
+          $struct = $this->extractChannel($index[$node['id']]);
+          $triples = ARC2::getTriplesFromIndex($struct);
+          foreach ($triples as $t) {
+            $this->addT($t);
+          }
+        }
+        elseif ($tag == 'item') {
+          $struct = $this->extractItem($index[$node['id']]);
+          $triples = ARC2::getTriplesFromIndex($struct);
+          foreach ($triples as $t) {
+            $this->addT($t);
+          }
+        }
+      }
+    }
+  }
+  
+  function extractChannel($els) {
+    $res = array($this->rdf . 'type' => array(array('value' => $this->rss . 'channel', 'type' => 'uri')));
+    $res = array_merge($res, $this->extractProps($els, 'channel'));
+    return array($res[$this->rss . 'link'][0]['value'] => $res);
+  }
+  
+  function extractItem($els) {
+    $res = array($this->rdf . 'type' => array(array('value' => $this->rss . 'item', 'type' => 'uri')));
+    $res = array_merge($res, $this->extractProps($els, 'item'));
+    if (isset($res[$this->rss . 'link'])) return array($res[$this->rss . 'link'][0]['value'] => $res);
+    if (isset($res[$this->dc . 'identifier'])) return array($res[$this->dc . 'identifier'][0]['value'] => $res);
+  }
+  
+  function extractProps($els, $container) {
+    $res = array();
+    foreach ($els as $info) {
+      /* key */
+      $tag = $info['tag'];
+      if (!preg_match('/^[a-z0-9]+\:/i', $tag)) {
+        $k = isset($this->mappings[$tag]) ? $this->mappings[$tag] : '';
+      }
+      else {
+        $k = $tag;
+      }
+      if (($container == 'channel') && ($k == $this->rss . 'item')) continue;
+      /* val */
+      $v = $info['cdata'];
+      if (!$v) $v = $this->v('url', '', $info['a']);
+      if (!$v) $v = $this->v('href', '', $info['a']);
+      /* prop */
+      if ($k) {
+        /* enclosure handling */
+        if ($k == $this->enc . 'enclosure') {
+          $sub_res = array();
+          foreach (array('length', 'type') as $attr) {
+            if ($attr_v = $this->v($attr, 0, $info['a'])) {
+              $sub_res[$this->enc . $attr] = array(array('value' => $attr_v, 'type' => 'literal'));
+            }
+          }
+          $struct[$v] = $sub_res;
+        }
+        /* date handling */
+        if (in_array($k, array($this->dc . 'date', $this->dct . 'modified'))) {
+          if (!preg_match('/^[0-9]{4}/', $v) && ($sub_v = strtotime($v)) && ($sub_v != -1)) {
+            $tz = date('Z', $sub_v); /* timezone offset */
+            $sub_v -= $tz; /* utc */
+            $v = date('Y-m-d\TH:i:s\Z', $sub_v);
+          }
+        }
+        if (!isset($res[$k])) $res[$k] = array();
+        $res[$k][] = array('value' => $v, 'type' => in_array($k, $this->dt_props) || !preg_match('/^[a-z0-9]+\:[^\s]+$/is', $v) ? 'literal' : 'uri');
+      }
+    }
+    return $res;
+  }
+  
+  /*  */
+
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_SGAJSONParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,63 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 SG API JSON Parser
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('JSONParser');
+
+class ARC2_SGAJSONParser extends ARC2_JSONParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->nsp = array($this->rdf => 'rdf');
+  }
+  
+  /*  */
+
+  function done() {
+    $this->extractRDF();
+  }
+  
+  function extractRDF() {
+    $s = $this->getContext();
+    $os = $this->getURLs($this->struct);
+    foreach ($os as $o) {
+      if ($o != $s) $this->addT($s, 'http://www.w3.org/2000/01/rdf-schema#seeAlso', $o, 'uri', 'uri');
+    }
+  }
+  
+  function getContext() {
+    if (!isset($this->struct['canonical_mapping'])) return '';
+    foreach ($this->struct['canonical_mapping'] as $k => $v) return $v;
+  }
+  
+  function getURLs($struct) {
+    $r =array();
+    if (is_array($struct)) {
+      foreach ($struct as $k => $v) {
+        if (preg_match('/^http:\/\//', $k) && !in_array($k, $r)) $r[] = $k;
+        $sub_r = $this->getURLs($v);
+        foreach ($sub_r as $sub_v) {
+          if (!in_array($sub_v, $r)) $r[] = $sub_v;
+        }
+      }
+    }
+    elseif (preg_match('/^http:\/\//', $struct) && !in_array($struct, $r)) {
+      $r[] = $struct;
+    }
+    return $r;
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_SPARQLParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,777 @@
+<?php
+/**
+ * ARC2 SPARQL Parser
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('TurtleParser');
+
+class ARC2_SPARQLParser extends ARC2_TurtleParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+
+  function __init() {
+    parent::__init();
+    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+    $this->bnode_id = 0;
+    $this->bnode_pattern_index = array('patterns' => array(), 'bnodes' => array());
+  }
+
+  /*  */
+
+  function parse($q, $src = '', $iso_fallback = 'ignore') {
+    $this->setDefaultPrefixes();
+    $this->base = $src ? $this->calcBase($src) : ARC2::getRequestURI();
+    $this->r = array(
+      'base' => '',
+      'vars' => array(),
+      'prefixes' => array()
+    );
+    $this->unparsed_code = $q;
+    list($r, $v) = $this->xQuery($q);
+    if ($r) {
+      $this->r['query'] = $r;
+      $this->unparsed_code = trim($v);
+    }
+    elseif (!$this->getErrors() && !$this->unparsed_code) {
+      $this->addError('Query not properly closed');
+    }
+    $this->r['prefixes'] = $this->prefixes;
+    $this->r['base'] = $this->base;
+    /* remove trailing comments */
+    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2];
+    if ($this->unparsed_code && !$this->getErrors()) {
+      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
+      $msg = trim($rest) ? 'Could not properly handle "' . $rest . '"' : 'Syntax error, probably an incomplete pattern';
+      $this->addError($msg);
+    }
+  }
+
+  function getQueryInfos() {
+    return $this->v('r', array());
+  }
+
+  /* 1 */
+
+  function xQuery($v) {
+    list($r, $v) = $this->xPrologue($v);
+    foreach (array('Select', 'Construct', 'Describe', 'Ask') as $type) {
+      $m = 'x' . $type . 'Query';
+      if ((list($r, $v) = $this->$m($v)) && $r) {
+        return array($r, $v);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 2 */
+
+  function xPrologue($v) {
+    $r = 0;
+    if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
+      $this->base = $sub_r;
+      $r = 1;
+    }
+    while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
+      $this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
+      $r = 1;
+    }
+    return array($r, $v);
+  }
+
+  /* 5.. */
+
+  function xSelectQuery($v) {
+    if ($sub_r = $this->x('SELECT\s+', $v)) {
+      $r = array(
+        'type' => 'select',
+        'result_vars' => array(),
+        'dataset' => array(),
+      );
+      $all_vars = 0;
+      $sub_v = $sub_r[1];
+      /* distinct, reduced */
+      if ($sub_r = $this->x('(DISTINCT|REDUCED)\s+', $sub_v)) {
+        $r[strtolower($sub_r[1])] = 1;
+        $sub_v = $sub_r[2];
+      }
+      /* result vars */
+      if ($sub_r = $this->x('\*\s+', $sub_v)) {
+        $all_vars = 1;
+        $sub_v = $sub_r[1];
+      }
+      else {
+        while ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) {
+          $r['result_vars'][] = $sub_r;
+        }
+      }
+      if (!$all_vars && !count($r['result_vars'])) {
+        $this->addError('No result bindings specified.');
+      }
+      /* dataset */
+      while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+        $r['dataset'][] = $sub_r;
+      }
+      /* where */
+      if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+        $r['pattern'] = $sub_r;
+      }
+      else {
+        return array(0, $v);
+      }
+      /* solution modifier */
+      if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+        $r = array_merge($r, $sub_r);
+      }
+      /* all vars */
+      if ($all_vars) {
+        foreach ($this->r['vars'] as $var) {
+          $r['result_vars'][] = array('var' => $var, 'aggregate' => 0, 'alias' => '');
+        }
+        if (!$r['result_vars']) {
+          $r['result_vars'][] = '*';
+        }
+      }
+      return array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  function xResultVar($v) {
+    return $this->xVar($v);
+  }
+
+  /* 6.. */
+
+  function xConstructQuery($v) {
+    if ($sub_r = $this->x('CONSTRUCT\s*', $v)) {
+      $r = array(
+        'type' => 'construct',
+        'dataset' => array(),
+      );
+      $sub_v = $sub_r[1];
+      /* construct template */
+      if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
+        $r['construct_triples'] = $sub_r;
+      }
+      else {
+        $this->addError('Construct Template not found');
+        return array(0, $v);
+      }
+      /* dataset */
+      while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+        $r['dataset'][] = $sub_r;
+      }
+      /* where */
+      if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+        $r['pattern'] = $sub_r;
+      }
+      else {
+        return array(0, $v);
+      }
+      /* solution modifier */
+      if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+        $r = array_merge($r, $sub_r);
+      }
+      return array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 7.. */
+
+  function xDescribeQuery($v) {
+    if ($sub_r = $this->x('DESCRIBE\s+', $v)) {
+      $r = array(
+        'type' => 'describe',
+        'result_vars' => array(),
+        'result_uris' => array(),
+        'dataset' => array(),
+      );
+      $sub_v = $sub_r[1];
+      $all_vars = 0;
+      /* result vars/uris */
+      if ($sub_r = $this->x('\*\s+', $sub_v)) {
+        $all_vars = 1;
+        $sub_v = $sub_r[1];
+      }
+      else {
+        do {
+          $proceed = 0;
+          if ((list($sub_r, $sub_v) = $this->xResultVar($sub_v)) && $sub_r) {
+            $r['result_vars'][] = $sub_r;
+            $proceed = 1;
+          }
+          if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+            $r['result_uris'][] = $sub_r;
+            $proceed =1;
+          }
+        } while ($proceed);
+      }
+      if (!$all_vars && !count($r['result_vars']) && !count($r['result_uris'])) {
+        $this->addError('No result bindings specified.');
+      }
+      /* dataset */
+      while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+        $r['dataset'][] = $sub_r;
+      }
+      /* where */
+      if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+        $r['pattern'] = $sub_r;
+      }
+      /* solution modifier */
+      if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+        $r = array_merge($r, $sub_r);
+      }
+      /* all vars */
+      if ($all_vars) {
+        foreach ($this->r['vars'] as $var) {
+          $r['result_vars'][] = array('var' => $var, 'aggregate' => 0, 'alias' => '');
+        }
+      }
+      return array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 8.. */
+
+  function xAskQuery($v) {
+    if ($sub_r = $this->x('ASK\s+', $v)) {
+      $r = array(
+        'type' => 'ask',
+        'dataset' => array(),
+      );
+      $sub_v = $sub_r[1];
+      /* dataset */
+      while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+        $r['dataset'][] = $sub_r;
+      }
+      /* where */
+      if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+        $r['pattern'] = $sub_r;
+        return array($r, $sub_v);
+      }
+      else {
+        $this->addError('Missing or invalid WHERE clause.');
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 9, 10, 11, 12 */
+
+  function xDatasetClause($v) {
+    if ($r = $this->x('FROM(\s+NAMED)?\s+', $v)) {
+      $named = $r[1] ? 1 : 0;
+      if ((list($r, $sub_v) = $this->xIRIref($r[2])) && $r) {
+        return array(array('graph' => $r, 'named' => $named), $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 13 */
+
+  function xWhereClause($v) {
+    if ($r = $this->x('(WHERE)?', $v)) {
+      $v = $r[2];
+    }
+    if ((list($r, $v) = $this->xGroupGraphPattern($v)) && $r) {
+      return array($r, $v);
+    }
+    return array(0, $v);
+  }
+
+  /* 14, 15 */
+
+  function xSolutionModifier($v) {
+    $r = array();
+    if ((list($sub_r, $sub_v) = $this->xOrderClause($v)) && $sub_r) {
+      $r['order_infos'] = $sub_r;
+    }
+    while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
+      $r = array_merge($r, $sub_r);
+    }
+    return ($v == $sub_v) ? array(0, $v) : array($r, $sub_v);
+  }
+
+  /* 18, 19 */
+
+  function xLimitOrOffsetClause($v) {
+    if ($sub_r = $this->x('(LIMIT|OFFSET)', $v)) {
+      $key = strtolower($sub_r[1]);
+      $sub_v = $sub_r[2];
+      if ((list($sub_r, $sub_v) = $this->xINTEGER($sub_v)) && ($sub_r !== false)) {
+        return array(array($key =>$sub_r), $sub_v);
+      }
+      if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && ($sub_r !== false)) {
+        return array(array($key =>$sub_r), $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 16 */
+
+  function xOrderClause($v) {
+    if ($sub_r = $this->x('ORDER BY\s+', $v)) {
+      $sub_v = $sub_r[1];
+      $r = array();
+      while ((list($sub_r, $sub_v) = $this->xOrderCondition($sub_v)) && $sub_r) {
+        $r[] = $sub_r;
+      }
+      if (count($r)) {
+        return array($r, $sub_v);
+      }
+      else {
+        $this->addError('No order conditions specified.');
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 17, 27 */
+
+  function xOrderCondition($v) {
+    if ($sub_r = $this->x('(ASC|DESC)', $v)) {
+      $dir = strtolower($sub_r[1]);
+      $sub_v = $sub_r[2];
+      if ((list($sub_r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $sub_r) {
+        $sub_r['direction'] = $dir;
+        return array($sub_r, $sub_v);
+      }
+    }
+    elseif ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
+      $sub_r['direction'] = 'asc';
+      return array($sub_r, $sub_v);
+    }
+    elseif ((list($sub_r, $sub_v) = $this->xBrackettedExpression($v)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    elseif ((list($sub_r, $sub_v) = $this->xBuiltInCall($v)) && $sub_r) {
+      $sub_r['direction'] = 'asc';
+      return array($sub_r, $sub_v);
+    }
+    elseif ((list($sub_r, $sub_v) = $this->xFunctionCall($v)) && $sub_r) {
+      $sub_r['direction'] = 'asc';
+      return array($sub_r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 20 */
+
+  function xGroupGraphPattern($v) {
+    $pattern_id = substr(md5(uniqid(rand())), 0, 4);
+    if ($sub_r = $this->x('\{', $v)) {
+      $r = array('type' => 'group', 'patterns' => array());
+      $sub_v = $sub_r[1];
+      if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) {
+        $this->indexBnodes($sub_r, $pattern_id);
+        $r['patterns'][] = array('type' => 'triples', 'patterns' => $sub_r);
+      }
+      do {
+        $proceed = 0;
+        if ((list($sub_r, $sub_v) = $this->xGraphPatternNotTriples($sub_v)) && $sub_r) {
+          $r['patterns'][] = $sub_r;
+          $pattern_id = substr(md5(uniqid(rand())), 0, 4);
+          $proceed = 1;
+        }
+        elseif ((list($sub_r, $sub_v) = $this->xFilter($sub_v)) && $sub_r) {
+          $r['patterns'][] = array('type' => 'filter', 'constraint' => $sub_r);
+          $proceed = 1;
+        }
+        if ($sub_r = $this->x('\.', $sub_v)) {
+          $sub_v = $sub_r[1];
+        }
+        if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_v)) && $sub_r) {
+          $this->indexBnodes($sub_r, $pattern_id);
+          $r['patterns'][] = array('type' => 'triples', 'patterns' => $sub_r);
+          $proceed = 1;
+        }
+        if ((list($sub_r, $sub_v) = $this->xPlaceholder($sub_v)) && $sub_r) {
+          $r['patterns'][] = $sub_r;
+          $proceed = 1;
+        }
+      } while ($proceed);
+      if ($sub_r = $this->x('\}', $sub_v)) {
+        $sub_v = $sub_r[1];
+        return array($r, $sub_v);
+      }
+      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($sub_v, 0, 30));
+      $this->addError('Incomplete or invalid Group Graph pattern. Could not handle "' . $rest . '"');
+    }
+    return array(0, $v);
+  }
+
+  function indexBnodes($triples, $pattern_id) {
+    $index_id = count($this->bnode_pattern_index['patterns']);
+    $index_id = $pattern_id;
+    $this->bnode_pattern_index['patterns'][] = $triples;
+    foreach ($triples as $t) {
+      foreach (array('s', 'p', 'o') as $term) {
+        if ($t[$term . '_type'] == 'bnode') {
+          $val = $t[$term];
+          if (isset($this->bnode_pattern_index['bnodes'][$val]) && ($this->bnode_pattern_index['bnodes'][$val] != $index_id)) {
+            $this->addError('Re-used bnode label "' .$val. '" across graph patterns');
+          }
+          else {
+            $this->bnode_pattern_index['bnodes'][$val] = $index_id;
+          }
+        }
+      }
+    }
+  }
+
+  /* 22.., 25.. */
+
+  function xGraphPatternNotTriples($v) {
+    if ((list($sub_r, $sub_v) = $this->xOptionalGraphPattern($v)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    if ((list($sub_r, $sub_v) = $this->xGraphGraphPattern($v)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    $r = array('type' => 'union', 'patterns' => array());
+    $sub_v = $v;
+    do {
+      $proceed = 0;
+      if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
+        $r['patterns'][] = $sub_r;
+        if ($sub_r = $this->x('UNION', $sub_v)) {
+          $sub_v = $sub_r[1];
+          $proceed = 1;
+        }
+      }
+    } while ($proceed);
+    $pc = count($r['patterns']);
+    if ($pc == 1) {
+      return array($r['patterns'][0], $sub_v);
+    }
+    elseif ($pc > 1) {
+      return array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 23 */
+
+  function xOptionalGraphPattern($v) {
+    if ($sub_r = $this->x('OPTIONAL', $v)) {
+      $sub_v = $sub_r[1];
+      if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
+        return array(array('type' => 'optional', 'patterns' => $sub_r['patterns']), $sub_v);
+      }
+      $this->addError('Missing or invalid Group Graph Pattern after OPTIONAL');
+    }
+    return array(0, $v);
+  }
+
+  /* 24.. */
+
+  function xGraphGraphPattern($v) {
+    if ($sub_r = $this->x('GRAPH', $v)) {
+      $sub_v = $sub_r[1];
+      $r = array('type' => 'graph', 'var' => '', 'uri' => '', 'patterns' => array());
+      if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
+        $r['var'] = $sub_r;
+      }
+      elseif ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+        $r['uri'] = $sub_r;
+      }
+      if ($r['var'] || $r['uri']) {
+        if ((list($sub_r, $sub_v) = $this->xGroupGraphPattern($sub_v)) && $sub_r) {
+          $r['patterns'][] = $sub_r;
+          return array($r, $sub_v);
+        }
+        $this->addError('Missing or invalid Graph Pattern');
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 26.., 27.. */
+
+  function xFilter($v) {
+    if ($r = $this->x('FILTER', $v)) {
+      $sub_v = $r[1];
+      if ((list($r, $sub_v) = $this->xBrackettedExpression($sub_v)) && $r) {
+        return array($r, $sub_v);
+      }
+      if ((list($r, $sub_v) = $this->xBuiltInCall($sub_v)) && $r) {
+        return array($r, $sub_v);
+      }
+      if ((list($r, $sub_v) = $this->xFunctionCall($sub_v)) && $r) {
+        return array($r, $sub_v);
+      }
+      $this->addError('Incomplete FILTER');
+    }
+    return array(0, $v);
+  }
+
+  /* 28.. */
+
+  function xFunctionCall($v) {
+    if ((list($r, $sub_v) = $this->xIRIref($v)) && $r) {
+      if ((list($sub_r, $sub_v) = $this->xArgList($sub_v)) && $sub_r) {
+        return array(array('type' => 'function_call', 'uri' => $r, 'args' => $sub_r), $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 29 */
+
+  function xArgList($v) {
+    $r = array();
+    $sub_v = $v;
+    $closed = 0;
+    if ($sub_r = $this->x('\(', $sub_v)) {
+      $sub_v = $sub_r[1];
+      do {
+        $proceed = 0;
+        if ((list($sub_r, $sub_v) = $this->xExpression($sub_v)) && $sub_r) {
+          $r[] = $sub_r;
+          if ($sub_r = $this->x('\,', $sub_v)) {
+            $sub_v = $sub_r[1];
+            $proceed = 1;
+          }
+        }
+        if ($sub_r = $this->x('\)', $sub_v)) {
+         $sub_v = $sub_r[1];
+         $closed = 1;
+         $proceed = 0;
+        }
+      } while ($proceed);
+    }
+    return $closed ? array($r, $sub_v) : array(0, $v);
+  }
+
+  /* 30, 31 */
+
+  function xConstructTemplate($v) {
+    if ($sub_r = $this->x('\{', $v)) {
+      $r = array();
+      if ((list($sub_r, $sub_v) = $this->xTriplesBlock($sub_r[1])) && is_array($sub_r)) {
+        $r = $sub_r;
+      }
+      if ($sub_r = $this->x('\}', $sub_v)) {
+        return array($r, $sub_r[1]);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 46, 47 */
+
+  function xExpression($v) {
+    if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($v)) && $sub_r) {
+      $r = array('type' => 'expression', 'sub_type' => 'or', 'patterns' => array($sub_r));
+      do {
+        $proceed = 0;
+        if ($sub_r = $this->x('\|\|', $sub_v)) {
+          $sub_v = $sub_r[1];
+          if ((list($sub_r, $sub_v) = $this->xConditionalAndExpression($sub_v)) && $sub_r) {
+            $r['patterns'][] = $sub_r;
+            $proceed = 1;
+          }
+        }
+      } while ($proceed);
+      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 48.., 49.. */
+
+  function xConditionalAndExpression($v) {
+    if ((list($sub_r, $sub_v) = $this->xRelationalExpression($v)) && $sub_r) {
+      $r = array('type' => 'expression', 'sub_type' => 'and', 'patterns' => array($sub_r));
+      do {
+        $proceed = 0;
+        if ($sub_r = $this->x('\&\&', $sub_v)) {
+          $sub_v = $sub_r[1];
+          if ((list($sub_r, $sub_v) = $this->xRelationalExpression($sub_v)) && $sub_r) {
+            $r['patterns'][] = $sub_r;
+            $proceed = 1;
+          }
+        }
+      } while ($proceed);
+      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 50, 51 */
+
+  function xRelationalExpression($v) {
+    if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($v)) && $sub_r) {
+      $r = array('type' => 'expression', 'sub_type' => 'relational', 'patterns' => array($sub_r));
+      do {
+        $proceed = 0;
+        /* don't mistake '<' + uriref with '<'-operator ("longest token" rule) */
+        if ((list($sub_r, $sub_v) = $this->xIRI_REF($sub_v)) && $sub_r) {
+          $this->addError('Expected operator, found IRIref: "'.$sub_r.'".');
+        }
+        if ($sub_r = $this->x('(\!\=|\=\=|\=|\<\=|\>\=|\<|\>)', $sub_v)) {
+          $op = $sub_r[1];
+          $sub_v = $sub_r[2];
+          $r['operator'] = $op;
+          if ((list($sub_r, $sub_v) = $this->xAdditiveExpression($sub_v)) && $sub_r) {
+            //$sub_r['operator'] = $op;
+            $r['patterns'][] = $sub_r;
+            $proceed = 1;
+          }
+        }
+      } while ($proceed);
+      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 52 */
+
+  function xAdditiveExpression($v) {
+    if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($v)) && $sub_r) {
+      $r = array('type' => 'expression', 'sub_type' => 'additive', 'patterns' => array($sub_r));
+      do {
+        $proceed = 0;
+        if ($sub_r = $this->x('(\+|\-)', $sub_v)) {
+          $op = $sub_r[1];
+          $sub_v = $sub_r[2];
+          if ((list($sub_r, $sub_v) = $this->xMultiplicativeExpression($sub_v)) && $sub_r) {
+            $sub_r['operator'] = $op;
+            $r['patterns'][] = $sub_r;
+            $proceed = 1;
+          }
+          elseif ((list($sub_r, $sub_v) = $this->xNumericLiteral($sub_v)) && $sub_r) {
+            $r['patterns'][] = array('type' => 'numeric', 'operator' => $op, 'value' => $sub_r);
+            $proceed = 1;
+          }
+        }
+      } while ($proceed);
+      //return array($r, $sub_v);
+      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 53 */
+
+  function xMultiplicativeExpression($v) {
+    if ((list($sub_r, $sub_v) = $this->xUnaryExpression($v)) && $sub_r) {
+      $r = array('type' => 'expression', 'sub_type' => 'multiplicative', 'patterns' => array($sub_r));
+      do {
+        $proceed = 0;
+        if ($sub_r = $this->x('(\*|\/)', $sub_v)) {
+          $op = $sub_r[1];
+          $sub_v = $sub_r[2];
+          if ((list($sub_r, $sub_v) = $this->xUnaryExpression($sub_v)) && $sub_r) {
+            $sub_r['operator'] = $op;
+            $r['patterns'][] = $sub_r;
+            $proceed = 1;
+          }
+        }
+      } while ($proceed);
+      return count($r['patterns']) == 1 ? array($r['patterns'][0], $sub_v) : array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 54 */
+
+  function xUnaryExpression($v) {
+    $sub_v = $v;
+    $op = '';
+    if ($sub_r = $this->x('(\!|\+|\-)', $sub_v)) {
+      $op = $sub_r[1];
+      $sub_v = $sub_r[2];
+    }
+    if ((list($sub_r, $sub_v) = $this->xPrimaryExpression($sub_v)) && $sub_r) {
+      if (!is_array($sub_r)) {
+        $sub_r = array('type' => 'unary', 'expression' => $sub_r);
+      }
+      elseif ($sub_op = $this->v1('operator', '', $sub_r)) {
+        $ops = array('!!' => '', '++' => '+', '--' => '+', '+-' => '-', '-+' => '-');
+        $op = isset($ops[$op . $sub_op]) ? $ops[$op . $sub_op] : $op . $sub_op;
+      }
+      $sub_r['operator'] = $op;
+      return array($sub_r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 55 */
+
+  function xPrimaryExpression($v) {
+    foreach (array('BrackettedExpression', 'BuiltInCall', 'IRIrefOrFunction', 'RDFLiteral', 'NumericLiteral', 'BooleanLiteral', 'Var', 'Placeholder') as $type) {
+      $m = 'x' . $type;
+      if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
+        return array($sub_r, $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 56 */
+
+  function xBrackettedExpression($v) {
+    if ($r = $this->x('\(', $v)) {
+      if ((list($r, $sub_v) = $this->xExpression($r[1])) && $r) {
+        if ($sub_r = $this->x('\)', $sub_v)) {
+          return array($r, $sub_r[1]);
+        }
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 57.., 58.. */
+
+  function xBuiltInCall($v) {
+    if ($sub_r = $this->x('(str|lang|langmatches|datatype|bound|sameterm|isiri|isuri|isblank|isliteral|regex)\s*\(', $v)) {
+      $r = array('type' => 'built_in_call', 'call' => strtolower($sub_r[1]));
+      if ((list($sub_r, $sub_v) = $this->xArgList('(' . $sub_r[2])) && is_array($sub_r)) {
+        $r['args'] = $sub_r;
+        return array($r, $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 59.. */
+
+  function xIRIrefOrFunction($v) {
+    if ((list($r, $v) = $this->xIRIref($v)) && $r) {
+      if ((list($sub_r, $sub_v) = $this->xArgList($v)) && is_array($sub_r)) {
+        return array(array('type' => 'function', 'uri' => $r, 'args' => $sub_r), $sub_v);
+      }
+      return array(array('type' => 'uri', 'uri' => $r), $sub_v);
+    }
+  }
+
+  /* 70.. @@sync with TurtleParser */
+
+  function xIRI_REF($v) {
+    if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
+      return array($r[1], $r[2]);
+    }
+    elseif ($r = $this->x('\<([^\<\>\s\"\|\^`]*)\>', $v)) {
+      return array($r[1] ? $r[1] : true, $r[2]);
+    }
+    /* allow reserved chars in obvious IRIs */
+    elseif ($r = $this->x('\<(https?\:[^\s][^\<\>]*)\>', $v)) {
+      return array($r[1] ? $r[1] : true, $r[2]);
+    }
+    return array(0, $v);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_SPARQLPlusParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,210 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 SPARQL+ Parser (SPARQL + Aggregates + LOAD + INSERT + DELETE)
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('SPARQLParser');
+
+class ARC2_SPARQLPlusParser extends ARC2_SPARQLParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /* +1 */
+  
+  function xQuery($v) {
+    list($r, $v) = $this->xPrologue($v);
+    foreach (array('Select', 'Construct', 'Describe', 'Ask', 'Insert', 'Delete', 'Load') as $type) {
+      $m = 'x' . $type . 'Query';
+      if ((list($r, $v) = $this->$m($v)) && $r) {
+        return array($r, $v);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* +3 */
+  
+  function xResultVar($v) {
+    $aggregate = '';
+    /* aggregate */
+    if ($sub_r = $this->x('\(?(AVG|COUNT|MAX|MIN|SUM)\s*\(\s*([^\)]+)\)\s+AS\s+([^\s\)]+)\)?', $v)) {
+      $aggregate = $sub_r[1];
+      $result_var = $sub_r[3];
+      $v = $sub_r[2] . $sub_r[4];
+    }
+    if ($sub_r && (list($sub_r, $sub_v) = $this->xVar($result_var)) && $sub_r) {
+      $result_var = $sub_r['value'];
+    }
+    /* * or var */
+    if ((list($sub_r, $sub_v) = $this->x('\*', $v)) && $sub_r) {
+      return array(array('var' => $sub_r['value'], 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''), $sub_v);
+    }
+    if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
+      return array(array('var' => $sub_r['value'], 'aggregate' => $aggregate, 'alias' => $aggregate ? $result_var : ''), $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* +4 */
+ 
+  function xLoadQuery($v) {
+    if ($sub_r = $this->x('LOAD\s+', $v)) {
+      $sub_v = $sub_r[1];
+      if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+        $r = array('type' => 'load', 'url' => $sub_r, 'target_graph' => '');
+        if ($sub_r = $this->x('INTO\s+', $sub_v)) {
+          $sub_v = $sub_r[1];
+          if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+            $r['target_graph'] = $sub_r;
+          }
+        }
+        return array($r, $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /* +5 */
+  
+  function xInsertQuery($v) {
+    if ($sub_r = $this->x('INSERT\s+', $v)) {
+      $r = array(
+        'type' => 'insert',
+        'dataset' => array(),
+      );
+      $sub_v = $sub_r[1];
+      /* target */
+      if ($sub_r = $this->x('INTO\s+', $sub_v)) {
+        $sub_v = $sub_r[1];
+        if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+          $r['target_graph'] = $sub_r;
+          /* CONSTRUCT keyword, optional */
+          if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
+            $sub_v = $sub_r[1];
+          }
+          /* construct template */
+          if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
+            $r['construct_triples'] = $sub_r;
+          }
+          else {
+            $this->addError('Construct Template not found');
+            return array(0, $v);
+          }
+          /* dataset */
+          while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+            $r['dataset'][] = $sub_r;
+          }
+          /* where */
+          if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+            $r['pattern'] = $sub_r;
+          }
+          /* solution modifier */
+          if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+            $r = array_merge($r, $sub_r);
+          }
+          return array($r, $sub_v);
+        }
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* +6 */
+  
+  function xDeleteQuery($v) {
+    if ($sub_r = $this->x('DELETE\s+', $v)) {
+      $r = array(
+        'type' => 'delete',
+        'target_graphs' => array()
+      );
+      $sub_v = $sub_r[1];
+      /* target */
+      do {
+        $proceed = false;
+        if ($sub_r = $this->x('FROM\s+', $sub_v)) {
+          $sub_v = $sub_r[1];
+          if ((list($sub_r, $sub_v) = $this->xIRIref($sub_v)) && $sub_r) {
+            $r['target_graphs'][] = $sub_r;
+            $proceed = 1;
+          }
+        }
+      } while ($proceed);
+      /* CONSTRUCT keyword, optional */
+      if ($sub_r = $this->x('CONSTRUCT\s+', $sub_v)) {
+        $sub_v = $sub_r[1];
+      }
+      /* construct template */
+      if ((list($sub_r, $sub_v) = $this->xConstructTemplate($sub_v)) && is_array($sub_r)) {
+        $r['construct_triples'] = $sub_r;
+        /* dataset */
+        while ((list($sub_r, $sub_v) = $this->xDatasetClause($sub_v)) && $sub_r) {
+          $r['dataset'][] = $sub_r;
+        }
+        /* where */
+        if ((list($sub_r, $sub_v) = $this->xWhereClause($sub_v)) && $sub_r) {
+          $r['pattern'] = $sub_r;
+        }
+        /* solution modifier */
+        if ((list($sub_r, $sub_v) = $this->xSolutionModifier($sub_v)) && $sub_r) {
+          $r = array_merge($r, $sub_r);
+        }
+      }
+      return array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+  
+  /* +7 */
+  
+  function xSolutionModifier($v) {
+    $r = array();
+    if ((list($sub_r, $sub_v) = $this->xGroupClause($v)) && $sub_r) {
+      $r['group_infos'] = $sub_r;
+    }
+    if ((list($sub_r, $sub_v) = $this->xOrderClause($sub_v)) && $sub_r) {
+      $r['order_infos'] = $sub_r;
+    }
+    while ((list($sub_r, $sub_v) = $this->xLimitOrOffsetClause($sub_v)) && $sub_r) {
+      $r = array_merge($r, $sub_r);
+    }
+    return ($v == $sub_v) ? array(0, $v) : array($r, $sub_v);
+  }
+
+  /* +8 */
+
+  function xGroupClause($v) {
+    if ($sub_r = $this->x('GROUP BY\s+', $v)) {
+      $sub_v = $sub_r[1];
+      $r = array();
+      do {
+        $proceed = 0;
+        if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
+          $r[] = $sub_r;
+          $proceed = 1;
+          if ($sub_r = $this->x('\,', $sub_v)) {
+            $sub_v = $sub_r[1];
+          }
+        }
+      } while ($proceed);
+      if (count($r)) {
+        return array($r, $sub_v);
+      }
+      else {
+        $this->addError('No columns specified in GROUP BY clause.');
+      }
+    }
+    return array(0, $v);
+  }
+
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_SPARQLXMLResultParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,112 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 SPARQL Result XML Parser
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('LegacyXMLParser');
+
+class ARC2_SPARQLXMLResultParser extends ARC2_LegacyXMLParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->srx = 'http://www.w3.org/2005/sparql-results#';
+    $this->nsp[$this->srx] = 'srx';
+    $this->allowCDataNodes = 0;
+  }
+  
+  /*  */
+  
+  function done() {
+  }
+  
+  /*  */
+  
+  function getVariables() {
+    $r = array();
+    foreach ($this->nodes as $node) {
+      if ($node['tag'] == $this->srx . 'variable') {
+        $r[] = $node['a']['name'];
+      }
+    }
+    return $r;
+  }
+  
+  function getRows() {
+    $r = array();
+    $index = $this->getNodeIndex();
+    foreach ($this->nodes as $node) {
+      if ($node['tag'] == $this->srx . 'result') {
+        $row = array();
+        $row_id = $node['id'];
+        $bindings = isset($index[$row_id])? $index[$row_id] : array();
+        foreach ($bindings as $binding) {
+          $row = array_merge($row, $this->getBinding($binding));
+        }
+        if ($row) {
+          $r[] = $row;
+        }
+      }
+    }
+    return $r;
+  }
+
+  function getBinding($node) {
+    $r = array();
+    $index = $this->getNodeIndex();
+    $var = $node['a']['name'];
+    $term = $index[$node['id']][0];
+    $r[$var . ' type'] = preg_replace('/^uri$/', 'uri', substr($term['tag'], strlen($this->srx)));
+    $r[$var] = ($r[$var . ' type'] == 'bnode') ? '_:' . $term['cdata'] : $term['cdata'];
+    if (isset($term['a']['datatype'])) {
+      $r[$var . ' datatype'] = $term['a']['datatype'];
+    }
+    elseif (isset($term['a'][$this->xml . 'lang'])) {
+      $r[$var . ' lang'] = $term['a'][$this->xml . 'lang'];
+    }
+    return $r;
+  }
+
+  function getBooleanInsertedDeleted() {
+    foreach ($this->nodes as $node) {
+      if ($node['tag'] == $this->srx . 'boolean') {
+        return ($node['cdata'] == 'true') ? array('boolean' => true) : array('boolean' => false);
+      }
+      elseif ($node['tag'] == $this->srx . 'inserted') {
+        return array('inserted' => $node['cdata']);
+      }
+      elseif ($node['tag'] == $this->srx . 'deleted') {
+        return array('deleted' => $node['cdata']);
+      }
+      elseif ($node['tag'] == $this->srx . 'results') {
+        return '';
+      }
+    }
+    return '';
+  }
+
+  /*  */
+  
+  function getStructure() {
+    $r = array('variables' => $this->getVariables(), 'rows' => $this->getRows());
+    /* boolean|inserted|deleted */
+    if ($sub_r = $this->getBooleanInsertedDeleted()) {
+      foreach ($sub_r as $k => $v) {
+        $r[$k] = $v;
+      }
+    }
+    return $r;
+  }
+
+  /*  */
+
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_SPOGParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,188 @@
+<?php
+/**
+ * ARC2 streaming SPOG parser
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('RDFParser');
+
+class ARC2_SPOGParser extends ARC2_RDFParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->encoding = $this->v('encoding', false, $this->a);
+    $this->xml = 'http://www.w3.org/XML/1998/namespace';
+    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf');
+    $this->target_encoding = '';
+  }
+  
+  /*  */
+
+  function parse($path, $data = '', $iso_fallback = false) {
+    $this->state = 0;
+    /* reader */
+    if (!$this->v('reader')) {
+      ARC2::inc('Reader');
+      $this->reader = new ARC2_Reader($this->a, $this);
+    }
+    $this->reader->setAcceptHeader('Accept: sparql-results+xml; q=0.9, */*; q=0.1');
+    $this->reader->activate($path, $data);
+    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+    /* xml parser */
+    $this->initXMLParser();
+    /* parse */
+    $first = true;
+    while ($d = $this->reader->readStream()) {
+      if ($iso_fallback && $first) {
+        $d = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . preg_replace('/^\<\?xml [^\>]+\?\>\s*/s', '', $d);
+        $first = false;
+      }
+      if (!xml_parse($this->xml_parser, $d, false)) {
+        $error_str = xml_error_string(xml_get_error_code($this->xml_parser));
+        $line = xml_get_current_line_number($this->xml_parser);
+        $this->tmp_error = 'XML error: "' . $error_str . '" at line ' . $line . ' (parsing as ' . $this->getEncoding() . ')';
+        $this->tmp_error .= $d . urlencode($d);
+        if (0 && !$iso_fallback && preg_match("/Invalid character/i", $error_str)) {
+          xml_parser_free($this->xml_parser);
+          unset($this->xml_parser);
+          $this->reader->closeStream();
+          $this->__init();
+          $this->encoding = 'ISO-8859-1';
+          unset($this->xml_parser);
+          unset($this->reader);
+          return $this->parse($path, $data, true);
+        }
+        else {
+          return $this->addError($this->tmp_error);
+        }
+      }
+    }
+    $this->target_encoding = xml_parser_get_option($this->xml_parser, XML_OPTION_TARGET_ENCODING);
+    xml_parser_free($this->xml_parser);
+    $this->reader->closeStream();
+    unset($this->reader);
+    return $this->done();
+  }
+  
+  /*  */
+  
+  function initXMLParser() {
+    if (!isset($this->xml_parser)) {
+      $enc = preg_match('/^(utf\-8|iso\-8859\-1|us\-ascii)$/i', $this->getEncoding(), $m) ? $m[1] : 'UTF-8';
+      $parser = xml_parser_create($enc);
+      xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
+      xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
+      xml_set_element_handler($parser, 'open', 'close');
+      xml_set_character_data_handler($parser, 'cdata');
+      xml_set_start_namespace_decl_handler($parser, 'nsDecl');
+      xml_set_object($parser, $this);
+      $this->xml_parser = $parser;
+    }
+  }
+
+  /*  */
+  
+  function getEncoding($src = 'config') {
+    if ($src == 'parser') {
+      return $this->target_encoding;
+    }
+    elseif (($src == 'config') && $this->encoding) {
+      return $this->encoding;
+    }
+    return $this->reader->getEncoding();
+    return 'UTF-8';
+  }
+  
+  /*  */
+  
+  function getTriples() {
+    return $this->v('triples', array());
+  }
+  
+  function countTriples() {
+    return $this->t_count;
+  }
+
+  function addT($s = '', $p = '', $o = '', $s_type = '', $o_type = '', $o_dt = '', $o_lang = '', $g = '') {
+    if (!($s && $p && $o)) return 0;
+    //echo "-----\nadding $s / $p / $o\n-----\n";
+    $t = array('s' => $s, 'p' => $p, 'o' => $o, 's_type' => $s_type, 'o_type' => $o_type, 'o_datatype' => $o_dt, 'o_lang' => $o_lang, 'g' => $g);
+    if ($this->skip_dupes) {
+      $h = md5(serialize($t));
+      if (!isset($this->added_triples[$h])) {
+        $this->triples[$this->t_count] = $t;
+        $this->t_count++;
+        $this->added_triples[$h] = true;
+      }
+    }
+    else {
+      $this->triples[$this->t_count] = $t;
+      $this->t_count++;
+    }
+  }
+
+  /*  */
+  
+  function open($p, $t, $a) {
+    $this->state = $t;
+    if ($t == 'result') {
+      $this->t = array();
+    }
+    elseif ($t == 'binding') {
+      $this->binding = $a['name'];
+      $this->t[$this->binding] = '';
+    }
+    elseif ($t == 'literal') {
+      $this->t[$this->binding . '_dt'] = $this->v('datatype', '', $a);
+      $this->t[$this->binding . '_lang'] = $this->v('xml:lang', '', $a);
+      $this->t[$this->binding . '_type'] = 'literal';
+    }
+    elseif ($t == 'uri') {
+      $this->t[$this->binding . '_type'] = 'uri';
+    }
+    elseif ($t == 'bnode') {
+      $this->t[$this->binding . '_type'] = 'bnode';
+      $this->t[$this->binding] = '_:';
+    }
+  }
+  
+  function close($p, $t) {
+    $this->prev_state = $this->state;
+    $this->state = '';
+    if ($t == 'result') {
+      $this->addT(
+        $this->v('s', '', $this->t), 
+        $this->v('p', '', $this->t), 
+        $this->v('o', '', $this->t), 
+        $this->v('s_type', '', $this->t), 
+        $this->v('o_type', '', $this->t), 
+        $this->v('o_dt', '', $this->t), 
+        $this->v('o_lang', '', $this->t), 
+        $this->v('g', '', $this->t)
+      );
+    }
+  }
+
+  function cData($p, $d) {
+    if (in_array($this->state, array('uri', 'bnode', 'literal'))) {
+      $this->t[$this->binding] .= $d;
+    }
+  }
+  
+  function nsDecl($p, $prf, $uri) {
+    $this->nsp[$uri] = isset($this->nsp[$uri]) ? $this->nsp[$uri] : $prf;
+  }
+
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_SemHTMLParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 RDF/XML Parser
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('LegacyXMLParser');
+
+class ARC2_SemHTMLParser extends ARC2_LegacyXMLParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->default_sem_html_formats = 'dc openid erdf rdfa posh-rdf microformats';
+    $this->triples = array();
+    $this->target_encoding = '';
+    $this->t_count = 0;
+    $this->added_triples = array();
+    $this->skip_dupes = false;
+    $this->bnode_prefix = $this->v('bnode_prefix', 'arc'.substr(md5(uniqid(rand())), 0, 4).'b', $this->a);
+    $this->bnode_id = 0;
+    $this->auto_extract = $this->v('auto_extract', 1, $this->a);
+    $this->extracted_formats = array();
+    $this->cache = array();
+    $this->detected_formats = array();
+    $this->keep_cdata_ws = $this->v('keep_cdata_whitespace', 0, $this->a);
+  }
+  
+  /*  */
+
+  function x($re, $v, $options = 'si', $keep_ws = 0) {
+    list($ws, $v) = preg_match('/^(\s*)(.*)$/s', $v, $m) ? array($m[1], $m[2]) : array('', $v);
+    if (preg_match("/^" . $re . "(.*)$/" . $options, $v, $m)) {
+      if ($keep_ws) $m[1] = $ws . $m[1];
+      return $m;
+    }
+    return false;
+  }
+
+  /*  */
+
+  function setReader(&$reader) {
+    $this->reader = $reader;
+  }
+  
+  function createBnodeID(){
+    $this->bnode_id++;
+    return '_:' . $this->bnode_prefix . $this->bnode_id;
+  }
+  
+  function addT($t) {
+    if (function_exists('html_entity_decode')) {
+      $t['o'] = html_entity_decode($t['o']);
+    }
+    if ($this->skip_dupes) {
+      $h = md5(serialize($t));
+      if (!isset($this->added_triples[$h])) {
+        $this->triples[$this->t_count] = $t;
+        $this->t_count++;
+        $this->added_triples[$h] = true;
+      }
+    }
+    else {
+      $this->triples[$this->t_count] = $t;
+      $this->t_count++;
+    }
+  }
+
+  function getTriples() {
+    return $this->v('triples', array());
+  }
+
+  function countTriples() {
+    return $this->t_count;
+  }
+  
+  function getSimpleIndex($flatten_objects = 1, $vals = '') {
+    return ARC2::getSimpleIndex($this->getTriples(), $flatten_objects, $vals);
+  }
+
+  /*  */
+
+  function parse($path, $data = '', $iso_fallback = 'ignore') {
+    $this->nodes = array();
+    $this->node_count = 0;
+    $this->level = 0;
+    /* reader */
+    if (!$this->v('reader')) {
+      ARC2::inc('Reader');
+      $this->reader = new ARC2_Reader($this->a, $this);
+    }
+    $this->reader->setAcceptHeader('Accept: text/html, application/xhtml, */*; q=0.9');
+    $this->reader->activate($path, $data);
+    $this->target_encoding = $this->reader->getEncoding(false);
+    $this->x_base = isset($this->a['base']) && $this->a['base'] ? $this->a['base'] : $this->reader->base;
+    $this->base = $this->x_base;
+    $this->doc_url = $this->reader->base;
+    /* parse */
+    $rest = '';
+    $this->cur_tag = '';
+    while ($d = $this->reader->readStream(1)) {
+      $rest = $this->processData($rest . $d);
+    }
+    $this->reader->closeStream();
+    unset($this->reader);
+    return $this->done();
+  }
+  
+  /*  */
+
+  function getEncoding($src = 'ignore') {
+    return $this->target_encoding;
+  }
+
+  /*  */
+  
+  function done() {
+    if ($this->auto_extract) {
+      $this->extractRDF();
+    }
+  }
+  
+  /*  */
+
+  function processData($v) {
+    $sub_v = $v;
+    do {
+      $proceed = 1;
+      if ((list($sub_r, $sub_v) = $this->xComment($sub_v)) && $sub_r) {
+        $this->open(0, 'comment', array('value' => $sub_r));
+        $this->close(0, 'comment');
+        continue;
+      }
+      if ((list($sub_r, $sub_v) = $this->xDoctype($sub_v)) && $sub_r) {
+        $this->open(0, 'doctype', array('value' => $sub_r));
+        $this->close(0, 'doctype');
+        /* RDFa detection */
+        if (preg_match('/rdfa /i', $sub_r)) $this->detected_formats['rdfa'] = 1;
+        continue;
+      }
+      if ($this->level && ((list($sub_r, $sub_v) = $this->xWS($sub_v)) && $sub_r)) {
+        $this->cData(0, $sub_r);
+      }
+      elseif ((list($sub_r, $sub_v) = $this->xOpen($sub_v)) && $sub_r) {
+        $this->open(0, $sub_r['tag'], $sub_r['a']);
+        $this->cur_tag = $sub_r['tag'];
+        if ($sub_r['empty']) {
+          $this->close(0, $sub_r['tag'], 1);
+          $this->cur_tag = '';
+        }
+        /* eRDF detection */
+        if (!isset($this->detected_formats['erdf']) && isset($sub_r['a']['profile m']) && in_array('http://purl.org/NET/erdf/profile', $sub_r['a']['profile m'])) $this->detected_formats['erdf'] = 1;
+        /* poshRDF detection */
+        if (!isset($this->detected_formats['posh-rdf']) && isset($sub_r['a']['class m']) && in_array('rdf-p', $sub_r['a']['class m'])) $this->detected_formats['posh-rdf'] = 1;
+        /* RDFa detection */
+        if (!isset($this->detected_formats['rdfa']) && ($this->cur_tag == 'html') && isset($sub_r['a']['version m']) && in_array('XHTML+RDFa', $sub_r['a']['version m'])) $this->detected_formats['rdfa'] = 1;
+        if (!isset($this->detected_formats['rdfa']) && isset($sub_r['a']['xmlns']) && $sub_r['a']['xmlns'] && $this->isRDFNSDecl($sub_r['a']['xmlns'])) $this->detected_formats['rdfa'] = 1;
+        if (!isset($this->detected_formats['rdfa']) && array_intersect(array('about', 'typeof', 'property'), array_keys($sub_r['a']))) $this->detected_formats['rdfa'] = 1;
+      }
+      elseif ((list($sub_r, $sub_v) = $this->xClose($sub_v)) && $sub_r) {
+        if (preg_match('/^(area|base|br|col|frame|hr|input|img|link|xmeta|param)$/', $sub_r['tag'])) {
+          /* already implicitly closed */
+        }
+        else {
+          $this->close(0, $sub_r['tag']);
+          $this->cur_tag = '';
+        }
+      }
+      elseif ((list($sub_r, $sub_v) = $this->xCData($sub_v)) && $sub_r) {
+        $this->cData(0, $sub_r);
+      }
+      else {
+        $proceed = 0;
+      }
+    } while ($proceed);
+    return $sub_v;
+  }
+
+  /*  */
+
+  function isRDFNSDecl($ns) {
+    foreach ($ns as $k => $v) {
+      if ($k) return 1;
+    }
+    return 0;
+  }
+
+  /*  */
+
+  function xComment($v) {
+    if ($r = $this->x('\<\!\-\-', $v)) {
+      if ($sub_r = $this->x('(.*)\-\-\>', $r[1], 'Us')) {
+        return array($sub_r[1], $sub_r[2]);
+      }
+    }
+    return array(0, $v);
+  }
+  
+  function xDoctype($v) {
+    if ($r = $this->x('\<\!DOCTYPE', $v)) {
+      if ($sub_r = $this->x('([^\>]+)\>', $r[1])) {
+        return array($sub_r[1], $sub_r[2]);
+      }
+    }
+    return array(0, $v);
+  }
+  
+  function xWS($v) {
+    if ($r = ARC2::x('(\s+)', $v)) {
+      return array($r[1], $r[2]);
+    }
+    return array(0, $v);
+  }
+  
+  /*  */
+
+  function xOpen($v) {
+    if ($r = $this->x('\<([^\s\/\>]+)([^\>]*)\>', $v)) {
+      list($sub_r, $sub_v) = $this->xAttributes($r[2]);
+      return array(array('tag' => strtolower($r[1]), 'a' => $sub_r, 'empty' => $this->isEmpty($r[1], $r[2])), $r[3]);
+    }
+    return array(0, $v);
+  }
+  
+  /*  */
+
+  function xAttributes($v) {
+    $r = array();
+    while ((list($sub_r, $v) = $this->xAttribute($v)) && $sub_r) {
+      if ($sub_sub_r = $this->x('xmlns\:?(.*)', $sub_r['k'])) {
+        $this->nsDecl(0, $sub_sub_r[1], $sub_r['value']);
+        $r['xmlns'][$sub_sub_r[1]] = $sub_r['value'];
+      }
+      else {
+        $r[$sub_r['k']] = $sub_r['value'];
+        $r[$sub_r['k'] . ' m'] = $sub_r['values'];
+      }
+    }
+    return array($r, $v);
+  }
+
+  /*  */
+
+  function xAttribute($v) {
+    if ($r = $this->x('([^\s\=]+)\s*(\=)?\s*([\'\"]?)', $v)) {
+      if (!$r[2]) {/* no '=' */
+        if ($r[1] == '/') {
+          return array(0, $r[4]);
+        }
+        return array(array('k' => $r[1], 'value' => 1, 'values' => array(1)), $r[4]);
+      }
+      if (!$r[3]) {/* no quots */
+        if ($sub_r = $this->x('([^\s]+)', $r[4])) {
+          return array(array('k' => $r[1], 'value' => $sub_r[1], 'values' => array($sub_r[1])), $sub_r[2]);
+        }
+        return array(array('k' => $r[1], 'value' => '', 'values' => array()), $r[4]);
+      }
+      $val = '';
+      $multi = 0;
+      $sub_v = $r[4];
+      while ($sub_v && (!$sub_r = $this->x('(\x5c\\' .$r[3]. '|\\' .$r[3]. ')', $sub_v))) {
+        $val .= substr($sub_v, 0, 1);
+        $sub_v = substr($sub_v, 1);
+      }
+      $sub_v = $sub_v ? $sub_r[2] : $sub_v;
+      $vals = preg_split('/ /', $val);
+      return array(array('k' => $r[1], 'value' => $val, 'values' => $vals), $sub_v);
+    }
+    return array(0, $v);
+  }
+  
+  /*  */
+
+  function isEmpty($t, $v) {
+    if (preg_match('/^(area|base|br|col|frame|hr|input|img|link|xmeta|param)$/', $t)) {
+      return 1;
+    }
+    if (preg_match('/\/$/', $v)) {
+      return 1;
+    }
+    return 0;
+  }
+  
+  /*  */
+  
+  function xClose($v) {
+    if ($r = $this->x('\<\/([^\s\>]+)\>', $v)) {
+      return array(array('tag' => strtolower($r[1])), $r[2]);
+    }
+    return array(0, $v);
+  }
+
+  /*  */
+  
+  function xCData($v) {
+    if (preg_match('/(script|style)/i', $this->cur_tag)) {
+      if ($r = $this->x('(.+)(\<\/' . $this->cur_tag . '\>)', $v, 'Uis')) {
+        return array($r[1], $r[2] . $r[3]);
+      }
+    }
+    elseif ($r = $this->x('([^\<]+)', $v, 'si', $this->keep_cdata_ws)) {
+      return array($r[1], $r[2]);
+    }
+    return array(0, $v);
+  }
+
+  /*  */
+
+  function extractRDF($formats = '') {
+    $this->node_index = $this->getNodeIndex();
+    $formats = !$formats ? $this->v('sem_html_formats', $this->default_sem_html_formats, $this->a) : $formats;
+    $formats = preg_split('/ /', $formats);
+    foreach ($formats as $format) {
+      if (!in_array($format, $this->extracted_formats)) {
+        $comp = $this->camelCase($format) . 'Extractor';
+        if (ARC2::inc($comp)) {
+          $cls = 'ARC2_' . $comp;
+          $e = new $cls($this->a, $this);
+          $e->extractRDF();
+        }
+        $this->extracted_formats[] = $format;
+      }
+    }
+  }
+  
+  function getNode($id) {
+    return isset($this->nodes[$id]) ? $this->nodes[$id] : 0;
+  }
+  
+  /*  */
+  
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/parsers/ARC2_TurtleParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,886 @@
+<?php
+/**
+ * ARC2 SPARQL-enhanced Turtle Parser
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('RDFParser');
+
+class ARC2_TurtleParser extends ARC2_RDFParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* reader */
+    parent::__init();
+    $this->state = 0;
+    $this->xml = 'http://www.w3.org/XML/1998/namespace';
+    $this->rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $this->xsd = 'http://www.w3.org/2001/XMLSchema#';
+    $this->nsp = array($this->xml => 'xml', $this->rdf => 'rdf', $this->xsd => 'xsd');
+    $this->unparsed_code = '';
+    $this->max_parsing_loops = $this->v('turtle_max_parsing_loops', 500, $this->a);
+  }
+  
+  /*  */
+  
+  function x($re, $v, $options = 'si') {
+    $v = preg_replace('/^[\xA0\xC2]+/', ' ', $v);
+    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) {/* comment removal */
+      $v = $m[2];
+    }
+    return ARC2::x($re, $v, $options);
+    //$this->unparsed_code = ($sub_r && count($sub_r)) ? $sub_r[count($sub_r) - 1] : '';
+  }
+
+  function createBnodeID(){
+    $this->bnode_id++;
+    return '_:' . $this->bnode_prefix . $this->bnode_id;
+  }
+
+  /*  */
+  
+  function addT($t) {
+    if ($this->skip_dupes) {
+      $h = md5(serialize($t));
+      if (!isset($this->added_triples[$h])) {
+        $this->triples[$this->t_count] = $t;
+        $this->t_count++;
+        $this->added_triples[$h] = true;
+      }
+    }
+    else {
+      $this->triples[$this->t_count] = $t;
+      $this->t_count++;
+    }
+  }
+
+  /*  */
+
+  function getTriples() {
+    return $this->v('triples', array());
+  }
+  
+  function countTriples() {
+    return $this->t_count;
+  }
+  
+  /*  */
+  
+  function getUnparsedCode() {
+    return $this->v('unparsed_code', '');
+  }
+  
+  /*  */
+  
+  function setDefaultPrefixes() {
+    $this->prefixes = array(
+      'rdf:' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+      'rdfs:' => 'http://www.w3.org/2000/01/rdf-schema#',
+      'owl:' => 'http://www.w3.org/2002/07/owl#',
+      'xsd:' => 'http://www.w3.org/2001/XMLSchema#',
+    );
+    if ($ns = $this->v('ns', array(), $this->a)) {
+      foreach ($ns as $p => $u) $this->prefixes[$p . ':'] = $u;
+    }
+  }
+  
+
+  function parse($path, $data = '', $iso_fallback = false) {
+    $this->setDefaultPrefixes();
+    /* reader */
+    if (!$this->v('reader')) {
+      ARC2::inc('Reader');
+      $this->reader = new ARC2_Reader($this->a, $this);
+    }
+    $this->reader->setAcceptHeader('Accept: application/x-turtle; q=0.9, */*; q=0.1');
+    $this->reader->activate($path, $data);
+    $this->base = $this->v1('base', $this->reader->base, $this->a);
+    $this->r = array('vars' => array());
+    /* parse */
+    $buffer = '';
+    $more_triples = array();
+    $sub_v = '';
+    $sub_v2 = '';
+    $loops = 0;
+    $prologue_done = 0;
+    while ($d = $this->reader->readStream(0, 8192)) {
+      $buffer .= $d;
+      $sub_v = $buffer;
+      do {
+        $proceed = 0;
+        if (!$prologue_done) {
+          $proceed = 1;
+          if ((list($sub_r, $sub_v) = $this->xPrologue($sub_v)) && $sub_r) {
+            $loops = 0;
+            $sub_v .= $this->reader->readStream(0, 128);
+            /* we might have missed the final DOT in the previous prologue loop */
+            if ($sub_r = $this->x('\.', $sub_v)) $sub_v = $sub_r[1];
+            if ($this->x("\@?(base|prefix)", $sub_v)) {/* more prologue to come, use outer loop */
+              $proceed = 0;
+            }
+          }
+          else {
+            $prologue_done = 1;
+          }
+        }
+        if ($prologue_done && (list($sub_r, $sub_v, $more_triples, $sub_v2) = $this->xTriplesBlock($sub_v)) && is_array($sub_r)) {
+          $proceed = 1;
+          $loops = 0;
+          foreach ($sub_r as $t) {
+            $this->addT($t);
+          }
+        }
+      } while ($proceed);
+      $loops++;
+      $buffer = $sub_v;
+      if ($loops > $this->max_parsing_loops) {/* most probably a parser or code bug, might also be a huge object value, though */
+        $this->addError('too many loops: ' . $loops . '. Could not parse "' . substr($buffer, 0, 200) . '..."');
+        break;
+      }
+    }
+    foreach ($more_triples as $t) {
+      $this->addT($t);
+    }
+    $sub_v = count($more_triples) ? $sub_v2 : $sub_v;
+    $buffer = $sub_v;
+    $this->unparsed_code = $buffer;
+    $this->reader->closeStream();
+    unset($this->reader);
+    /* remove trailing comments */
+    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $this->unparsed_code, $m)) $this->unparsed_code = $m[2];
+    if ($this->unparsed_code && !$this->getErrors()) {
+      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
+      if (trim($rest)) $this->addError('Could not parse "' . $rest . '"');
+    }
+    return $this->done();
+  }
+
+  function xPrologue($v) {
+    $r = 0;
+    if (!$this->t_count) {
+      if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
+        $this->base = $sub_r;
+        $r = 1;
+      }
+      while ((list($sub_r, $v) = $this->xPrefixDecl($v)) && $sub_r) {
+        $this->prefixes[$sub_r['prefix']] = $sub_r['uri'];
+        $r = 1;
+      }
+    }
+    return array($r, $v);
+  }
+  
+  /* 3 */
+
+  function xBaseDecl($v) {
+    if ($r = $this->x("\@?base\s+", $v)) {
+      if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
+        if ($sub_r = $this->x('\.', $sub_v)) {
+          $sub_v = $sub_r[1];
+        }
+        return array($r, $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /* 4 */
+  
+  function xPrefixDecl($v) {
+    if ($r = $this->x("\@?prefix\s+", $v)) {
+      if ((list($r, $sub_v) = $this->xPNAME_NS($r[1])) && $r) {
+        $prefix = $r;
+        if((list($r, $sub_v) = $this->xIRI_REF($sub_v)) && $r) {
+          $uri = $this->calcURI($r, $this->base);
+          if ($sub_r = $this->x('\.', $sub_v)) {
+            $sub_v = $sub_r[1];
+          }
+          return array(array('prefix' => $prefix, 'uri_ref' => $r, 'uri' => $uri), $sub_v);
+        }
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 21.., 32.. */
+  
+  function xTriplesBlock($v) {
+    $pre_r = array();
+    $r = array();
+    $state = 1;
+    $sub_v = $v;
+    $buffer = $sub_v;
+    do {
+      $proceed = 0;
+      if ($state == 1) {/* expecting subject */
+        $t = array('type' => 'triple', 's' => '', 'p' => '', 'o' => '', 's_type' => '', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
+        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+          $t['s'] = $sub_r['value'];
+          $t['s_type'] = $sub_r['type'];
+          $state = 2;
+          $proceed = 1;
+          if ($sub_r = $this->x('(\}|\.)', $sub_v)) {
+            if ($t['s_type'] == 'placeholder') {
+              $state = 4;
+            }
+            else {
+              $this->addError('"' . $sub_r[1]. '" after subject found.');
+            }
+          }
+        }
+        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
+          $t['s'] = $sub_r['id'];
+          $t['s_type'] = $sub_r['type'];
+          $pre_r = array_merge($pre_r, $sub_r['triples']);
+          $state = 2;
+          $proceed = 1;
+          if ($sub_r = $this->x('\.', $sub_v)) {
+            $this->addError('DOT after subject found.');
+          }
+        }
+        elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
+          $t['s'] = $sub_r['id'];
+          $t['s_type'] = $sub_r['type'];
+          $pre_r = array_merge($pre_r, $sub_r['triples']);
+          $state = 2;
+          $proceed = 1;
+        }
+        elseif ($sub_r = $this->x('\.', $sub_v)) {
+          $this->addError('Subject expected, DOT found.' . $sub_v);
+        }
+      }
+      if ($state == 2) {/* expecting predicate */
+        if ($sub_r = $this->x('a\s+', $sub_v)) {
+          $sub_v = $sub_r[1];
+          $t['p'] = $this->rdf . 'type';
+          $t['p_type'] = 'uri';
+          $state = 3;
+          $proceed = 1;
+        }
+        elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+          if ($sub_r['type'] == 'bnode') {
+            $this->addError('Blank node used as triple predicate');
+          }
+          $t['p'] = $sub_r['value'];
+          $t['p_type'] = $sub_r['type'];
+          $state = 3;
+          $proceed = 1;
+        }
+        elseif ($sub_r = $this->x('\.', $sub_v)) {
+          $state = 4;          
+        }
+        elseif ($sub_r = $this->x('\}', $sub_v)) {
+          $buffer = $sub_v;
+          $r = array_merge($r, $pre_r);
+          $pre_r = array();
+          $proceed = 0;
+        }
+      }
+      if ($state == 3) {/* expecting object */
+        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+          $t['o'] = $sub_r['value'];
+          $t['o_type'] = $sub_r['type'];
+          $t['o_lang'] = $this->v('lang', '', $sub_r);
+          $t['o_datatype'] = $this->v('datatype', '', $sub_r);
+          $pre_r[] = $t;
+          $state = 4;
+          $proceed = 1;
+        }
+        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
+          $t['o'] = $sub_r['id'];
+          $t['o_type'] = $sub_r['type'];
+          $t['o_datatype'] = '';
+          $pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
+          $state = 4;
+          $proceed = 1;
+        }
+        elseif ((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
+          $t['o'] = $sub_r['id'];
+          $t['o_type'] = $sub_r['type'];
+          $t['o_datatype'] = '';
+          $pre_r = array_merge($pre_r, array($t), $sub_r['triples']);
+          $state = 4;
+          $proceed = 1;
+        }
+      }
+      if ($state == 4) {/* expecting . or ; or , or } */
+        if ($sub_r = $this->x('\.', $sub_v)) {
+          $sub_v = $sub_r[1];
+          $buffer = $sub_v;
+          $r = array_merge($r, $pre_r);
+          $pre_r = array();
+          $state = 1;
+          $proceed = 1;
+        }
+        elseif ($sub_r = $this->x('\;', $sub_v)) {
+          $sub_v = $sub_r[1];
+          $state = 2;
+          $proceed = 1;
+        }
+        elseif ($sub_r = $this->x('\,', $sub_v)) {
+          $sub_v = $sub_r[1];
+          $state = 3;
+          $proceed = 1;
+          if ($sub_r = $this->x('\}', $sub_v)) {
+            $this->addError('Object expected, } found.');
+          }
+        }
+        if ($sub_r = $this->x('(\}|\{|OPTIONAL|FILTER|GRAPH)', $sub_v)) {
+          $buffer = $sub_v;
+          $r = array_merge($r, $pre_r);
+          $pre_r = array();
+          $proceed = 0;
+        }
+      }
+    } while ($proceed);
+    return count($r) ? array($r, $buffer, $pre_r, $sub_v) : array(0, $buffer, $pre_r, $sub_v);
+  }
+  
+  /* 39.. */
+  
+  function xBlankNodePropertyList($v) {
+    if ($sub_r = $this->x('\[', $v)) {
+      $sub_v = $sub_r[1];
+      $s = $this->createBnodeID();
+      $r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
+      $t = array('type' => 'triple', 's' => $s, 'p' => '', 'o' => '', 's_type' => 'bnode', 'p_type' => '', 'o_type' => '', 'o_datatype' => '', 'o_lang' => '');
+      $state = 2;
+      $closed = 0;
+      do {
+        $proceed = 0;
+        if ($state == 2) {/* expecting predicate */
+          if ($sub_r = $this->x('a\s+', $sub_v)) {
+            $sub_v = $sub_r[1];
+            $t['p'] = $this->rdf . 'type';
+            $t['p_type'] = 'uri';
+            $state = 3;
+            $proceed = 1;
+          }
+          elseif ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+            $t['p'] = $sub_r['value'];
+            $t['p_type'] = $sub_r['type'];
+            $state = 3;
+            $proceed = 1;
+          }
+        }
+        if ($state == 3) {/* expecting object */
+          if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+            $t['o'] = $sub_r['value'];
+            $t['o_type'] = $sub_r['type'];
+            $t['o_lang'] = $this->v('lang', '', $sub_r);
+            $t['o_datatype'] = $this->v('datatype', '', $sub_r);
+            $r['triples'][] = $t;
+            $state = 4;
+            $proceed = 1;
+          }
+          elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
+            $t['o'] = $sub_r['id'];
+            $t['o_type'] = $sub_r['type'];
+            $t['o_datatype'] = '';
+            $r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
+            $state = 4;
+            $proceed = 1;
+          }
+          elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
+            $t['o'] = $sub_r['id'];
+            $t['o_type'] = $sub_r['type'];
+            $t['o_datatype'] = '';
+            $r['triples'] = array_merge($r['triples'], array($t), $sub_r['triples']);
+            $state = 4;
+            $proceed = 1;
+          }
+        }
+        if ($state == 4) {/* expecting . or ; or , or ] */
+          if ($sub_r = $this->x('\.', $sub_v)) {
+            $sub_v = $sub_r[1];
+            $state = 1;
+            $proceed = 1;
+          }
+          if ($sub_r = $this->x('\;', $sub_v)) {
+            $sub_v = $sub_r[1];
+            $state = 2;
+            $proceed = 1;
+          }
+          if ($sub_r = $this->x('\,', $sub_v)) {
+            $sub_v = $sub_r[1];
+            $state = 3;
+            $proceed = 1;
+          }
+          if ($sub_r = $this->x('\]', $sub_v)) {
+            $sub_v = $sub_r[1];
+            $proceed = 0;
+            $closed = 1;
+          }
+        }
+      } while ($proceed);
+      if ($closed) {
+        return array($r, $sub_v);
+      }
+      return array(0, $v);
+    }
+    return array(0, $v);
+  }
+  
+  /* 40.. */
+  
+  function xCollection($v) {
+    if ($sub_r = $this->x('\(', $v)) {
+      $sub_v = $sub_r[1];
+      $s = $this->createBnodeID();
+      $r = array('id' => $s, 'type' => 'bnode', 'triples' => array());
+      $closed = 0;
+      do {
+        $proceed = 0;
+        if ((list($sub_r, $sub_v) = $this->xVarOrTerm($sub_v)) && $sub_r) {
+          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['value'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => $this->v('lang', '', $sub_r), 'o_datatype' => $this->v('datatype', '', $sub_r));
+          $proceed = 1;
+        }
+        elseif ((list($sub_r, $sub_v) = $this->xCollection($sub_v)) && $sub_r) {
+          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
+          $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
+          $proceed = 1;
+        }
+        elseif((list($sub_r, $sub_v) = $this->xBlankNodePropertyList($sub_v)) && $sub_r) {
+          $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'first', 'o' => $sub_r['id'], 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => $sub_r['type'], 'o_lang' => '', 'o_datatype' => '');
+          $r['triples'] = array_merge($r['triples'], $sub_r['triples']);
+          $proceed = 1;
+        }
+        if ($proceed) {
+          if ($sub_r = $this->x('\)', $sub_v)) {
+            $sub_v = $sub_r[1];
+            $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $this->rdf . 'nil', 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'uri', 'o_lang' => '', 'o_datatype' => '');
+            $closed = 1;
+            $proceed = 0;
+          }
+          else {
+            $next_s = $this->createBnodeID();
+            $r['triples'][] = array('type' => 'triple', 's' => $s, 'p' => $this->rdf . 'rest', 'o' => $next_s, 's_type' => 'bnode', 'p_type' => 'uri', 'o_type' => 'bnode', 'o_lang' => '', 'o_datatype' => '');
+            $s = $next_s;
+          }
+        }
+      } while ($proceed);
+      if ($closed) {
+        return array($r, $sub_v);
+      }
+    }
+    return array (0, $v);
+  }
+  
+  /* 42 */
+  
+  function xVarOrTerm($v) {
+    if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    elseif ((list($sub_r, $sub_v) = $this->xGraphTerm($v)) && $sub_r) {
+      return array($sub_r, $sub_v);
+    }
+    return array(0, $v);
+  }
+  
+  /* 44, 74.., 75.. */
+  
+  function xVar($v) {
+    if ($r = $this->x('(\?|\$)([^\s]+)', $v)) {
+      if ((list($sub_r, $sub_v) = $this->xVARNAME($r[2])) && $sub_r) {
+        if (!in_array($sub_r, $this->r['vars'])) {
+          $this->r['vars'][] = $sub_r;
+        }
+        return array(array('value' => $sub_r, 'type' => 'var'), $sub_v . $r[3]);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 45 */
+  
+  function xGraphTerm($v) {
+    foreach (array(
+      'IRIref' => 'uri', 
+      'RDFLiteral' => 'literal', 
+      'NumericLiteral' => 'literal', 
+      'BooleanLiteral' => 'literal', 
+      'BlankNode' => 'bnode', 
+      'NIL' => 'uri',
+      'Placeholder' => 'placeholder'
+    ) as $term => $type) {
+      $m = 'x' . $term;
+      if ((list($sub_r, $sub_v) = $this->$m($v)) && $sub_r) {
+        if (!is_array($sub_r)) {
+          $sub_r = array('value' => $sub_r);
+        }
+        $sub_r['type'] = $this->v1('type', $type, $sub_r);
+        return array($sub_r, $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+
+  /* 60 */
+  
+  function xRDFLiteral($v) {
+    if ((list($sub_r, $sub_v) = $this->xString($v)) && $sub_r) {
+      $sub_r['value'] = $this->unescapeNtripleUTF($sub_r['value']);
+      $r = $sub_r;
+      if ((list($sub_r, $sub_v) = $this->xLANGTAG($sub_v)) && $sub_r) {
+        $r['lang'] = $sub_r;
+      }
+      elseif (!$this->x('\s', $sub_v) && ($sub_r = $this->x('\^\^', $sub_v)) && (list($sub_r, $sub_v) = $this->xIRIref($sub_r[1])) && $sub_r[1]) {
+        $r['datatype'] = $sub_r;
+      }
+      return array($r, $sub_v);
+    }
+    return array(0, $v);
+  }
+
+  /* 61.., 62.., 63.., 64.. */  
+  
+  function xNumericLiteral($v) {
+    $sub_r = $this->x('(\-|\+)?', $v);
+    $prefix = $sub_r[1];
+    $sub_v = $sub_r[2];
+    foreach (array('DOUBLE' => 'double', 'DECIMAL' => 'decimal', 'INTEGER' => 'integer') as $type => $xsd) {
+      $m = 'x' . $type;
+      if ((list($sub_r, $sub_v) = $this->$m($sub_v)) && ($sub_r !== false)) {
+        $r = array('value' => $prefix . $sub_r, 'type' => 'literal', 'datatype' => $this->xsd . $xsd);
+        return array($r, $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /* 65.. */
+  
+  function xBooleanLiteral($v) {
+    if ($r = $this->x('(true|false)', $v)) {
+      return array($r[1], $r[2]);
+    }
+    return array(0, $v);
+  }
+
+  /* 66.., 87.., 88.., 89.., 90.., 91.. */
+  
+  function xString($v) {/* largely simplified, may need some tweaks in following revisions */
+    $sub_v = $v;
+    if (!preg_match('/^\s*([\']{3}|\'|[\"]{3}|\")(.*)$/s', $sub_v, $m)) return array(0, $v);
+    $delim = $m[1];
+    $rest = $m[2];
+    $sub_types = array("'''" => 'literal_long1', '"""' => 'literal_long2', "'" => 'literal1', '"' => 'literal2');
+    $sub_type = $sub_types[$delim];
+    $pos = 0;
+    $r = false;
+    do {
+      $proceed = 0;
+      $delim_pos = strpos($rest, $delim, $pos);
+      if ($delim_pos === false) break;
+      $new_rest = substr($rest, $delim_pos + strlen($delim));
+      $r = substr($rest, 0, $delim_pos);
+      if (!preg_match('/([\x5c]+)$/s', $r, $m) || !(strlen($m[1]) % 2)) {
+        $rest = $new_rest;
+      }
+      else {
+        $r = false;
+        $pos = $delim_pos + 1;
+        $proceed = 1;
+      }
+    } while ($proceed);
+    if ($r !== false) {
+      return array(array('value' => $this->toUTF8($r) , 'type' => 'literal', 'sub_type' => $sub_type), $rest);
+    }
+    return array(0, $v);
+  }
+  
+  /* 67 */
+  
+  function xIRIref($v) {
+    if ((list($r, $v) = $this->xIRI_REF($v)) && $r) {
+      return array($this->calcURI($r, $this->base), $v);
+    }
+    elseif ((list($r, $v) = $this->xPrefixedName($v)) && $r) {
+      return array($r, $v);
+    }
+    return array(0, $v);
+  }
+  
+  /* 68 */
+  
+  function xPrefixedName($v) {
+    if ((list($r, $v) = $this->xPNAME_LN($v)) && $r) {
+      return array($r, $v);
+    }
+    elseif ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
+      return isset($this->prefixes[$r]) ? array($this->prefixes[$r], $sub_v) : array(0, $v);
+    }
+    return array(0, $v);
+  }
+  
+  /* 69.., 73.., 93, 94..  */
+  
+  function xBlankNode($v) {
+    if (($r = $this->x('\_\:', $v)) && (list($r, $sub_v) = $this->xPN_LOCAL($r[1])) && $r) {
+      return array(array('type' => 'bnode', 'value' => '_:' . $r), $sub_v);
+    }
+    if ($r = $this->x('\[[\x20\x9\xd\xa]*\]', $v)) {
+      return array(array('type' => 'bnode', 'value' => $this->createBnodeID()), $r[1]);
+    }
+    return array(0, $v);
+  }
+
+  /* 70.. @@sync with SPARQLParser */
+  
+  function xIRI_REF($v) {
+    //if ($r = $this->x('\<([^\<\>\"\{\}\|\^\'[:space:]]*)\>', $v)) {
+    if (($r = $this->x('\<(\$\{[^\>]*\})\>', $v)) && ($sub_r = $this->xPlaceholder($r[1]))) {
+      return array($r[1], $r[2]);
+    }
+    elseif ($r = $this->x('\<\>', $v)) {
+      return array(true, $r[1]);
+    }
+    elseif ($r = $this->x('\<([^\s][^\<\>]*)\>', $v)) {
+      return array($r[1] ? $r[1] : true, $r[2]);
+    }
+    return array(0, $v);
+  }
+  
+  /* 71 */
+  
+  function xPNAME_NS($v) {
+    list($r, $sub_v) = $this->xPN_PREFIX($v);
+    $prefix = $r ? $r : '';
+    return ($r = $this->x("\:", $sub_v)) ? array($prefix . ':', $r[1]) : array(0, $v);
+  }
+
+  /* 72 */
+  
+  function xPNAME_LN($v) {
+    if ((list($r, $sub_v) = $this->xPNAME_NS($v)) && $r) {
+      if (!$this->x('\s', $sub_v) && (list($sub_r, $sub_v) = $this->xPN_LOCAL($sub_v)) && $sub_r) {
+        if (!isset($this->prefixes[$r])) {
+          return array(0, $v);
+        }
+        return array($this->prefixes[$r] . $sub_r, $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /* 76 */
+  
+  function xLANGTAG($v) {
+    if (!$this->x('\s', $v) && ($r = $this->x('\@([a-z]+(\-[a-z0-9]+)*)', $v))) {
+      return array($r[1], $r[3]);
+    }
+    return array(0, $v);
+  }
+  
+  /* 77.. */
+  
+  function xINTEGER($v) {
+    if ($r = $this->x('([0-9]+)', $v)) {
+      return array($r[1], $r[2]);
+    }
+    return array(false, $v);
+  }
+
+  /* 78.. */
+
+  function xDECIMAL($v) {
+    if ($r = $this->x('([0-9]+\.[0-9]*)', $v)) {
+      return array($r[1], $r[2]);
+    }
+    if ($r = $this->x('(\.[0-9]+)', $v)) {
+      return array($r[1], $r[2]);
+    }
+    return array(false, $v);
+  }
+
+  /* 79.., 86.. */
+
+  function xDOUBLE($v) {
+    if ($r = $this->x('([0-9]+\.[0-9]*E[\+\-]?[0-9]+)', $v)) {
+      return array($r[1], $r[2]);
+    }
+    if ($r = $this->x('(\.[0-9]+E[\+\-]?[0-9]+)', $v)) {
+      return array($r[1], $r[2]);
+    }
+    if ($r = $this->x('([0-9]+E[\+\-]?[0-9]+)', $v)) {
+      return array($r[1], $r[2]);
+    }
+    return array(false, $v);
+  }
+  
+  /* 92 */
+  
+  function xNIL($v) {
+    if ($r = $this->x('\([\x20\x9\xd\xa]*\)', $v)) {
+      return array(array('type' => 'uri', 'value' => $this->rdf . 'nil'), $r[1]);
+    }
+    return array(0, $v);
+  }
+
+  /* 95.. */
+  
+  function xPN_CHARS_BASE($v) {
+    if ($r = $this->x("([a-z]+|\\\u[0-9a-f]{1,4})", $v)) {
+      return array($r[1], $r[2]);
+    }
+    return array(0, $v);
+  }
+
+  /* 96 */
+  
+  function xPN_CHARS_U($v) {
+    if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
+      return array($r, $sub_v);
+    }
+    elseif ($r = $this->x("(_)", $v)) {
+      return array($r[1], $r[2]);
+    }
+    return array(0, $v);
+  }
+
+  /* 97.. */
+  
+  function xVARNAME($v) {
+    $r = '';
+    do {
+      $proceed = 0;
+      if ($sub_r = $this->x('([0-9]+)', $v)) {
+        $r .= $sub_r[1];
+        $v = $sub_r[2];
+        $proceed = 1;
+      }
+      elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($v)) && $sub_r) {
+        $r .= $sub_r;
+        $v = $sub_v;
+        $proceed = 1;
+      }
+      elseif ($r && ($sub_r = $this->x('([\xb7\x300-\x36f]+)', $v))) {
+        $r .= $sub_r[1];
+        $v = $sub_r[2];
+        $proceed = 1;
+      }
+    } while ($proceed);
+    return array($r, $v);
+  }
+
+  /* 98.. */
+  
+  function xPN_CHARS($v) {
+    if ((list($r, $sub_v) = $this->xPN_CHARS_U($v)) && $r) {
+      return array($r, $sub_v);
+    }
+    elseif ($r = $this->x('([\-0-9\xb7\x300-\x36f])', $v)) {
+      return array($r[1], $r[2]);
+    }
+    return array(false, $v);
+  }
+
+  /* 99 */
+  
+  function xPN_PREFIX($v) {
+    if ($sub_r = $this->x("([^\s\:\(\)\{\}\;\,]+)", $v, 's')) {/* accelerator */
+      return array($sub_r[1], $sub_r[2]);/* @@testing */
+    }
+    if ((list($r, $sub_v) = $this->xPN_CHARS_BASE($v)) && $r) {
+      do {
+        $proceed = 0;
+        list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
+        if ($sub_r !== false) {
+          $r .= $sub_r;
+          $proceed = 1;
+        }
+        elseif ($sub_r = $this->x("\.", $sub_v)) {
+          $r .= '.';
+          $sub_v = $sub_r[1];
+          $proceed = 1;
+        }
+      } while ($proceed);
+      list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v);
+      $r .= $sub_r ? $sub_r : '';
+    }
+    return array($r, $sub_v);
+  }
+  
+  /* 100 */
+  
+  function xPN_LOCAL($v) {
+    if (($sub_r = $this->x("([^\s\(\)\{\}\[\]\;\,\.]+)", $v, 's')) && !preg_match('/^\./', $sub_r[2])) {/* accelerator */
+      return array($sub_r[1], $sub_r[2]);/* @@testing */
+    }
+    $r = '';
+    $sub_v = $v;
+    do {
+      $proceed = 0;
+      if ($this->x('\s', $sub_v)) {
+        return array($r, $sub_v);
+      }
+      if ($sub_r = $this->x('([0-9])', $sub_v)) {
+        $r .= $sub_r[1];
+        $sub_v = $sub_r[2];
+        $proceed = 1;
+      }
+      elseif ((list($sub_r, $sub_v) = $this->xPN_CHARS_U($sub_v)) && $sub_r) {
+        $r .= $sub_r;
+        $proceed = 1;
+      }
+      elseif ($r) {
+        if (($sub_r = $this->x('(\.)', $sub_v)) && !preg_match('/^[\s\}]/s', $sub_r[2])) {
+          $r .= $sub_r[1];
+          $sub_v = $sub_r[2];
+        }
+        if ((list($sub_r, $sub_v) = $this->xPN_CHARS($sub_v)) && $sub_r) {
+          $r .= $sub_r;
+          $proceed = 1;
+        }
+      }
+    } while ($proceed);
+    return array($r, $sub_v);
+  }
+  
+  /*  */
+  
+  function unescapeNtripleUTF($v) {
+    if (strpos($v, '\\') === false) return $v;
+    $mappings = array('t' => "\t", 'n' => "\n", 'r' => "\r", '\"' => '"', '\'' => "'");
+    foreach ($mappings as $in => $out) {
+      $v = preg_replace('/\x5c([' . $in . '])/', $out, $v);
+    }
+    if (strpos(strtolower($v), '\u') === false) return $v;
+    while (preg_match('/\\\(U)([0-9A-F]{8})/', $v, $m) || preg_match('/\\\(u)([0-9A-F]{4})/', $v, $m)) {
+      $no = hexdec($m[2]);
+  		if ($no < 128) $char = chr($no);
+      else if ($no < 2048) $char = chr(($no >> 6) + 192) . chr(($no & 63) + 128);
+      else if ($no < 65536) $char = chr(($no >> 12) + 224) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
+  		else if ($no < 2097152) $char = chr(($no >> 18) + 240) . chr((($no >> 12) & 63) + 128) . chr((($no >> 6) & 63) + 128) . chr(($no & 63) + 128);
+      else $char= '';
+      $v = str_replace('\\' . $m[1] . $m[2], $char, $v);
+    }
+    return $v;
+  }
+  
+  /*  */
+  
+  function xPlaceholder($v) {
+    //if ($r = $this->x('(\?|\$)\{([^\}]+)\}', $v)) {
+    if ($r = $this->x('(\?|\$)', $v)) {
+      if (preg_match('/(\{(?:[^{}]+|(?R))*\})/', $r[2], $m) && strpos(trim($r[2]), $m[1]) === 0) {
+        $ph = substr($m[1], 1, -1);
+        $rest = substr(trim($r[2]), strlen($m[1]));
+        if (!isset($this->r['placeholders'])) $this->r['placeholders'] = array();
+        if (!in_array($ph, $this->r['placeholders'])) $this->r['placeholders'][] = $ph;
+        return array(array('value' => $ph, 'type' => 'placeholder'), $rest);
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /*  */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_LegacyHTMLSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,111 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Legacy XML Serializer
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_LegacyHTMLSerializer extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'text/html';
+  }
+
+  /*  */
+  
+  function getSerializedArray($struct, $root = 1, $ind = ' ') {
+    $n = "\n";
+    $r = '';
+    $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
+    foreach ($struct as $k => $v) {
+      if (!$is_flat) $r .= $n . $ind . $ind . '<dt>' . $k . '</dt>';
+      $r .= $n . $ind . $ind . '<dd>' . (is_array($v) ? $this->getSerializedArray($v, 0, $ind . $ind . $ind) . $n . $ind . $ind : htmlspecialchars($v)) . '</dd>';
+    }
+    return $n . $ind . '<dl>' . $r . $n . $ind . '</dl>';
+  }
+  
+  /*  */
+
+  function isAssociativeArray($v) {
+    foreach (array_keys($v) as $k => $val) {
+      if ($k !== $val) return 1;
+    }
+    return 0;
+  }
+  
+  /*  */
+
+  function getSerializedNode($index, $node, $level = 0, $raw = 0) {
+    $r = '';
+    $tag = $this->v('tag', '', $node);
+    if (preg_match('/^(comment|script)$/', $tag)) {
+    }
+    elseif ($tag == 'cdata') {
+      $r .= $this->v('cdata', '', $node);
+      $r .= $this->v('value', '', $node['a']);
+    }
+    else {
+      /* open tag */
+      if (preg_match('/^(div|form|p|section)$/', $tag)) {
+        $r .= str_pad("\n", $level + 1, "  ");
+      }
+      $r .= '<' . $tag;
+      $attrs = $this->v('a', array(), $node);
+      foreach ($attrs as $k => $v) {
+        /* use uri, if detected */
+        if ($k != 'id') {
+          $v = $this->v($k . ' uri', $v, $attrs);
+        }
+        /* skip arrays and other derived attrs */
+        if (preg_match('/\s/s', $k)) continue;
+        $r .= ' ' . $k . '="' . $v . '"';
+      }
+      if ($node['empty']) {
+        $r .= '/>';
+      }
+      else {
+        $r .= '>';
+        /* cdata */
+        $r .= $this->v('cdata', '', $node);
+        /* sub-nodes */
+        $sub_nodes = $this->v($node['id'], array(), $index);
+        foreach ($sub_nodes as $sub_node) {
+          $r .= $this->getSerializedNode($index, $sub_node, $level + 1, 1);
+        }
+        /* close tag */
+        //$r .= str_pad("\n", $level + 1, "  ") . '</' . $tag . '>';
+        $r .= '</' . $tag . '>';
+        if (preg_match('/^(div|form|p|section)$/', $tag)) {
+          $r .= str_pad("\n", $level + 1, "  ");
+        }
+      }
+    }
+    /* doc envelope, in case of sub-structure serializing */
+    if (!$raw && ($level == 0) && ($node['level'] > 1)) {
+      $r = '<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+  <head>
+  <body>
+    ' . $r . '
+  </body>
+</html>
+     ';
+    }
+    return $r;
+  }
+
+  /*  */
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_LegacyJSONSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,53 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Legacy JSON Serializer
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_LegacyJSONSerializer extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'application/json';
+  }
+
+  /*  */
+  
+  function getSerializedArray($struct, $ind = '') {
+    $n = "\n";
+    if (function_exists('json_encode')) return str_replace('","', '",' . $n . '"', str_replace("\/","/",json_encode($struct)));
+    $r = '';
+    $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f");
+    $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f');
+    $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
+    foreach ($struct as $k => $v) {
+      $r .= $r ? ',' . $n . $ind . $ind : $ind . $ind;
+      $r .= $is_flat ? '' : '"' . $k . '": ';
+      $r .= is_array($v) ? $this->getSerializedArray($v, $ind . '  ') : '"' . str_replace($from, $to, $v) . '"';
+    }
+    return $is_flat ? $ind . '[' . $n . $r . $n . $ind . ']' : $ind . '{' . $n . $r . $n . $ind . '}';
+  }
+  
+  /*  */
+
+  function isAssociativeArray($v) {
+    foreach (array_keys($v) as $k => $val) {
+      if ($k !== $val) return 1;
+    }
+    return 0;
+  }
+  
+  /*  */
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_LegacyXMLSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Legacy XML Serializer
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_LegacyXMLSerializer extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'text/xml';
+  }
+
+  /*  */
+  
+  function getSerializedArray($struct, $root = 1, $ind = '  ') {
+    $n = "\n";
+    $r = '';
+    $is_flat = $this->isAssociativeArray($struct) ? 0 : 1;
+    foreach ($struct as $k => $v) {
+      $tag = $is_flat ? 'item' : preg_replace('/[\s]/s', '_', $k);
+      $tag = preg_replace('/^.*([a-z0-9\-\_]+)$/Uis', '\\1', $tag);
+      $r .= $n . $ind . '<' . $tag . '>' . (is_array($v) ? $this->getSerializedArray($v, 0, $ind . '  ') . $n . $ind : htmlspecialchars($v)) . '</' . $tag . '>';
+    }
+    if ($root) $r = $this->getHead() . $r . $this->getFooter();
+    return $r;
+  }
+  
+  /*  */
+
+  function getHead() {
+    $n = "\n";
+    $r = '<?xml version="1.0"?>';
+    $r .= $n . '<items>';
+    return $r;
+  }
+  
+  function getFooter() {
+    $n = "\n";
+    $r = $n . '</items>';
+    return $r;
+  }
+  
+  /*  */
+
+  function isAssociativeArray($v) {
+    foreach (array_keys($v) as $k => $val) {
+      if ($k !== $val) return 1;
+    }
+    return 0;
+  }
+  
+  /*  */
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_MicroRDFSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,142 @@
+<?php
+/**
+ * ARC2 MicroRDF Serializer
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('RDFSerializer');
+
+class ARC2_MicroRDFSerializer extends ARC2_RDFSerializer {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'text/html';
+    $this->label_store = $this->v('label_store', '', $this->a);
+  }
+
+  /*  */
+  
+  function getLabel($res, $ps = '') {
+    if (!$ps) $ps = array();
+    foreach ($ps as $p => $os) {
+      if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
+        return $os[0]['value'];
+      }
+    }
+    if (preg_match('/^\_\:/', $res)) return "An unnamed resource";
+    return $this->extractTermLabel($res);
+    return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
+  }
+  
+  function getSerializedIndex($index, $res = '') {
+    $r = '';
+    $n = "\n";
+    if ($res) $index = array($res => $index[$res]);
+    //return Trice::dump($index);
+    $types = $this->v($this->expandPName('rdf:type'), array(), $index);
+    $main_type = $types ? $types[0]['value'] : '';
+    foreach ($index as $s => $ps) {
+      /* node */
+      $r .= '
+        <div class="rdf-item" ' . $this->mdAttrs($s, $main_type) . '>
+          <h3 class="rdf-itemlabel"><a href="' . $s . '">' . ucfirst($this->getLabel($s, $ps))  . '</a></h3>
+      ';
+      /* arcs */
+      foreach ($ps as $p => $os) {
+        $p_cls = strtolower($this->getPName($p));
+        $p_cls = str_replace(':', '-', $p_cls);
+        $r .= '
+          <div class="rdf-prop ' . $p_cls . '">
+            <a class="rdf-proplabel" href="' . $p . '">' . ucfirst($this->getLabel($p)) . ':</a>
+            <ul class="rdf-values">
+        ';
+        $oc = count($os);
+        foreach ($os as $i => $o) {
+          $val = $this->getObjectValue($o, $p);
+          $cls = '';
+          if ($i == 0) $cls .= ($cls ? ' ' : '') . 'first';
+          if ($i == $oc - 1) $cls .= ($cls ? ' ' : '') . 'last';
+          $r .= $n . '<li' . ($cls ? ' class="' . $cls . '"' : '') . '>' . $val . '</li>';
+        }
+        $r .= '
+            </ul>
+            <div class="clb"></div>
+          </div>
+        ';
+      }
+      /* /node */
+      $r .= '
+        <div class="clb"></div>
+        </div>
+      ';
+    }
+    return $r;
+  }
+  
+  function getObjectValue($o, $p) {
+    if ($o['type'] == 'uri') {
+      if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
+        return $this->getImageObjectValue($o, $p);
+      }
+      return $this->getURIObjectValue($o, $p);
+    }
+    if ($o['type'] == "bnode") {
+      return $this->getBNodeObjectValue($o, $p);
+    }
+    return $this->getLiteralObjectValue($o, $p);
+  }
+  
+  function getImageObjectValue($o, $p) {
+    return '<img class="rdf-value" itemprop="' . $p. '" src="' . htmlspecialchars($o['value']) . '" alt="img" />';
+  }
+  
+  function getURIObjectValue($o, $p) {
+    $id = htmlspecialchars($o['value']);
+    $label = $this->getObjectLabel($o['value']);
+    /* differing href */
+    $href = htmlspecialchars($this->v('href', $o['value'], $o));
+    if ($id != $href) {
+      return '<a class="rdf-value" itemprop="' . $p. '" href="' . $id . '" onclick="location.href=\'' . $href . '\';return false">' . $label . '</a>';
+    }
+    return '<a class="rdf-value" itemprop="' . $p. '" href="' . $id . '">' . $label . '</a>';
+    //$label = $o['value'];
+    //$label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
+  }
+
+  function getBNodeObjectValue($o, $p) {
+    return '<div class="rdf-value" itemprop="' . $p. '" itemscope="">' . $o['value'] . '</div>';
+    return '<div class="rdf-value" itemprop="' . $p. '" itemscope="">An unnamed resource</div>';
+  }
+
+  function getLiteralObjectValue($o, $p) {
+    return '<div class="rdf-value" itemprop="' . $p. '">' . $o['value'] . '</div>';
+  }
+
+  /*  */
+
+  function getObjectLabel($id) {
+    $r = $this->extractTermLabel($id);
+    if (!$this->label_store) return $r;
+    $q = '
+      SELECT ?val WHERE {
+        <' . $id . '> ?p ?val .
+        FILTER(REGEX(str(?p), "(label|title|name|summary)$"))
+      } LIMIT 1
+    ';
+    $row = $this->label_store->query($q, 'row');
+    return $row ? $row['val'] : $r;
+  }
+
+  /*  */
+  
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_NTriplesSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,192 @@
+<?php
+/**
+ * ARC2 N-Triples Serializer
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+*/
+
+ARC2::inc('RDFSerializer');
+
+class ARC2_NTriplesSerializer extends ARC2_RDFSerializer {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->esc_chars = array();
+    $this->raw = 0;
+  }
+
+  /*  */
+  
+  function getTerm($v, $term = '') {
+    // type detection
+    if (!is_array($v) || empty($v['type'])) {
+      // bnode
+      if (preg_match('/^\_\:/', $v)) {
+        return $this->getTerm(array('value' => $v, 'type' => 'bnode'));
+      }
+      // uri
+      if (preg_match('/^[a-z0-9]+\:[^\s\"]*$/is' . ($this->has_pcre_unicode ? 'u' : ''), $v)) {
+        return $this->getTerm(array('value' => $v, 'type' => 'uri'));
+      }
+      // fallback for non-unicode environments: subjects and predicates can't be literals.
+      if (in_array($term, array('s', 'p'))) {
+        return $this->getTerm(array('value' => $v, 'type' => 'uri'));
+      }
+      // assume literal
+      return $this->getTerm(array('type' => 'literal', 'value' => $v));
+    }
+    if ($v['type'] == 'bnode') {
+      return $v['value'];
+    }
+    elseif ($v['type'] == 'uri') {
+      return '<' . $this->escape($v['value']) . '>';
+    }
+    // something went wrong
+    elseif ($v['type'] != 'literal') {
+      return $this->getTerm($v['value']);
+    }
+    /* literal */
+    $quot = '"';
+    if ($this->raw && preg_match('/\"/', $v['value'])) {
+      $quot = "'";
+      if (preg_match('/\'/', $v['value'])) {
+        $quot = '"""';
+        if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
+          $quot = "'''";
+          $v['value'] = preg_replace("/'$/", "' ", $v['value']);
+          $v['value'] = preg_replace("/^'/", " '", $v['value']);
+          $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+        }
+      }
+    }
+    if ($this->raw && (strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) {
+      $quot = $quot . $quot . $quot;
+    }
+    $suffix = isset($v['lang']) && $v['lang'] ? '@' . $v['lang'] : '';
+    $suffix = isset($v['datatype']) && $v['datatype'] ? '^^' . $this->getTerm($v['datatype']) : $suffix;
+    //return $quot . "object" . utf8_encode($v['value']) . $quot . $suffix;
+    return $quot . $this->escape($v['value']) . $quot . $suffix;
+  }
+  
+  function getSerializedIndex($index, $raw = 0) {
+    $this->raw = $raw;
+    $r = '';
+    $nl = "\n";
+    foreach ($index as $s => $ps) {
+      $s = $this->getTerm($s, 's');
+      foreach ($ps as $p => $os) {
+        $p = $this->getTerm($p, 'p');
+        if (!is_array($os)) {/* single literal o */
+          $os = array(array('value' => $os, 'type' => 'literal'));
+        }
+        foreach ($os as $o) {
+          $o = $this->getTerm($o, 'o‚');
+          $r .= $r ? $nl : '';
+          $r .= $s . ' ' . $p . ' ' . $o . ' .';
+        }
+      }
+    }
+    return $r . $nl;
+  }
+  
+  /*  */
+
+  function escape($v) {
+    $r = '';
+	// decode, if possible
+    $v = (strpos(utf8_decode(str_replace('?', '', $v)), '?') === false) ? utf8_decode($v) : $v;
+	if ($this->raw) return $v;// no further escaping wanted
+	// escape tabs and linefeeds
+	$v = str_replace(array("\t", "\r", "\n"), array('\t', '\r', '\n'), $v);
+	// escape non-ascii-chars
+	$v = preg_replace_callback('/([^a-zA-Z0-9 \!\#\$\%\&\(\)\*\+\,\-\.\/\:\;\=\?\@\^\_\{\|\}]+)/', array($this, 'escapeChars'), $v);
+	return $v;
+  }
+  
+  function escapeChars($matches) {
+	$v = $matches[1];
+	$r = '';
+	// loop through mb chars
+	if (function_exists('mb_strlen')) {
+		for ($i = 0, $i_max = mb_strlen($v, 'UTF-8'); $i < $i_max; $i++) {
+		  $c = mb_substr($v, $i, 1, 'UTF-8');
+		  if (!isset($this->esc_chars[$c])) {
+			$this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c, 1));
+		  }
+		  $r .= $this->esc_chars[$c];
+		}
+	}
+	// fall back to built-in JSON functionality, if available
+	else if (function_exists('json_encode')) {
+		$r = json_encode($v);
+		if ($r == 'null') $r = json_encode (utf8_encode($v));
+		// remove boundary quotes
+		if (substr($r, 0, 1) == '"') $r = substr($r, 1);
+		if (substr($r, -1) == '"') $r = substr($r, 0, -1);
+		// uppercase hex chars
+		$r = preg_replace('/(\\\u)([0-9a-f]{4})/e', "'\\1' . strtoupper('\\2')", $r);
+		$r = preg_replace('/(\\\U)([0-9a-f]{8})/e', "'\\1' . strtoupper('\\2')", $r);
+	}
+	// escape byte-wise (may be wrong for mb chars and newer php versions)
+	else {
+		for ($i = 0, $i_max = strlen($v); $i < $i_max; $i++) {
+		  $c = $v[$i];
+		  if (!isset($this->esc_chars[$c])) {
+			$this->esc_chars[$c] = $this->getEscapedChar($c, $this->getCharNo($c));
+		  }
+		  $r .= $this->esc_chars[$c];
+		}
+	}
+	return $r;
+  }
+  
+  /*  */
+  
+  function getCharNo($c, $is_encoded = false) {
+    $c_utf = $is_encoded ? $c : utf8_encode($c);
+    $bl = strlen($c_utf);/* binary length */
+    $r = 0;
+    switch ($bl) {
+      case 1:/* 0####### (0-127) */
+        $r = ord($c_utf);
+        break;
+      case 2:/* 110##### 10###### = 192+x 128+x */
+        $r = ((ord($c_utf[0]) - 192) * 64) + (ord($c_utf[1]) - 128);
+        break;
+      case 3:/* 1110#### 10###### 10###### = 224+x 128+x 128+x */
+        $r = ((ord($c_utf[0]) - 224) * 4096) + ((ord($c_utf[1]) - 128) * 64) + (ord($c_utf[2]) - 128);
+        break;
+      case 4:/* 1111#### 10###### 10###### 10###### = 240+x 128+x 128+x 128+x */
+        $r = ((ord($c_utf[0]) - 240) * 262144) + ((ord($c_utf[1]) - 128) * 4096) + ((ord($c_utf[2]) - 128) * 64) + (ord($c_utf[3]) - 128);
+        break;
+    }
+    return $r;
+  }
+
+  function getEscapedChar($c, $no) {/*see http://www.w3.org/TR/rdf-testcases/#ntrip_strings */
+    if ($no < 9)        return "\\u" . sprintf('%04X', $no);  /* #x0-#x8 (0-8) */
+    if ($no == 9)       return '\t';                          /* #x9 (9) */
+    if ($no == 10)      return '\n';                          /* #xA (10) */
+    if ($no < 13)       return "\\u" . sprintf('%04X', $no);  /* #xB-#xC (11-12) */
+    if ($no == 13)      return '\r';                          /* #xD (13) */
+    if ($no < 32)       return "\\u" . sprintf('%04X', $no);  /* #xE-#x1F (14-31) */
+    if ($no < 34)       return $c;                            /* #x20-#x21 (32-33) */
+    if ($no == 34)      return '\"';                          /* #x22 (34) */
+    if ($no < 92)       return $c;                            /* #x23-#x5B (35-91) */
+    if ($no == 92)      return '\\';                          /* #x5C (92) */
+    if ($no < 127)      return $c;                            /* #x5D-#x7E (93-126) */
+    if ($no < 65536)    return "\\u" . sprintf('%04X', $no);  /* #x7F-#xFFFF (128-65535) */
+    if ($no < 1114112)  return "\\U" . sprintf('%08X', $no);  /* #x10000-#x10FFFF (65536-1114111) */
+    return '';                                                /* not defined => ignore */
+  }
+  
+  /*  */
+ 
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_POSHRDFSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,105 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 POSH RDF Serializer
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('RDFSerializer');
+
+class ARC2_POSHRDFSerializer extends ARC2_RDFSerializer {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'text/html';
+  }
+
+  /*  */
+  
+  function getLabel($res, $ps = '') {
+    if (!$ps) $ps = array();
+    foreach ($ps as $p => $os) {
+      if (preg_match('/[\/\#](name|label|summary|title|fn)$/i', $p)) {
+        return $os[0]['value'];
+      }
+    }
+    if (preg_match('/^\_\:/', $res)) return "An unnamed resource";
+    return preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('_', ' ', $res));
+  }
+  
+  function getSerializedIndex($index, $res = '') {
+    $r = '';
+    $n = "\n";
+    if ($res) $index = array($res => $index[$res]);
+    //return Trice::dump($index);
+    foreach ($index as $s => $ps) {
+      /* node */
+      $r .= '
+        <div class="rdf-view">
+          <h3><a class="rdf-s" href="' . $s . '">' . $this->getLabel($s, $ps)  . '</a></h3>
+      ';
+      /* arcs */
+      foreach ($ps as $p => $os) {
+        $r .= '
+          <div class="rdf-o-list">
+            <a class="rdf-p" href="' . $p . '">' . ucfirst($this->getLabel($p)) . '</a>
+        ';
+        foreach ($os as $o) {
+          $r .= $n . $this->getObjectValue($o);
+        }
+        $r .= '    
+          </div>
+        ';
+      }
+      /* node */
+      $r .= '
+        <div class="clb"></div>
+        </div>
+      ';
+    }
+    return $r;
+  }
+  
+  function getObjectValue($o) {
+    if ($o['type'] == 'uri') {
+      if (preg_match('/(jpe?g|gif|png)$/i', $o['value'])) {
+        return $this->getImageObjectValue($o);
+      }
+      return $this->getURIObjectValue($o);
+    }
+    if ($o['type'] == "bnode") {
+      return $this->getBNodeObjectValue($o);
+    }
+    return $this->getLiteralObjectValue($o);
+  }
+  
+  function getImageObjectValue($o) {
+    return '<img class="rdf-o" src="' . htmlspecialchars($o['value']) . '" alt="img" />';
+  }
+  
+  function getURIObjectValue($o) {
+    $href = htmlspecialchars($o['value']);
+    $label = $o['value'];
+    $label = preg_replace('/^https?\:\/\/(www\.)?/', '', $label);
+    return '<a class="rdf-o" href="' . $href . '">' . $label . '</a>';
+  }
+
+  function getBNodeObjectValue($o) {
+    return '<div class="rdf-o" title="' . $o['value']. '">An unnamed resource</div>';
+  }
+
+  function getLiteralObjectValue($o) {
+    return '<div class="rdf-o">' . $o['value'] . '</div>';
+  }
+
+  /*  */
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_RDFJSONSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,89 @@
+<?php
+/**
+ * ARC2 RDF/JSON Serializer
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+*/
+
+ARC2::inc('RDFSerializer');
+
+class ARC2_RDFJSONSerializer extends ARC2_RDFSerializer {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'application/json';
+  }
+
+  /*  */
+  
+  function getTerm($v, $term = 's') {
+    if (!is_array($v)) {
+      if (preg_match('/^\_\:/', $v)) {
+        return ($term == 'o') ? $this->getTerm(array('value' => $v, 'type' => 'bnode'), 'o') : '"' . $v . '"';
+      }
+      return ($term == 'o') ? $this->getTerm(array('value' => $v, 'type' => 'uri'), 'o') : '"' . $v . '"';
+    }
+    if (!isset($v['type']) || ($v['type'] != 'literal')) {
+      if ($term != 'o') {
+        return $this->getTerm($v['value'], $term);
+      }
+      if (preg_match('/^\_\:/', $v['value'])) {
+        return '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "bnode" }';
+      }
+      return '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "uri" }';
+    }
+    /* literal */
+    $r = '{ "value" : "' . $this->jsonEscape($v['value']) . '", "type" : "literal"';
+    $suffix = isset($v['datatype']) ? ', "datatype" : "' . $v['datatype'] . '"' : '';
+    $suffix = isset($v['lang']) ? ', "lang" : "' . $v['lang'] . '"' : $suffix;
+    $r .= $suffix . ' }';
+    return $r;
+  }
+
+  function jsonEscape($v) {
+    if (function_exists('json_encode')) {
+        return preg_replace('/^"(.*)"$/', '\\1', str_replace("\/","/",json_encode($v)));
+    }
+    $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f");
+    $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f');
+    return str_replace($from, $to, $v);
+  }
+    
+  function getSerializedIndex($index, $raw = 0) {
+    $r = '';
+    $nl = "\n";
+    foreach ($index as $s => $ps) {
+      $r .= $r ? ',' . $nl . $nl : '';
+      $r .= '  ' . $this->getTerm($s). ' : {';
+      $first_p = 1;
+      foreach ($ps as $p => $os) {
+        $r .= $first_p ? $nl : ',' . $nl;
+        $r .= '    ' . $this->getTerm($p). ' : [';
+        $first_o = 1;
+        if (!is_array($os)) {/* single literal o */
+          $os = array(array('value' => $os, 'type' => 'literal'));
+        }
+        foreach ($os as $o) {
+          $r .= $first_o ? $nl : ',' . $nl;
+          $r .= '      ' . $this->getTerm($o, 'o');
+          $first_o = 0;
+        }
+        $first_p = 0;
+        $r .= $nl . '    ]';
+      }
+      $r .= $nl . '  }';
+    }
+    $r .= $r ? ' ' : '';
+    return '{' . $nl . $r . $nl . '}';
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_RDFSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,53 @@
+<?php
+/**
+ * ARC2 RDF Serializer
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_RDFSerializer extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    foreach ($this->ns as $k => $v) {
+      $this->nsp[$v] = $k;
+    }
+  }
+
+  /*  */
+  
+  function xgetPName($v) {/* moved to merged getPName in ARC2_CLass */
+    if (preg_match('/^([a-z0-9\_\-]+)\:([a-z\_][a-z0-9\_\-]*)$/i', $v, $m) && isset($this->ns[$m[1]])) {
+      $this->used_ns = !in_array($this->ns[$m[1]], $this->used_ns) ? array_merge($this->used_ns, array($this->ns[$m[1]])) : $this->used_ns;
+      return $v;
+    }
+    if (preg_match('/^(.*[\/\#])([a-z\_][a-z0-9\-\_]*)$/i', $v, $m)) {
+      return $this->getPrefix($m[1]) . ':' . $m[2];
+    }
+    return 0;
+  }
+  
+  /*  */
+  
+  function getSerializedTriples($triples, $raw = 0) {
+    $index = ARC2::getSimpleIndex($triples, 0);
+    return $this->getSerializedIndex($index, $raw);
+  }
+  
+  function getSerializedIndex($index, $raw = 0) {
+    return '';
+  }
+  
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_RDFXMLSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,198 @@
+<?php
+/**
+ * ARC2 RDF/XML Serializer
+ *
+ * @author    Benjamin Nowack
+ * @license   <http://arc.semsol.org/license>
+ * @homepage  <http://arc.semsol.org/>
+ * @package   ARC2
+ * @version   2010-11-16
+*/
+
+ARC2::inc('RDFSerializer');
+
+class ARC2_RDFXMLSerializer extends ARC2_RDFSerializer {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'application/rdf+xml';
+    $this->pp_containers = $this->v('serializer_prettyprint_containers', 0, $this->a);
+    $this->default_ns = $this->v('serializer_default_ns', '', $this->a);
+    $this->type_nodes = $this->v('serializer_type_nodes', 0, $this->a);
+  }
+
+  /*  */
+  
+  function getTerm($v, $type) {
+    if (!is_array($v)) {/* uri or bnode */
+      if (preg_match('/^\_\:(.*)$/', $v, $m)) {
+        return ' rdf:nodeID="' . $m[1] . '"';
+      }
+      if ($type == 's') {
+        return ' rdf:about="' . htmlspecialchars($v) . '"';
+      }
+      if ($type == 'p') {
+        $pn = $this->getPName($v);
+        return $pn ? $pn : 0;
+      }
+      if ($type == 'o') {
+        $v = $this->expandPName($v);
+        if (!preg_match('/^[a-z0-9]{2,}\:[^\s]+$/is', $v)) return $this->getTerm(array('value' => $v, 'type' => 'literal'), $type);
+        return ' rdf:resource="' . htmlspecialchars($v) . '"';
+      }
+      if ($type == 'datatype') {
+        $v = $this->expandPName($v);
+        return ' rdf:datatype="' . htmlspecialchars($v) . '"';
+      }
+      if ($type == 'lang') {
+        return ' xml:lang="' . htmlspecialchars($v) . '"';
+      }
+    }
+    if ($this->v('type', '', $v) != 'literal') {
+      return $this->getTerm($v['value'], 'o');
+    }
+    /* literal */
+    $dt = isset($v['datatype']) ? $v['datatype'] : '';
+    $lang = isset($v['lang']) ? $v['lang'] : '';
+    if ($dt == 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') {
+      return ' rdf:parseType="Literal">' . $v['value'];
+    }
+    elseif ($dt) {
+      return $this->getTerm($dt, 'datatype') . '>' . htmlspecialchars($v['value']);
+    }
+    elseif ($lang) {
+      return $this->getTerm($lang, 'lang') . '>' . htmlspecialchars($v['value']);
+    }
+    return '>' . htmlspecialchars($this->v('value', '', $v));
+  }
+
+  function getPName($v, $connector = ':') {
+    if ($this->default_ns && (strpos($v, $this->default_ns) === 0)) {
+      $pname = substr($v, strlen($this->default_ns));
+      if (!preg_match('/\//', $pname)) return $pname;
+    }
+    return parent::getPName($v, $connector);
+  }
+  
+  function getHead() {
+    $r = '';
+    $nl = "\n";
+    $r .= '<?xml version="1.0" encoding="UTF-8"?>';
+    $r .= $nl . '<rdf:RDF';
+    $first_ns = 1;
+    foreach ($this->used_ns as $v) {
+      $r .= $first_ns ? ' ' : $nl . '  ';
+      foreach ($this->ns as $prefix => $ns) {
+        if ($ns != $v) continue;
+        $r .= 'xmlns:' . $prefix . '="' .$v. '"';
+        break;
+      }
+      $first_ns = 0;
+    }
+    if ($this->default_ns) {
+      $r .= $first_ns ? ' ' : $nl . '  ';
+      $r .= 'xmlns="' . $this->default_ns . '"';
+    }
+    $r .= '>';
+    return $r;
+  }
+  
+  function getFooter() {
+    $r = '';
+    $nl = "\n";
+    $r .= $nl . $nl . '</rdf:RDF>';
+    return $r;
+  }
+  
+  function getSerializedIndex($index, $raw = 0) {
+    $r = '';
+    $nl = "\n";
+    foreach ($index as $raw_s => $ps) {
+      $r .= $r ? $nl . $nl : '';
+      $s = $this->getTerm($raw_s, 's');
+      $tag = 'rdf:Description';
+      list($tag, $ps) = $this->getNodeTag($ps);
+      $sub_ps = 0;
+      /* pretty containers */
+      if ($this->pp_containers && ($ctag = $this->getContainerTag($ps))) {
+        $tag = 'rdf:' . $ctag;
+        list($ps, $sub_ps) = $this->splitContainerEntries($ps);
+      }
+      $r .= '  <' . $tag . '' .$s . '>';
+      $first_p = 1;
+      foreach ($ps as $p => $os) {
+        if (!$os) continue;
+        $p = $this->getTerm($p, 'p');
+        if ($p) {
+          $r .= $nl . str_pad('', 4);
+          $first_o = 1;
+          if (!is_array($os)) {/* single literal o */
+            $os = array(array('value' => $os, 'type' => 'literal'));
+          }
+          foreach ($os as $o) {
+            $o = $this->getTerm($o, 'o');
+            $r .= $first_o ? '' : $nl . '    ';
+            $r .= '<' . $p;
+            $r .= $o;
+            $r .= preg_match('/\>/', $o) ? '</' . $p . '>' : '/>'; 
+            $first_o = 0;
+          }
+          $first_p = 0;
+        }
+      }
+      $r .= $r ? $nl . '  </' . $tag . '>' : '';
+      if ($sub_ps) $r .= $nl . $nl . $this->getSerializedIndex(array($raw_s => $sub_ps), 1);
+    }
+    if ($raw) {
+      return $r;
+    }
+    return $this->getHead() . $nl . $nl . $r . $this->getFooter();
+  }
+
+  function getNodeTag($ps) {
+    if (!$this->type_nodes) return array('rdf:Description', $ps);
+    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $types = $this->v($rdf . 'type', array(), $ps);
+    if (!$types) return array('rdf:Description', $ps);
+    $type = array_shift($types);
+    $ps[$rdf . 'type'] = $types;
+    if (!is_array($type)) $type = array('value' => $type);
+    return array($this->getPName($type['value']), $ps);
+  }
+
+  /*  */
+
+  function getContainerTag($ps) {
+    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    if (!isset($ps[$rdf . 'type'])) return '';
+    $types = $ps[$rdf . 'type'];
+    foreach ($types as $type) {
+      if (!in_array($type['value'], array($rdf . 'Bag', $rdf . 'Seq', $rdf . 'Alt'))) return '';
+      return str_replace($rdf, '', $type['value']);
+    }
+  }
+
+  function splitContainerEntries($ps) {
+    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $items = array();
+    $rest = array();
+    foreach ($ps as $p => $os) {
+      $p_short = str_replace($rdf, '', $p);
+      if ($p_short === 'type') continue;
+      if (preg_match('/^\_([0-9]+)$/', $p_short, $m)) {
+        $items = array_merge($items, $os);
+      }
+      else {
+        $rest[$p] = $os;
+      }
+    }
+    if ($items) return array(array($rdf . 'li' => $items), $rest);
+    return array($rest, 0);
+  }
+
+  /*  */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_RSS10Serializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,30 @@
+<?php
+/**
+ * ARC2 RSS 1.0 Serializer
+ *
+ * @author Toby Inkster
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('RDFXMLSerializer');
+
+class ARC2_RSS10Serializer extends ARC2_RDFXMLSerializer {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'application/rss+xml';
+    $this->default_ns = 'http://purl.org/rss/1.0/';
+    $this->type_nodes = true;
+  }
+
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/serializers/ARC2_TurtleSerializer.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,121 @@
+<?php
+/**
+ * ARC2 Turtle Serializer
+ *
+ * @author    Benjamin Nowack
+ * @license   http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package   ARC2
+ * @version   2010-11-16
+*/
+
+ARC2::inc('RDFSerializer');
+
+class ARC2_TurtleSerializer extends ARC2_RDFSerializer {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->content_header = 'application/x-turtle';
+  }
+
+  /*  */
+  
+  function getTerm($v, $term = '', $qualifier = '') {
+    if (!is_array($v)) {
+      if (preg_match('/^\_\:/', $v)) {
+        return $v;
+      }
+      if (($term === 'p') && ($pn = $this->getPName($v))) {
+        return $pn;
+      }
+      if (
+        ($term === 'o') &&
+        in_array($qualifier, array('rdf:type', 'rdfs:domain', 'rdfs:range', 'rdfs:subClassOf')) &&
+        ($pn = $this->getPName($v))
+      ) {
+        return $pn;
+      }
+      if (preg_match('/^[a-z0-9]+\:[^\s]*$/is' . ($this->has_pcre_unicode ? 'u' : ''), $v)) {
+        return '<' .$v. '>';
+      }
+      return $this->getTerm(array('type' => 'literal', 'value' => $v), $term, $qualifier);
+    }
+    if (!isset($v['type']) || ($v['type'] != 'literal')) {
+      return $this->getTerm($v['value'], $term, $qualifier);
+    }
+    /* literal */
+    $quot = '"';
+    if (preg_match('/\"/', $v['value'])) {
+      $quot = "'";
+      if (preg_match('/\'/', $v['value']) || preg_match('/[\x0d\x0a]/', $v['value'])) {
+        $quot = '"""';
+        if (preg_match('/\"\"\"/', $v['value']) || preg_match('/\"$/', $v['value']) || preg_match('/^\"/', $v['value'])) {
+          $quot = "'''";
+          $v['value'] = preg_replace("/'$/", "' ", $v['value']);
+          $v['value'] = preg_replace("/^'/", " '", $v['value']);
+          $v['value'] = str_replace("'''", '\\\'\\\'\\\'', $v['value']);
+        }
+      }
+    }
+    if ((strlen($quot) == 1) && preg_match('/[\x0d\x0a]/', $v['value'])) {
+      $quot = $quot . $quot . $quot;
+    }
+    $suffix = isset($v['lang']) && $v['lang'] ? '@' . $v['lang'] : '';
+    $suffix = isset($v['datatype']) && $v['datatype'] ? '^^' . $this->getTerm($v['datatype'], 'dt') : $suffix;
+    return $quot . $v['value'] . $quot . $suffix;
+  }
+  
+  function getHead() {
+    $r = '';
+    $nl = "\n";
+    foreach ($this->used_ns as $v) {
+      $r .= $r ? $nl : '';
+      foreach ($this->ns as $prefix => $ns) {
+        if ($ns != $v) continue;
+        $r .= '@prefix ' . $prefix . ': <' .$v. '> .';
+        break;
+      }
+    }
+    return $r;
+  }
+  
+  function getSerializedIndex($index, $raw = 0) {
+    $r = '';
+    $nl = "\n";
+    foreach ($index as $s => $ps) {
+      $r .= $r ? ' .' . $nl . $nl : '';
+      $s = $this->getTerm($s, 's');
+      $r .= $s;
+      $first_p = 1;
+      foreach ($ps as $p => $os) {
+        if (!$os) continue;
+        $p = $this->getTerm($p, 'p');
+        $r .= $first_p ? ' ' : ' ;' . $nl . str_pad('', strlen($s) + 1);
+        $r .= $p;
+        $first_o = 1;
+        if (!is_array($os)) {/* single literal o */
+          $os = array(array('value' => $os, 'type' => 'literal'));
+        }
+        foreach ($os as $o) {
+          $r .= $first_o ? ' ' : ' ,' . $nl . str_pad('', strlen($s) + strlen($p) + 2);
+          $o = $this->getTerm($o, 'o', $p);
+          $r .= $o;
+          $first_o = 0;
+        }
+        $first_p = 0;
+      }
+    }
+    $r .= $r ? ' .' : '';
+    if ($raw) {
+      return $r;
+    }
+    return $r ? $this->getHead() . $nl . $nl . $r : '';
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/sparqlscript/ARC2_SPARQLScriptParser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,280 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 SPARQLScript Parser (SPARQL+ + functions)
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('ARC2_SPARQLPlusParser');
+
+class ARC2_SPARQLScriptParser extends ARC2_SPARQLPlusParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+
+  function parse($v, $src = '', $iso_fallback = 'ignore') {
+    $this->setDefaultPrefixes();
+    $this->base = $src ? $this->calcBase($src) : ARC2::getScriptURI();
+    $this->blocks = array();
+    $this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
+    do {
+      $proceed = 0;
+      if ((list($r, $v) = $this->xScriptBlock($v)) && $r) {
+        $this->blocks[] = $r;
+        $proceed = 1;
+      }
+      $this->unparsed_code = trim($v);
+    } while ($proceed);
+    if (trim($this->unparsed_code) && !$this->getErrors()) {
+      $rest = preg_replace('/[\x0a|\x0d]/i', ' ', substr($this->unparsed_code, 0, 30));
+      $msg = trim($rest) ? 'Could not properly handle "' . $rest . '"' : 'Syntax Error';
+      $this->addError($msg);
+    }
+  }
+  
+  function getScriptBlocks() {
+    return $this->v('blocks', array());
+  }
+
+  /*  */
+
+  function xScriptBlock($v) {
+    /* comment removal */  
+    while (preg_match('/^\s*(\#[^\xd\xa]*)(.*)$/si', $v, $m)) $v = $m[2];
+    /* BaseDecl */
+    if ((list($sub_r, $v) = $this->xBaseDecl($v)) && $sub_r) {
+      $this->base = $sub_r;
+    }
+    /* PrefixDecl */
+    while ((list($r, $v) = $this->xPrefixDecl($v)) && $r) {
+      $this->prefixes[$r['prefix']] = $r['uri'];
+    }
+    /* EndpointDecl */
+    if ((list($r, $v) = $this->xEndpointDecl($v)) && $r) {
+      return array($r, $v);
+    }
+    /* Return */
+    if ((list($r, $v) = $this->xReturn($v)) && $r) {
+      return array($r, $v);
+    }
+    /* Assignment */
+    if ((list($r, $v) = $this->xAssignment($v)) && $r) {
+      return array($r, $v);
+    }
+    /* IFBlock */
+    if ((list($r, $v) = $this->xIFBlock($v)) && $r) {
+      return array($r, $v);
+    }
+    /* FORBlock */
+    if ((list($r, $v) = $this->xFORBlock($v)) && $r) {
+      return array($r, $v);
+    }
+    /* String */
+    if ((list($r, $v) = $this->xString($v)) && $r) {
+      return array($r, $v);
+    }
+    /* FunctionCall */
+    if ((list($r, $v) = $this->xFunctionCall($v)) && $r) {
+      return array($r, ltrim($v, ';'));
+    }
+    /* Query */
+    $prev_r = $this->r;
+    $this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
+    if ((list($r, $rest) = $this->xQuery($v)) && $r) {
+      $q = $rest ? trim(substr($v, 0, -strlen($rest))) : trim($v);
+      $v = $rest;
+      $r = array_merge($this->r, array(
+        'type' => 'query',
+        'query_type' => $r['type'],
+        'query' => $q,
+        //'prefixes' => $this->prefixes,
+        'base' => $this->base,
+        //'infos' => $r
+      ));
+      return array($r, $v);
+    }
+    else {
+      $this->r = $prev_r;
+    }
+    return array(0, $v);
+  }
+
+  function xBlockSet($v) {
+    if (!$r = $this->x("\{", $v)) return array(0, $v);
+    $blocks = array();
+    $sub_v = $r[1];
+    while ((list($sub_r, $sub_v) = $this->xScriptBlock($sub_v)) && $sub_r) {
+      $blocks[] = $sub_r;
+    }
+    if (!$sub_r = $this->x("\}", $sub_v)) return array(0, $v);
+    $sub_v = $sub_r[1];
+    return array(array('type' => 'block_set', 'blocks' => $blocks), $sub_v);
+  }
+  
+  /* s2 */
+  
+  function xEndpointDecl($v) {
+    if ($r = $this->x("ENDPOINT\s+", $v)) {
+      if ((list($r, $sub_v) = $this->xIRI_REF($r[1])) && $r) {
+        $r = $this->calcURI($r, $this->base);
+        if ($sub_r = $this->x('\.', $sub_v)) {
+          $sub_v = $sub_r[1];
+        }
+        return array(
+          array('type' => 'endpoint_decl', 'endpoint' => $r),
+          $sub_v
+        );
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /* s3 */
+  
+  function xAssignment($v) {
+    /* Var */
+    list($r, $sub_v) = $this->xVar($v);
+    if (!$r) return array(0, $v);
+    $var = $r;
+    /* := | = */
+    if (!$sub_r = $this->x("\:?\=", $sub_v)) return array(0, $v);
+    $sub_v = $sub_r[1];
+    /* try String */
+    list($r, $sub_v) = $this->xString($sub_v);
+    if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'string', 'string' => $r), ltrim($sub_v, '; '));
+    /* try VarMerge */
+    list($r, $sub_v) = $this->xVarMerge($sub_v);
+    if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'var_merge', 'var2' => $r[0], 'var3' => $r[1]), ltrim($sub_v, '; '));
+    /* try Var */
+    list($r, $sub_v) = $this->xVar($sub_v);
+    if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'var', 'var2' => $r), ltrim($sub_v, '; '));
+    /* try function */
+    list($r, $sub_v) = $this->xFunctionCall($sub_v);
+    if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'function_call', 'function_call' => $r), ltrim($sub_v, '; '));
+    /* try Placeholder */
+    list($r, $sub_v) = $this->xPlaceholder($sub_v);
+    if ($r) return array(array('type' => 'assignment', 'var' => $var, 'sub_type' => 'placeholder', 'placeholder' => $r), ltrim($sub_v, '; '));
+    /* try query */
+    $prev_r = $this->r;
+    $this->r = array('base' => '', 'vars' => array(), 'prefixes' => $this->prefixes);
+    list($r, $rest) = $this->xQuery($sub_v);
+    if (!$r) {
+      $this->r = $prev_r;
+      return array(0, $v);
+    }
+    else {
+      $q = $rest ? trim(substr($sub_v, 0, -strlen($rest))) : trim($sub_v);
+      return array(
+        array(
+          'type' => 'assignment', 
+          'var' => $var,
+          'sub_type' => 'query',
+          'query' => array_merge($this->r, array(
+            'type' => 'query',
+            'query_type' => $r['type'],
+            'query' => $q,
+            'base' => $this->base,
+          )),
+        ),
+        ltrim($rest, '; ')
+      );
+    }
+  }
+
+  function xReturn($v) {
+    if ($r = $this->x("return\s+", $v)) {
+      /* fake assignment which accepts same right-hand values */
+      $sub_v = '$__return_value__ := ' . $r[1];
+      if ((list($r, $sub_v) = $this->xAssignment($sub_v)) && $r) {
+        $r['type'] = 'return';
+        return array($r, $sub_v);
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /* s4 'IF' BrackettedExpression '{' Script '}' ( 'ELSE' '{' Script '}')?  */
+  
+  function xIFBlock($v) {
+    if ($r = $this->x("IF\s*", $v)) {
+      if ((list($sub_r, $sub_v) = $this->xBrackettedExpression($r[1])) && $sub_r) {
+        $cond = $sub_r;
+        if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_v)) && $sub_r) {
+          $blocks = $sub_r['blocks'];
+          /* else */
+          $else_blocks = array();
+          $rest = $sub_v;
+          if ($sub_r = $this->x("ELSE\s*", $sub_v)) {
+            if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_r[1])) && $sub_r) {
+              $else_blocks = $sub_r['blocks'];
+            }
+            else {
+              $sub_v = $rest;
+            }
+          }
+          return array(
+            array(
+              'type' => 'ifblock',
+              'condition' => $cond,
+              'blocks' => $blocks,
+              'else_blocks' => $else_blocks,
+            ),
+            $sub_v
+          );
+        }
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /* s5 'FOR' '(' Var 'IN' Var ')' '{' Script '}' */
+  
+  function xFORBlock($v) {
+    if ($r = $this->x("FOR\s*\(\s*[\$\?]([^\s]+)\s+IN\s+[\$\?]([^\s]+)\s*\)", $v)) {/* @@todo split into sub-patterns? */
+      $iterator = $r[1];
+      $set_var = $r[2];
+      $sub_v = $r[3];
+      if ((list($sub_r, $sub_v) = $this->xBlockSet($sub_v)) && $sub_r) {
+        return array(
+          array(
+            'type' => 'forblock',
+            'set' => $set_var,
+            'iterator' => $iterator,
+            'blocks' => $sub_r['blocks']
+          ),
+          $sub_v
+        );
+      }
+    }
+    return array(0, $v);
+  }
+  
+  /* s6 Var '+' Var */
+  
+  function xVarMerge($v) {
+    if ((list($sub_r, $sub_v) = $this->xVar($v)) && $sub_r) {
+      $var1 = $sub_r;
+      if ($sub_r = $this->x("\+", $sub_v)) {
+        $sub_v = $sub_r[1];
+        if ((list($sub_r, $sub_v) = $this->xVar($sub_v)) && $sub_r) {
+          return array(
+            array($var1, $sub_r),
+            $sub_v
+          );
+        }
+      }
+    }
+    return array(0, $v);
+  }
+  
+}  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/sparqlscript/ARC2_SPARQLScriptProcessor.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,592 @@
+<?php
+/**
+ * ARC2 SPARQLScript Processor
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_SPARQLScriptProcessor extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->max_operations = $this->v('sparqlscript_max_operations', 0, $this->a);
+    $this->max_queries = $this->v('sparqlscript_max_queries', 0, $this->a);
+    $this->return = 0;
+    $this->script_hash = '';
+    $this->env = array(
+      'endpoint' => '',
+      'vars' => array(),
+      'output' => '',
+      'operation_count' => 0,
+      'query_count' => 0,
+      'query_log' => array()
+    );
+  }
+  
+  function reset() {
+    $this->__init();
+  }
+
+  /*  */
+  
+  function processScript($s) {
+    $this->script_hash = abs(crc32($s));
+    $parser = $this->getParser();
+    $parser->parse($s);
+    $blocks = $parser->getScriptBlocks();
+    if ($parser->getErrors()) return 0;
+    foreach ($blocks as $block) {
+      $this->processBlock($block);
+      if ($this->return) return 0;
+      if ($this->getErrors()) return 0;
+    }
+  }
+
+  function getResult() {
+    if ($this->return) {
+      return $this->getVarValue('__return_value__');
+    }
+    else {
+      return $this->env['output'];
+    }
+  }
+
+  /*  */
+  
+  function getParser() {
+    ARC2::inc('SPARQLScriptParser');
+    return new ARC2_SPARQLScriptParser($this->a, $this);
+  }
+  
+  /*  */
+
+  function setVar($name, $val, $type = 'literal', $meta = '') {
+    /* types: literal, var, rows, bool, doc, http_response, undefined, ? */
+    $this->env['vars'][$name] = array(
+      'value_type' => $type,
+      'value' => $val,
+      'meta' => $meta ? $meta : array()
+    );
+  }
+
+  function getVar($name) {
+    return isset($this->env['vars'][$name]) ? $this->env['vars'][$name] : '';
+  }
+
+  function getVarValue($name) {
+    return ($v = $this->getVar($name)) ? (isset($v['value']) ? $v['value'] : $v ) : '';
+  }
+
+  /*  */
+
+  function replacePlaceholders($val, $context = '', $return_string = 1, $loop = 0) {
+    do {
+      $old_val = $val;
+      if (preg_match_all('/(\{(?:[^{}]+|(?R))*\})/', $val, $m)) {
+        foreach ($m[1] as $match) {
+          if (strpos($val, '$' . $match) === false) {/* just some container brackets, recurse */
+            $val = str_replace($match, '{' . $this->replacePlaceholders(substr($match, 1, -1), $context, $return_string, $loop + 1) . '}', $val);
+          }
+          else {
+            $ph = substr($match, 1, -1);
+            $sub_val = $this->getPlaceholderValue($ph);
+            if (is_array($sub_val)) {
+              $sub_val = $this->getArraySerialization($sub_val, $context);
+            }
+            $val = str_replace('${' . $ph . '}', $sub_val, $val);
+          }
+        }
+      }
+    } while (($old_val != $val) && ($loop < 10));
+    return $val;
+  }
+  
+  function getPlaceholderValue($ph) {
+    /* simple vars */
+    if (isset($this->env['vars'][$ph])) {
+      return $this->v('value', $this->env['vars'][$ph], $this->env['vars'][$ph]);
+    }
+    /* GET/POST */
+    if (preg_match('/^(GET|POST)\.([^\.]+)(.*)$/', $ph, $m)) {
+      $vals = strtoupper($m[1]) == 'GET' ? $_GET : $POST;
+      $r = isset($vals[$m[2]]) ? $vals[$m[2]] : '';
+      return $m[3] ? $this->getPropertyValue(array('value' => $r, 'value_type' => '?'), ltrim($m[3], '.')) : $r;
+    }
+    /* NOW */
+    if (preg_match('/^NOW(.*)$/', $ph, $m)) {
+      $rest = $m[1];
+      /* may have sub-phs */
+      $rest = $this->replacePlaceholders($rest);
+      $r_struct = array(
+        'y' => date('Y'),
+        'mo' => date('m'),
+        'd' => date('d'),
+        'h' => date('H'),
+        'mi' => date('i'),
+        's' => date('s')
+      );
+      if (preg_match('/(\+|\-)\s*([0-9]+)(y|mo|d|h|mi|s)[a-z]*(.*)/is', trim($rest), $m2)) {
+        eval('$r_struct[$m2[3]] ' . $m2[1] . '= (int)' . $m2[2] . ';');
+        $rest = $m2[4];
+      }
+      $uts = mktime($r_struct['h'], $r_struct['mi'], $r_struct['s'], $r_struct['mo'], $r_struct['d'], $r_struct['y']);
+      $uts -= date('Z', $uts); /* timezone offset */
+      $r = date('Y-m-d\TH:i:s\Z', $uts);
+      if (preg_match('/^\.(.+)$/', $rest, $m)) {
+        return $this->getPropertyValue(array('value' => $r), $m[1]);
+      }
+      return $r;
+    }
+    /* property */
+    if (preg_match('/^([^\.]+)\.(.+)$/', $ph, $m)) {
+      list($var, $path) = array($m[1], $m[2]);
+      if (isset($this->env['vars'][$var])) {
+        return $this->getPropertyValue($this->env['vars'][$var], $path);
+      }
+    }
+    return '';
+  }
+  
+  function getPropertyValue($obj, $path) {
+    $val = isset($obj['value']) ? $obj['value'] : $obj;
+    $path = $this->replacePlaceholders($path, 'property_value', 0);
+    /* reserved */
+    if ($path == 'size') {
+      if ($obj['value_type'] == 'rows') return count($val);
+      if ($obj['value_type'] == 'literal') return strlen($val);
+    }
+    if (preg_match('/^replace\([\'\"](\/.*\/[a-z]*)[\'\"],\s*[\'\"](.*)[\'\"]\)$/is', $path, $m)) {
+      return @preg_replace($m[1], str_replace('$', '\\', $m[2]), $val);
+    }
+    if (preg_match('/^match\([\'\"](\/.*\/[a-z]*)[\'\"]\)$/is', $path, $m)) {
+      return @preg_match($m[1], $val, $m) ? $m : '';
+    }
+    if (preg_match('/^urlencode\([\'\"]?(get|post|.*)[\'\"]?\)$/is', $path, $m)) {
+      return (strtolower($m[1]) == 'post') ? rawurlencode($val) : urlencode($val);
+    }
+    if (preg_match('/^toDataURI\([^\)]*\)$/is', $path, $m)) {
+      return 'data:text/plain;charset=utf-8,' . rawurlencode($val);
+    }
+    if (preg_match('/^fromDataURI\([^\)]*\)$/is', $path, $m)) {
+      return rawurldecode(str_replace('data:text/plain;charset=utf-8,', '', $val));
+    }
+    if (preg_match('/^toPrettyDate\([^\)]*\)$/is', $path, $m)) {
+      $uts = strtotime(preg_replace('/(T|\+00\:00)/', ' ', $val));
+      return date('D j M H:i', $uts);
+    }
+    if (preg_match('/^render\(([^\)]*)\)$/is', $path, $m)) {
+      $src_format = trim($m[1], '"\'');
+      return $this->render($val, $src_format);
+    }
+    /* struct */
+    if (is_array($val)) {
+      if (isset($val[$path])) return $val[$path];
+      $exp_path = $this->expandPName($path);
+      if (isset($val[$exp_path])) return $val[$exp_path];
+      if (preg_match('/^([^\.]+)\.(.+)$/', $path, $m)) {
+        list($var, $path) = array($m[1], $m[2]);
+        if (isset($val[$var])) {
+          return $this->getPropertyValue(array('value' => $val[$var]), $path);
+        }
+        /* qname */
+        $exp_var = $this->expandPName($var);
+        if (isset($val[$exp_var])) {
+          return $this->getPropertyValue(array('value' => $val[$exp_var]), $path);
+        }
+        return '';
+      }
+    }
+    /* meta */
+    if (preg_match('/^\_/', $path) && isset($obj['meta']) && isset($obj['meta'][substr($path, 1)])) {
+      return $obj['meta'][substr($path, 1)];
+    }
+    return '';
+  }
+
+  function render($val, $src_format = '') {
+    if ($src_format) {
+      $mthd = 'render' . $this->camelCase($src_format);
+      if (method_exists($this, $mthd)) {
+        return $this->$mthd($val);
+      }
+      else {
+        return 'No rendering method found for "' . $src_format. '"';
+      }
+    }
+    /* try RDF */
+    return $this->getArraySerialization($val);
+  }
+  
+  function renderObjects($os) {
+    $r = '';
+    foreach ($os as $o) {
+      $r .= $r ? ', ' : '';
+      $r .= $o['value'];
+    }
+    return $r;
+  }
+
+  /*  */
+  
+  function getArraySerialization($v, $context) {
+    $v_type = ARC2::getStructType($v);/* string|array|triples|index */
+    $pf = ARC2::getPreferredFormat();
+    /* string */
+    if ($v_type == 'string') return $v;
+    /* simple array (e.g. from SELECT) */
+    if ($v_type == 'array') {
+      return join(', ', $v);
+      $m = method_exists($this, 'toLegacy' . $pf) ? 'toLegacy' . $pf : 'toLegacyXML';
+    }
+    /* rdf */
+    if (($v_type == 'triples') || ($v_type == 'index')) {
+      $m = method_exists($this, 'to' . $pf) ? 'to' . $pf : ($context == 'query' ? 'toNTriples' : 'toRDFXML');
+    }
+    /* else */
+    return $this->$m($v);
+  }
+
+  /*  */
+
+  function processBlock($block) {
+    if ($this->max_operations && ($this->env['operation_count'] >= $this->max_operations)) return $this->addError('Number of ' . $this->max_operations . ' allowed operations exceeded.');
+    if ($this->return) return 0;
+    $this->env['operation_count']++;
+    $type = $block['type'];
+    $m = 'process' . $this->camelCase($type) . 'Block';
+    if (method_exists($this, $m)) {
+      return $this->$m($block);
+    }
+    return $this->addError('Unsupported block type "' . $type . '"');
+  }
+
+  /*  */
+  
+  function processEndpointDeclBlock($block) {
+    $this->env['endpoint'] = $block['endpoint'];
+    return $this->env;
+  }
+
+  /*  */
+
+  function processQueryBlock($block) {
+    if ($this->max_queries && ($this->env['query_count'] >= $this->max_queries)) return $this->addError('Number of ' . $this->max_queries . ' allowed queries exceeded.');
+    $this->env['query_count']++;
+    $ep_uri = $this->replacePlaceholders($this->env['endpoint'], 'endpoint');
+    /* q */
+    $prologue = 'BASE <' . $block['base']. '>';
+    $q = $this->replacePlaceholders($block['query'], 'query');
+    /* prefixes */
+    $ns = isset($this->a['ns']) ? array_merge($this->a['ns'], $block['prefixes']) : $block['prefixes'];
+    $q = $prologue . "\n" . $this->completeQuery($q, $ns);
+    $this->env['query_log'][] = '(' . $ep_uri . ') ' . $q;
+    if ($store = $this->getStore($ep_uri)) {
+      $sub_r = $this->v('is_remote', '', $store) ? $store->query($q, '', $ep_uri) : $store->query($q);
+      /* ignore socket errors */
+      if (($errs = $this->getErrors()) && preg_match('/socket/', $errs[0])) {
+        $this->warnings[] = $errs[0];
+        $this->errors = array();
+        $sub_r = array();
+      }
+      return $sub_r;
+    }
+    else {
+      return $this->addError("no store (" . $ep_uri . ")");
+    }
+  }
+  
+  function getStore($ep_uri) {
+    /* local store */
+    if ((!$ep_uri || $ep_uri == ARC2::getScriptURI()) && ($this->v('sparqlscript_default_endpoint', '', $this->a) == 'local')) {
+      if (!isset($this->local_store)) $this->local_store = ARC2::getStore($this->a);/* @@todo error checking */
+      return $this->local_store;
+    }
+    elseif ($ep_uri) {
+      ARC2::inc('RemoteStore');
+      $conf = array_merge($this->a, array('remote_store_endpoint' => $ep_uri, 'reader_timeout' => 10));
+      return new ARC2_RemoteStore($conf, $this);
+    }
+    return 0;
+  }
+
+  /*  */
+
+  function processAssignmentBlock($block) {
+    $sub_type = $block['sub_type'];
+    $m = 'process' . $this->camelCase($sub_type) . 'AssignmentBlock';
+    if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"');
+    return $this->$m($block);
+  }
+
+  function processQueryAssignmentBlock($block) {
+    $qr = $this->processQueryBlock($block['query']);
+    if ($this->getErrors() || !isset($qr['query_type'])) return 0;
+    $qt = $qr['query_type'];
+    $vts = array('ask' => 'bool', 'select' => 'rows', 'desribe' => 'doc', 'construct' => 'doc');
+    $r = array(
+      'value_type' => isset($vts[$qt]) ? $vts[$qt] : $qt . ' result',
+      'value' => ($qt == 'select') ? $this->v('rows', array(), $qr['result']) : $qr['result'],
+    );
+    $this->env['vars'][$block['var']['value']] = $r;
+  }
+  
+  function processStringAssignmentBlock($block) {
+    $r = array('value_type' => 'literal', 'value' => $this->replacePlaceholders($block['string']['value']));
+    $this->env['vars'][$block['var']['value']] = $r;
+  }
+  
+  function processVarAssignmentBlock($block) {
+    if (isset($this->env['vars'][$block['var2']['value']])) {
+      $this->env['vars'][$block['var']['value']] = $this->env['vars'][$block['var2']['value']];
+    }
+    else {
+      $this->env['vars'][$block['var']['value']] = array('value_type' => 'undefined', 'value' => '');
+    }
+  }
+  
+  function processPlaceholderAssignmentBlock($block) {
+    $ph_val = $this->getPlaceholderValue($block['placeholder']['value']);
+    $this->env['vars'][$block['var']['value']] = array('value_type' => 'undefined', 'value' => $ph_val);
+  }
+  
+  function processVarMergeAssignmentBlock($block) {
+    $val1 = isset($this->env['vars'][$block['var2']['value']]) ? $this->env['vars'][$block['var2']['value']] : array('value_type' => 'undefined', 'value' => '');
+    $val2 = isset($this->env['vars'][$block['var3']['value']]) ? $this->env['vars'][$block['var3']['value']] : array('value_type' => 'undefined', 'value' => '');
+    if (is_array($val1) && is_array($val2)) {
+      $this->env['vars'][$block['var']['value']] = array('value_type' => $val2['value_type'], 'value' => array_merge($val1['value'], $val2['value']));
+    }
+    elseif (is_numeric($val1) && is_numeric($val2)) {
+      $this->env['vars'][$block['var']['value']] = $val1 + $val2;
+    }
+  }
+  
+  function processFunctionCallAssignmentBlock($block) {
+    $sub_r = $this->processFunctionCallBlock($block['function_call']);
+    if ($this->getErrors()) return 0;
+    $this->env['vars'][$block['var']['value']] = $sub_r;
+  }
+
+  /*  */
+
+  function processReturnBlock($block) {
+    $sub_type = $block['sub_type'];
+    $m = 'process' . $this->camelCase($sub_type) . 'AssignmentBlock';
+    if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"');
+    $sub_r = $this->$m($block);
+    $this->return = 1;
+    return $sub_r;
+  }
+
+  /*  */
+  
+  function processIfblockBlock($block) {
+    if ($this->testCondition($block['condition'])) {
+      $blocks = $block['blocks'];
+    }
+    else {
+      $blocks = $block['else_blocks'];
+    }
+    foreach ($blocks as $block) {
+      $sub_r = $this->processBlock($block);
+      if ($this->getErrors()) return 0;
+    }
+  }
+  
+  function testCondition($cond) {
+    $m = 'test' . $this->camelCase($cond['type']) . 'Condition';
+    if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"');
+    return $this->$m($cond);
+  }
+
+  function testVarCondition($cond) {
+    $r = 0;
+    $vn = $cond['value'];
+    if (isset($this->env['vars'][$vn])) $r = $this->env['vars'][$vn]['value'];
+    $op = $this->v('operator', '', $cond);
+    if ($op == '!') $r = !$r;
+    return $r ? true : false;
+  }
+  
+  function testPlaceholderCondition($cond) {
+    $val = $this->getPlaceholderValue($cond['value']);
+    $r = $val ? true : false;
+    $op = $this->v('operator', '', $cond);
+    if ($op == '!') $r = !$r;
+    return $r;
+  }
+  
+  function testExpressionCondition($cond) {
+    $m = 'test' . $this->camelCase($cond['sub_type']) . 'ExpressionCondition';
+    if (!method_exists($this, $m)) return $this->addError('Unknown method "' . $m . '"');
+    return $this->$m($cond);
+  }
+  
+  function testRelationalExpressionCondition($cond) {
+    $op = $cond['operator'];
+    if ($op == '=') $op = '==';
+    $val1 = $this->getPatternValue($cond['patterns'][0]);
+    $val2 = $this->getPatternValue($cond['patterns'][1]);
+    eval('$result = ($val1 ' . $op . ' $val2) ? 1 : 0;');
+    return $result;
+  }
+
+  function testAndExpressionCondition($cond) {
+    foreach ($cond['patterns'] as $pattern) {
+      if (!$this->testCondition($pattern)) return false;
+    }
+    return true;
+  }
+
+  function getPatternValue($pattern) {
+    $m = 'get' . $this->camelCase($pattern['type']) . 'PatternValue';
+    if (!method_exists($this, $m)) return '';
+    return $this->$m($pattern);
+  }
+
+  function getLiteralPatternValue($pattern) {
+    return $pattern['value'];
+  }
+  
+  function getPlaceholderPatternValue($pattern) {
+    return $this->getPlaceholderValue($pattern['value']);
+  }
+  
+  /*  */
+  
+  function processForblockBlock($block) {
+    $set = $this->v($block['set'], array('value' => array()), $this->env['vars']);
+    $entries = isset($set['value']) ? $set['value'] : $set;
+    $iterator = $block['iterator'];
+    $blocks = $block['blocks'];
+    if (!is_array($entries)) return 0;
+    $rc = count($entries);
+    foreach ($entries as $i => $entry) {
+      $val_type = $this->v('value_type', 'set', $set) . ' entry';
+      $this->env['vars'][$iterator] = array(
+        'value' => $entry,
+        'value_type' => $val_type,
+        'meta' => array(
+          'pos' => $i,
+          'odd_even' => ($i % 2) ? 'even' : 'odd'
+        )
+      );
+      foreach ($blocks as $block) {
+        $this->processBlock($block);
+        if ($this->getErrors()) return 0;
+      }
+    }
+  }
+  
+  /*  */
+
+  function processLiteralBlock($block) {
+    $this->env['output'] .= $this->replacePlaceholders($block['value'], 'output');
+  }
+
+  /*  */
+  
+  function processFunctionCallBlock($block) {
+    $uri = $this->replacePlaceholders($block['uri'], 'function_call');
+    /* built-ins */
+    if (strpos($uri, $this->a['ns']['sps']) === 0) {
+      return $this->processBuiltinFunctionCallBlock($block);
+    }
+    /* remote functions */
+  }
+
+  function processBuiltinFunctionCallBlock($block) {
+    $fnc_uri = $this->replacePlaceholders($block['uri'], 'function_call');
+    $fnc_name = substr($fnc_uri, strlen($this->a['ns']['sps']));
+    if (preg_match('/^(get|post)$/i', $fnc_name, $m)) {
+      return $this->processHTTPCall($block, strtoupper($m[1]));
+    }
+    if ($fnc_name == 'eval') {
+      return $this->processEvalCall($block);
+    }
+  }
+
+  function processEvalCall($block) {
+    if (!$block['args']) return 0;
+    $arg = $block['args'][0];
+    $script = '';
+    if ($arg['type'] == 'placeholder') $script = $this->getPlaceholderValue($arg['value']);
+    if ($arg['type'] == 'literal') $script = $arg['value'];
+    if ($arg['type'] == 'var') $script = $this->getVarValue($arg['value']);
+    //echo "\n" . $script . $arg['type'];
+    $this->processScript($script);
+  }
+  
+  function processHTTPCall($block, $mthd = 'GET') {
+    ARC2::inc('Reader');
+    $reader = new ARC2_Reader($this->a, $this);
+    $url = $this->replacePlaceholders($block['args'][0]['value'], 'function_call');
+    if ($mthd != 'GET') {
+      $reader->setHTTPMethod($mthd);
+      $reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded");
+    }
+    $to = $this->v('remote_call_timeout', 0, $this->a);
+    $reader->activate($url, '', 0, $to);
+    $format = $reader->getFormat();
+    $resp = '';
+    while ($d = $reader->readStream()) {
+      $resp .= $d;
+    }
+    $reader->closeStream();
+    unset($this->reader);
+    return array('value_type' => 'http_response', 'value' => $resp);
+  }
+  
+  /*  */
+  
+  function extractVars($pattern, $input = '') {
+    $vars = array();
+    /* replace PHs, track ()s */
+    $regex = $pattern;
+    $vars = array();
+    if (preg_match_all('/([\?\$]\{([^\}]+)\}|\([^\)]+\))/', $regex, $m)) {
+      $matches = $m[1];
+      $pre_vars = $m[2];
+      foreach ($matches as $i => $match) {
+        $vars[] = $pre_vars[$i];
+        if ($pre_vars[$i]) {/* placeholder */
+          $regex = str_replace($match, '(.+)', $regex);
+        }
+        else {/* parentheses, but may contain placeholders */
+          $sub_regex = $match;
+          while (preg_match('/([\?\$]\{([^\}]+)\})/', $sub_regex, $m)) {
+            $sub_regex = str_replace($m[1], '(.+)', $sub_regex);
+            $vars[] = $m[2];
+          }
+          $regex = str_replace($match, $sub_regex, $regex);
+        }
+      }
+      /* eval regex */
+      if (@preg_match('/' . $regex . '/is', $input, $m)) {
+        $vals = $m;
+      }
+      else {
+        return 0;
+      }
+      for ($i = 0; $i < count($vars); $i++) {
+        if ($vars[$i]) {
+          $this->setVar($vars[$i], isset($vals[$i + 1]) ? $vals[$i + 1] : '');
+        }
+      }
+      return 1;
+    }
+    /* no placeholders */
+    return ($pattern == $input) ? 1 : 0;
+  }
+  
+  /*  */
+  
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_MemStore.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,194 @@
+<?php
+/**
+ * ARC2 Memory Store
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_MemStore extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+    $this->is_mem = 1;
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->data = array();
+  }
+
+  /*  */
+
+  function isSetUp() {
+    return 1;
+  }
+  
+  function setUp() {}
+  
+  /*  */
+  
+  function reset() {
+    $this->data = array();
+  }
+  
+  function drop() {
+    $this->reset();
+  }
+
+  /*  */
+
+  function insert($doc, $g = 'http://localhost/') {
+    $index = $this->v($g, array(), $this->data);
+    $this->data[$g] = ARC2::getMergedIndex($index, $this->toIndex($doc));
+  }
+  
+  /*  */
+  /*  */
+
+  
+  function delete($doc, $g = 'http://localhost/') {
+    $index = $this->v($g, array(), $this->data);
+    $this->data[$g] = ARC2::getCleanedIndex($index, $this->toIndex($doc));
+  }
+
+  function replace($doc, $g, $doc_2) {
+    return array($this->delete($doc, $g), $this->insert($doc_2, $g));
+  }
+  
+  /*  */
+  
+  function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
+    if ($log_query) $this->logQuery($q);
+    ARC2::inc('SPARQLPlusParser');
+    $p = new ARC2_SPARQLPlusParser($this->a, $this);
+    $p->parse($q, $src);
+    $infos = $p->getQueryInfos();
+    $t1 = ARC2::mtime();
+    if (!$errs = $p->getErrors()) {
+      $qt = $infos['query']['type'];
+      $r = array('query_type' => $qt, 'result' => $this->runQuery($q, $qt));
+    }
+    else {
+      $r = array('result' => '');
+    }
+    $t2 = ARC2::mtime();
+    $r['query_time'] = $t2 - $t1;
+    /* query result */
+    if ($result_format == 'raw') {
+      return $r['result'];
+    }
+    if ($result_format == 'rows') {
+      return $this->v('rows', array(), $r['result']);
+    }
+    if ($result_format == 'row') {
+      return $r['result']['rows'] ? $r['result']['rows'][0] : array();
+    }
+    return $r;
+  }
+
+  function runQuery($q, $qt = '') {
+    /* ep */
+    $ep = $this->v('remote_store_endpoint', 0, $this->a);
+    if (!$ep) return false;
+    /* prefixes */
+    $ns = isset($this->a['ns']) ? $this->a['ns'] : array();
+    $added_prefixes = array();
+    $prologue = '';
+    foreach ($ns as $k => $v) {
+      $k = rtrim($k, ':');
+      if (in_array($k, $added_prefixes)) continue;
+      if (preg_match('/(^|\s)' . $k . ':/s', $q) && !preg_match('/PREFIX\s+' . $k . '\:/is', $q)) {
+        $prologue .=  "\n" . 'PREFIX ' . $k . ': <' . $v . '>';
+      }
+      $added_prefixes[] = $k;
+    }
+    $q = $prologue . "\n" . $q;
+    /* http verb */
+    $mthd = in_array($qt, array('load', 'insert', 'delete')) ? 'POST' : 'GET';
+    /* reader */
+    ARC2::inc('Reader');
+    $reader = new ARC2_Reader($this->a, $this);
+    $reader->setAcceptHeader('Accept: application/sparql-results+xml; q=0.9, application/rdf+xml; q=0.9, */*; q=0.1');
+    if ($mthd == 'GET') {
+      $url = $ep;
+      $url .= strpos($ep, '?') ? '&' : '?';
+      $url .= 'query=' . urlencode($q);
+      if ($k = $this->v('store_read_key', '', $this->a)) $url .= '&key=' . urlencode($k);
+    }
+    else {
+      $url = $ep;
+      $reader->setHTTPMethod($mthd);
+      $reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded");
+      $suffix = ($k = $this->v('store_write_key', '', $this->a)) ? '&key=' . rawurlencode($k) : '';
+      $reader->setMessageBody('query=' . rawurlencode($q) . $suffix);
+    }
+    $to = $this->v('remote_store_timeout', 0, $this->a);
+    $reader->activate($url, '', 0, $to);
+    $format = $reader->getFormat();
+    $resp = '';
+    while ($d = $reader->readStream()) {
+      $resp .= $d;
+    }
+    $reader->closeStream();
+    $ers = $reader->getErrors();
+    unset($this->reader);
+    if ($ers) return array('errors' => $ers);
+		$mappings = array('rdfxml' => 'RDFXML', 'sparqlxml' => 'SPARQLXMLResult', 'turtle' => 'Turtle');
+    if (!$format || !isset($mappings[$format])) {
+      return $resp;
+      //return $this->addError('No parser available for "' . $format . '" SPARQL result');
+    }
+    /* format parser */
+    $suffix = $mappings[$format] . 'Parser';
+    ARC2::inc($suffix);
+    $cls = 'ARC2_' . $suffix;
+    $parser = new $cls($this->a, $this);
+    $parser->parse($ep, $resp);
+    /* ask|load|insert|delete */
+    if (in_array($qt, array('ask', 'load', 'insert', 'delete'))) {
+      $bid = $parser->getBooleanInsertedDeleted();
+      switch ($qt) {
+        case 'ask': return $bid['boolean'];
+        default: return $bid;
+      }
+    }
+    /* select */
+    if (($qt == 'select') && !method_exists($parser, 'getRows')) return $resp;
+    if ($qt == 'select') return array('rows' => $parser->getRows(), 'variables' => $parser->getVariables());
+    /* any other */
+    return $parser->getSimpleIndex(0);
+  }
+  
+  /*  */
+  
+  function optimizeTables() {}
+  
+  /*  */
+
+  function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
+    if (!isset($this->resource_labels)) $this->resource_labels = array();
+    if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
+    if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
+    $r = '';
+    if (preg_match('/^\_\:/', $res)) {
+      return $unnamed_label;
+    }
+    $row = $this->query('SELECT ?o WHERE { <' . $res . '> ?p ?o . FILTER(REGEX(str(?p), "(label|name)$", "i"))}', 'row');
+    if ($row) {
+      $r = $row['o'];
+    }
+    else {
+      $r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
+      $r = str_replace('_', ' ', $r);
+      $r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
+    }
+    $this->resource_labels[$res] = $r;
+    return $r;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_RemoteStore.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,204 @@
+<?php
+/**
+ * ARC2 Remote RDF Store
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_RemoteStore extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+    $this->is_remote = 1;
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+
+  function isSetUp() {
+    return 1;
+  }
+  
+  function setUp() {}
+
+  function killDBProcesses() {}
+  
+  /*  */
+  
+  function reset() {}
+  
+  function drop() {}
+  
+  function insert($doc, $g, $keep_bnode_ids = 0) {
+    return $this->query('INSERT INTO <' . $g . '> { ' . $this->toNTriples($doc, '', 1) . ' }');
+  }
+  
+  function delete($doc, $g) {
+    if (!$doc) {
+      return $this->query('DELETE FROM <' . $g . '>');
+    }
+    else {
+      return $this->query('DELETE FROM <' . $g . '> { ' . $this->toNTriples($doc, '', 1) . ' }');
+    }
+  }
+  
+  function replace($doc, $g, $doc_2) {
+    return array($this->delete($doc, $g), $this->insert($doc_2, $g));
+  }
+  
+  /*  */
+  
+  function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
+    if ($log_query) $this->logQuery($q);
+    ARC2::inc('SPARQLPlusParser');
+    $p = new ARC2_SPARQLPlusParser($this->a, $this);
+    $p->parse($q, $src);
+    $infos = $p->getQueryInfos();
+    $t1 = ARC2::mtime();
+    if (!$errs = $p->getErrors()) {
+      $qt = $infos['query']['type'];
+      $r = array('query_type' => $qt, 'result' => $this->runQuery($q, $qt, $infos));
+    }
+    else {
+      $r = array('result' => '');
+    }
+    $t2 = ARC2::mtime();
+    $r['query_time'] = $t2 - $t1;
+    /* query result */
+    if ($result_format == 'raw') {
+      return $r['result'];
+    }
+    if ($result_format == 'rows') {
+      return $this->v('rows', array(), $r['result']);
+    }
+    if ($result_format == 'row') {
+      if (!isset($r['result']['rows'])) return array();
+      return $r['result']['rows'] ? $r['result']['rows'][0] : array();
+    }
+    return $r;
+  }
+
+  function runQuery($q, $qt = '', $infos = '') {
+    /* ep */
+    $ep = $this->v('remote_store_endpoint', 0, $this->a);
+    if (!$ep) return false;
+    /* prefixes */
+    $q = $this->completeQuery($q);
+    /* custom handling */
+    $mthd = 'run' . $this->camelCase($qt) . 'Query';
+    if (method_exists($this, $mthd)) {
+      return $this->$mthd($q, $infos);
+    }
+    /* http verb */
+    $mthd = in_array($qt, array('load', 'insert', 'delete')) ? 'POST' : 'GET';
+    /* reader */
+    ARC2::inc('Reader');
+    $reader = new ARC2_Reader($this->a, $this);
+    $reader->setAcceptHeader('Accept: application/sparql-results+xml; q=0.9, application/rdf+xml; q=0.9, */*; q=0.1');
+    if ($mthd == 'GET') {
+      $url = $ep;
+      $url .= strpos($ep, '?') ? '&' : '?';
+      $url .= 'query=' . urlencode($q);
+      if ($k = $this->v('store_read_key', '', $this->a)) $url .= '&key=' . urlencode($k);
+    }
+    else {
+      $url = $ep;
+      $reader->setHTTPMethod($mthd);
+      $reader->setCustomHeaders("Content-Type: application/x-www-form-urlencoded");
+      $suffix = ($k = $this->v('store_write_key', '', $this->a)) ? '&key=' . rawurlencode($k) : '';
+      $reader->setMessageBody('query=' . rawurlencode($q) . $suffix);
+    }
+    $to = $this->v('remote_store_timeout', 0, $this->a);
+    $reader->activate($url, '', 0, $to);
+    $format = $reader->getFormat();
+    $resp = '';
+    while ($d = $reader->readStream()) {
+      $resp .= $this->toUTF8($d);
+    }
+    $reader->closeStream();
+    $ers = $reader->getErrors();
+    $this->a['reader_auth_infos'] = $reader->getAuthInfos();
+    unset($this->reader);
+    if ($ers) return array('errors' => $ers);
+    $mappings = array('rdfxml' => 'RDFXML', 'sparqlxml' => 'SPARQLXMLResult', 'turtle' => 'Turtle');
+    if (!$format || !isset($mappings[$format])) {
+      return $resp;
+      //return $this->addError('No parser available for "' . $format . '" SPARQL result');
+    }
+    /* format parser */
+    $suffix = $mappings[$format] . 'Parser';
+    ARC2::inc($suffix);
+    $cls = 'ARC2_' . $suffix;
+    $parser = new $cls($this->a, $this);
+    $parser->parse($ep, $resp);
+    /* ask|load|insert|delete */
+    if (in_array($qt, array('ask', 'load', 'insert', 'delete'))) {
+      $bid = $parser->getBooleanInsertedDeleted();
+      if ($qt == 'ask') {
+        $r = $bid['boolean'];
+      }
+      else {
+        $r = $bid;
+      }
+    }
+    /* select */
+    elseif (($qt == 'select') && !method_exists($parser, 'getRows')) {
+      $r = $resp;
+    }
+    elseif ($qt == 'select') {
+      $r = array('rows' => $parser->getRows(), 'variables' => $parser->getVariables());
+    }
+    /* any other */
+    else {
+      $r = $parser->getSimpleIndex(0);
+    }
+    unset($parser);
+    return $r;
+  }
+  
+  /*  */
+  
+  function optimizeTables() {}
+  
+  /*  */
+
+  function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
+    if (!isset($this->resource_labels)) $this->resource_labels = array();
+    if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
+    if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
+    $r = '';
+    if (preg_match('/^\_\:/', $res)) {
+      return $unnamed_label;
+    }
+    $row = $this->query('SELECT ?o WHERE { <' . $res . '> ?p ?o . FILTER(REGEX(str(?p), "(label|name)$", "i"))}', 'row');
+    if ($row) {
+      $r = $row['o'];
+    }
+    else {
+      $r = preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
+      $r = str_replace('_', ' ', $r);
+      $r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
+    }
+    $this->resource_labels[$res] = $r;
+    return $r;
+  }
+  
+  function getDomains($p) {
+    $r = array();
+    foreach($this->query('SELECT DISTINCT ?type WHERE {?s <' . $p . '> ?o ; a ?type . }', 'rows') as $row) {
+      $r[] = $row['type'];
+    }
+    return $r;
+  }
+
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_Store.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,711 @@
+<?php
+/**
+ * ARC2 RDF Store
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+*/
+
+ARC2::inc('Class');
+
+class ARC2_Store extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->table_lock = 0;
+    $this->triggers = $this->v('store_triggers', array(), $this->a);
+    $this->queue_queries = $this->v('store_queue_queries', 0, $this->a);
+    $this->is_win = (strtolower(substr(PHP_OS, 0, 3)) == 'win') ? true : false;
+    $this->max_split_tables = $this->v('store_max_split_tables', 10, $this->a);
+    $this->split_predicates = $this->v('store_split_predicates', array(), $this->a);
+  }
+
+  /*  */
+  
+  function getName() {
+    return $this->v('store_name', 'arc', $this->a);
+  }
+
+  function getTablePrefix() {
+    if (!isset($this->tbl_prefix)) {
+      $r = $this->v('db_table_prefix', '', $this->a);
+      $r .= $r ? '_' : '';
+      $r .= $this->getName() . '_';
+      $this->tbl_prefix = $r;
+    }
+    return $this->tbl_prefix;;
+  }
+
+  /*  */
+  
+  function createDBCon() {
+    foreach (array('db_host' => 'localhost', 'db_user' => '', 'db_pwd' => '', 'db_name' => '') as $k => $v) {
+      $this->a[$k] = $this->v($k, $v, $this->a);
+    }
+    if (!$db_con = mysql_connect($this->a['db_host'], $this->a['db_user'], $this->a['db_pwd'])) {
+      return $this->addError(mysql_error());
+    }
+    $this->a['db_con'] = $db_con;
+    if (!mysql_select_db($this->a['db_name'], $db_con)) {
+      $fixed = 0;
+      /* try to create it */
+      if ($this->a['db_name']) {
+        $this->queryDB("
+          CREATE DATABASE IF NOT EXISTS " . $this->a['db_name'] . " 
+          DEFAULT CHARACTER SET utf8
+          DEFAULT COLLATE utf8_general_ci
+          ", $db_con, 1
+        );
+        if (mysql_select_db($this->a['db_name'], $db_con)) {
+          $this->queryDB("SET NAMES 'utf8'", $db_con);
+          $fixed = 1;
+        }
+      }
+      if (!$fixed) {
+        return $this->addError(mysql_error($db_con));
+      }
+    }
+    if (preg_match('/^utf8/', $this->getCollation())) {
+      $this->queryDB("SET NAMES 'utf8'", $db_con);
+    }
+	// This is RDF, we may need many JOINs...
+	$this->queryDB("SET SESSION SQL_BIG_SELECTS=1", $db_con);
+    return true;
+  }
+  
+  function getDBCon($force = 0) {
+    if ($force || !isset($this->a['db_con'])) {
+      if (!$this->createDBCon()) {
+        return false;
+      }
+    }
+    if (!$force && !@mysql_thread_id($this->a['db_con'])) return $this->getDBCon(1);
+    return $this->a['db_con'];
+  }
+  
+  function closeDBCon() {
+    if ($this->v('db_con', false, $this->a)) {
+      @mysql_close($this->a['db_con']);
+    }
+    unset($this->a['db_con']);
+  }
+  
+  function getDBVersion() {
+    if (!$this->v('db_version')) {
+      $this->db_version = preg_match("/^([0-9]+)\.([0-9]+)\.([0-9]+)/", mysql_get_server_info($this->getDBCon()), $m) ? sprintf("%02d-%02d-%02d", $m[1], $m[2], $m[3])  : '00-00-00';
+    }
+    return $this->db_version;
+  }
+  
+  /*  */
+  
+  function getCollation() {
+    $rs = $this->queryDB('SHOW TABLE STATUS LIKE "' . $this->getTablePrefix(). 'setting"', $this->getDBCon());
+    return ($rs && ($row = mysql_fetch_array($rs)) && isset($row['Collation'])) ? $row['Collation'] : '';
+  }
+
+  function getColumnType() {
+    if (!$this->v('column_type')) {
+      $tbl = $this->getTablePrefix() . 'g2t';
+      $rs = $this->queryDB('SHOW COLUMNS FROM ' . $tbl . ' LIKE "t"', $this->getDBCon());
+      $row = $rs ? mysql_fetch_array($rs) : array('Type' => 'mediumint');
+      $this->column_type = preg_match('/mediumint/', $row['Type']) ? 'mediumint' : 'int';
+    }
+    return $this->column_type;
+  }
+
+  /*  */
+
+  function hasHashColumn($tbl) {
+    $var_name = 'has_hash_column_' . $tbl;
+    if (!isset($this->$var_name)) {
+      $tbl = $this->getTablePrefix() . $tbl;
+      $rs = $this->queryDB('SHOW COLUMNS FROM ' . $tbl . ' LIKE "val_hash"', $this->getDBCon());
+      $this->$var_name = ($rs && mysql_fetch_array($rs));
+    }
+    return $this->$var_name;
+  }
+
+  /*  */
+
+  function hasFulltextIndex() {
+    if (!isset($this->has_fulltext_index)) {
+      $this->has_fulltext_index = 0;
+      $tbl = $this->getTablePrefix() . 'o2val';
+      $rs = $this->queryDB('SHOW INDEX FROM ' . $tbl, $this->getDBCon());
+      while ($row = mysql_fetch_array($rs)) {
+        if ($row['Column_name'] != 'val') continue;
+        if ($row['Index_type'] != 'FULLTEXT') continue;
+        $this->has_fulltext_index = 1;
+        break;
+      }
+    }
+    return $this->has_fulltext_index;
+  }
+
+  function enableFulltextSearch() {
+    if ($this->hasFulltextIndex()) return 1;
+    $tbl = $this->getTablePrefix() . 'o2val';
+    $this->queryDB('CREATE FULLTEXT INDEX vft ON ' . $tbl . '(val(128))', $this->getDBCon(), 1);
+  }
+
+  function disableFulltextSearch() {
+    if (!$this->hasFulltextIndex()) return 1;
+    $tbl = $this->getTablePrefix() . 'o2val';
+    $this->queryDB('DROP INDEX vft ON ' . $tbl, $this->getDBCon());
+  }
+
+  /*  */
+
+  function countDBProcesses() {
+    return ($rs = $this->queryDB('SHOW PROCESSLIST', $this->getDBCon())) ? mysql_num_rows($rs) : 0;
+  }
+
+  function killDBProcesses($needle = '', $runtime = 30) {
+    $dbcon = $this->getDBCon();
+    /* make sure needle is sql */
+    if (preg_match('/\?.+ WHERE/i', $needle, $m)) {
+      $needle = $this->query($needle, 'sql');
+    }
+    $rs = $this->queryDB('SHOW FULL PROCESSLIST', $dbcon);
+    $ref_tbl = $this->getTablePrefix() . 'triple';
+    while ($row = mysql_fetch_array($rs)) {
+      if ($row['Time'] < $runtime) continue;
+      if (!preg_match('/^\s*(INSERT|SELECT) /s', $row['Info'])) continue; /* only basic queries */
+      if (!strpos($row['Info'], $ref_tbl . ' ')) continue; /* only from this store */
+      $kill = 0;
+      if ($needle && (strpos($row['Info'], $needle) !== false)) $kill = 1;
+      if (!$needle) $kill = 1;
+      if (!$kill) continue;
+      $this->queryDB('KILL ' . $row['Id'], $dbcon);
+    }
+  }
+  
+  /*  */
+
+  function getTables() {
+    return array('triple', 'g2t', 'id2val', 's2val', 'o2val', 'setting');
+  }  
+  
+  /*  */
+
+  function isSetUp() {
+    if (($con = $this->getDBCon())) {
+      $tbl = $this->getTablePrefix() . 'setting';
+      return $this->queryDB("SELECT 1 FROM " . $tbl . " LIMIT 0", $con) ? 1 : 0;
+    }
+  }
+  
+  function setUp($force = 0) {
+    if (($force || !$this->isSetUp()) && ($con = $this->getDBCon())) {
+      if ($this->getDBVersion() < '04-00-04') {
+        /* UPDATE + JOINs */
+        return $this->addError('MySQL version not supported. ARC requires version 4.0.4 or higher.');
+      }
+      ARC2::inc('StoreTableManager');
+      $mgr = new ARC2_StoreTableManager($this->a, $this);
+      $mgr->createTables();
+    }
+  }
+
+  function extendColumns() {
+    ARC2::inc('StoreTableManager');
+    $mgr = new ARC2_StoreTableManager($this->a, $this);
+    $mgr->extendColumns();
+    $this->column_type = 'int';
+  }
+
+  function splitTables() {
+    ARC2::inc('StoreTableManager');
+    $mgr = new ARC2_StoreTableManager($this->a, $this);
+    $mgr->splitTables();
+  }
+  
+  /*  */
+  
+  function hasSetting($k) {
+    $tbl = $this->getTablePrefix() . 'setting';
+    $sql = "SELECT val FROM " . $tbl . " WHERE k = '" .md5($k). "'";
+    $rs = $this->queryDB($sql, $this->getDBCon());
+    return ($rs && ($row = mysql_fetch_array($rs))) ? 1 : 0;
+  }
+  
+  function getSetting($k, $default = 0) {
+    $tbl = $this->getTablePrefix() . 'setting';
+    $sql = "SELECT val FROM " . $tbl . " WHERE k = '" .md5($k). "'";
+    $rs = $this->queryDB($sql, $this->getDBCon());
+    if ($rs && ($row = mysql_fetch_array($rs))) {
+      return unserialize($row['val']);
+    }
+    return $default;
+  }
+  
+  function setSetting($k, $v) {
+    $con = $this->getDBCon();
+    $tbl = $this->getTablePrefix() . 'setting';
+    if ($this->hasSetting($k)) {
+      $sql = "UPDATE " .$tbl . " SET val = '" . mysql_real_escape_string(serialize($v), $con) . "' WHERE k = '" . md5($k) . "'";
+    }
+    else {
+      $sql = "INSERT INTO " . $tbl . " (k, val) VALUES ('" . md5($k) . "', '" . mysql_real_escape_string(serialize($v), $con) . "')";
+    }
+    return $this->queryDB($sql, $con);
+  }
+  
+  function removeSetting($k) {
+    $tbl = $this->getTablePrefix() . 'setting';
+    return $this->queryDB("DELETE FROM " . $tbl . " WHERE k = '" . md5($k) . "'", $this->getDBCon());
+  }
+  
+  function getQueueTicket() {
+    if (!$this->queue_queries) return 1;
+    $t = 'ticket_' . substr(md5(uniqid(rand())), 0, 10);
+    $con = $this->getDBCon();
+    /* lock */
+    $rs = $this->queryDB('LOCK TABLES ' . $this->getTablePrefix() . 'setting WRITE', $con);
+    /* queue */
+    $queue = $this->getSetting('query_queue', array());
+    $queue[] = $t;
+    $this->setSetting('query_queue', $queue);
+    $this->queryDB('UNLOCK TABLES', $con);
+    /* loop */
+    $lc = 0;
+    $queue = $this->getSetting('query_queue', array());
+    while ($queue && ($queue[0] != $t) && ($lc < 30)) {
+      if ($this->is_win) {
+        sleep(1);
+        $lc++;
+      }
+      else {
+         usleep(100000);
+         $lc += 0.1;
+      }
+      $queue = $this->getSetting('query_queue', array());
+    }
+    return ($lc < 30) ? $t : 0;
+  }
+  
+  function removeQueueTicket($t) {
+    if (!$this->queue_queries) return 1;
+    $con = $this->getDBCon();
+    /* lock */
+    $this->queryDB('LOCK TABLES ' . $this->getTablePrefix() . 'setting WRITE', $con);
+    /* queue */
+    $vals = $this->getSetting('query_queue', array());
+    $pos = array_search($t, $vals);
+    $queue = ($pos < (count($vals) - 1)) ? array_slice($vals, $pos + 1) : array();
+    $this->setSetting('query_queue', $queue);
+    $this->queryDB('UNLOCK TABLES', $con);
+  }
+  
+  /*  */
+
+  function reset($keep_settings = 0) {
+    $con = $this->getDBCon();
+    $tbls = $this->getTables();
+    $prefix = $this->getTablePrefix();
+    /* remove split tables */
+    $ps = $this->getSetting('split_predicates', array());
+    foreach ($ps as $p) {
+      $tbl = 'triple_' . abs(crc32($p));
+      $this->queryDB('DROP TABLE ' . $prefix . $tbl, $con);
+    }
+    $this->removeSetting('split_predicates');
+    /* truncate tables */
+    foreach ($tbls as $tbl) {
+      if ($keep_settings && ($tbl == 'setting')) {
+        continue;
+      }
+      $this->queryDB('TRUNCATE ' . $prefix . $tbl, $con);
+    }
+  }
+  
+  function drop() {
+    $con = $this->getDBCon();
+    $tbls = $this->getTables();
+    $prefix = $this->getTablePrefix();
+    foreach ($tbls as $tbl) {
+      $this->queryDB('DROP TABLE ' . $prefix . $tbl, $con);
+    }
+  }
+  
+  function insert($doc, $g, $keep_bnode_ids = 0) {
+    $doc = is_array($doc) ? $this->toTurtle($doc) : $doc;
+    $infos = array('query' => array('url' => $g, 'target_graph' => $g));
+    ARC2::inc('StoreLoadQueryHandler');
+    $h = new ARC2_StoreLoadQueryHandler($this->a, $this);
+    $r = $h->runQuery($infos, $doc, $keep_bnode_ids);
+    $this->processTriggers('insert', $infos);
+    return $r;
+  }
+  
+  function delete($doc, $g) {
+    if (!$doc) {
+      $infos = array('query' => array('target_graphs' => array($g)));
+      ARC2::inc('StoreDeleteQueryHandler');
+      $h = new ARC2_StoreDeleteQueryHandler($this->a, $this);
+      $r = $h->runQuery($infos);
+      $this->processTriggers('delete', $infos);
+      return $r;
+    }
+  }
+  
+  function replace($doc, $g, $doc_2) {
+    return array($this->delete($doc, $g), $this->insert($doc_2, $g));
+  }
+  
+  function dump() {
+    ARC2::inc('StoreDumper');
+    $d = new ARC2_StoreDumper($this->a, $this);
+    $d->dumpSPOG();
+  }
+  
+  function createBackup($path, $q = '') {
+    ARC2::inc('StoreDumper');
+    $d = new ARC2_StoreDumper($this->a, $this);
+    $d->saveSPOG($path, $q);
+  }
+  
+  function renameTo($name) {
+    $con = $this->getDBCon();
+    $tbls = $this->getTables();
+    $old_prefix = $this->getTablePrefix();
+    $new_prefix = $this->v('db_table_prefix', '', $this->a);
+    $new_prefix .= $new_prefix ? '_' : '';
+    $new_prefix .= $name . '_';
+    foreach ($tbls as $tbl) {
+      $rs = $this->queryDB('RENAME TABLE ' . $old_prefix . $tbl .' TO ' . $new_prefix . $tbl, $con);
+      $err = mysql_error($con);
+      if ($err) {
+        return $this->addError($err);
+      }
+    }
+    $this->a['store_name'] = $name;
+    unset($this->tbl_prefix);
+  }
+  
+  function replicateTo($name) {
+    $conf = array_merge($this->a, array('store_name' => $name));
+    $new_store = ARC2::getStore($conf);
+    $new_store->setUp();
+    $new_store->reset();
+    $con = $this->getDBCon();
+    $tbls = $this->getTables();
+    $old_prefix = $this->getTablePrefix();
+    $new_prefix = $new_store->getTablePrefix();
+    foreach ($tbls as $tbl) {
+      $rs = $this->queryDB('INSERT IGNORE INTO ' . $new_prefix . $tbl .' SELECT * FROM ' . $old_prefix . $tbl, $con);
+      $err = mysql_error($con);
+      if ($err) {
+        return $this->addError($err);
+      }
+    }
+    return $new_store->query('SELECT COUNT(*) AS t_count WHERE { ?s ?p ?o}', 'row');
+  }
+  
+  /*  */
+  
+  function query($q, $result_format = '', $src = '', $keep_bnode_ids = 0, $log_query = 0) {
+    if ($log_query) $this->logQuery($q);
+    $con = $this->getDBCon();
+    if (preg_match('/^dump/i', $q)) {
+      $infos = array('query' => array('type' => 'dump'));
+    }
+    else {
+      ARC2::inc('SPARQLPlusParser');
+      $p = new ARC2_SPARQLPlusParser($this->a, $this);
+      $p->parse($q, $src);
+      $infos = $p->getQueryInfos();
+    }
+    if ($result_format == 'infos') return $infos;
+    $infos['result_format'] = $result_format;
+    if (!isset($p) || !$p->getErrors()) {
+      $qt = $infos['query']['type'];
+      if (!in_array($qt, array('select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'))) {
+        return $this->addError('Unsupported query type "'.$qt.'"');
+      }
+      $t1 = ARC2::mtime();
+      $r = array('query_type' => $qt, 'result' => $this->runQuery($infos, $qt, $keep_bnode_ids, $q));
+      $t2 = ARC2::mtime();
+      $r['query_time'] = $t2 - $t1;
+      /* query result */
+      if ($result_format == 'raw') {
+        return $r['result'];
+      }
+      if ($result_format == 'rows') {
+        return $r['result']['rows'] ? $r['result']['rows'] : array();
+      }
+      if ($result_format == 'row') {
+        return $r['result']['rows'] ? $r['result']['rows'][0] : array();
+      }
+      return $r;
+    }
+    return 0;
+  }
+
+  function runQuery($infos, $type, $keep_bnode_ids = 0, $q = '') {
+    ARC2::inc('Store' . ucfirst($type) . 'QueryHandler');
+    $cls = 'ARC2_Store' . ucfirst($type) . 'QueryHandler';
+    $h = new $cls($this->a, $this);
+    $ticket = 1;
+    $r = array();
+    if ($q && ($type == 'select')) $ticket = $this->getQueueTicket($q);
+    if ($ticket) {
+      if ($type == 'load') {/* the LoadQH supports raw data as 2nd parameter */
+        $r = $h->runQuery($infos, '', $keep_bnode_ids);
+      }
+      else {
+        $r = $h->runQuery($infos, $keep_bnode_ids);
+      }
+    }
+    if ($q && ($type == 'select')) $this->removeQueueTicket($ticket);
+    $trigger_r = $this->processTriggers($type, $infos);
+    return $r;
+  }
+  
+  function processTriggers($type, $infos) {
+    $r = array();
+    $trigger_defs = $this->triggers;
+    $this->triggers = array();
+    $triggers = $this->v($type, array(), $trigger_defs);
+    if ($triggers) {
+      $r['trigger_results'] = array();
+      $triggers = is_array($triggers) ? $triggers : array($triggers);
+      $trigger_inc_path = $this->v('store_triggers_path', '', $this->a);
+      foreach ($triggers as $trigger) {
+        $trigger .= !preg_match('/Trigger$/', $trigger) ? 'Trigger' : '';
+        if (ARC2::inc(ucfirst($trigger), $trigger_inc_path)) {
+          $cls = 'ARC2_' . ucfirst($trigger);
+          $config = array_merge($this->a, array('query_infos' => $infos));
+          $trigger_obj = new $cls($config, $this);
+          if (method_exists($trigger_obj, 'go')) {
+            $r['trigger_results'][] = $trigger_obj->go();
+          }
+        }
+      }
+    }
+    $this->triggers = $trigger_defs;
+    return $r;
+  }
+  
+  /*  */
+
+  function getValueHash($val) {
+    return abs(crc32($val));
+  }
+
+  function getTermID($val, $term = '') {
+    /* mem cache */
+    if (!isset($this->term_id_cache) || (count(array_keys($this->term_id_cache)) > 100)) {
+      $this->term_id_cache = array();
+    }
+    if (!isset($this->term_id_cache[$term])) {
+      $this->term_id_cache[$term] = array();
+    }
+    $tbl = preg_match('/^(s|o)$/', $term) ? $term . '2val' : 'id2val';
+    /* cached? */
+    if ((strlen($val) < 100) && isset($this->term_id_cache[$term][$val])) {
+      return $this->term_id_cache[$term][$val];
+    }
+    $con = $this->getDBCon();
+    $r = 0;
+    /* via hash */
+    if (preg_match('/^(s2val|o2val)$/', $tbl) && $this->hasHashColumn($tbl)) {
+      $sql = "SELECT id, val FROM " . $this->getTablePrefix() . $tbl . " WHERE val_hash = '" . $this->getValueHash($val) . "'";
+      if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs)) {
+        while ($row = mysql_fetch_array($rs)) {
+          if ($row['val'] == $val) {
+            $r = $row['id'];
+            break;
+          }
+        }
+      }
+    }
+    /* exact match */
+    else {
+      $sql = "SELECT id FROM " . $this->getTablePrefix() . $tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "' LIMIT 1";
+      if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
+        $r = $row['id'];
+      }
+    }
+    if ($r && (strlen($val) < 100)) {
+      $this->term_id_cache[$term][$val] = $r;
+    }
+    return $r;
+  }
+
+  function getIDValue($id, $term = '') {
+    $tbl = preg_match('/^(s|o)$/', $term) ? $term . '2val' : 'id2val';
+    $con = $this->getDBCon();
+    $sql = "SELECT val FROM " . $this->getTablePrefix() . $tbl . " WHERE id = " . mysql_real_escape_string($id, $con) . " LIMIT 1";
+    if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
+      return $row['val'];
+    }
+    return 0;
+  }
+
+  /*  */
+  
+  function getLock($t_out = 10, $t_out_init = '') {
+    if (!$t_out_init) $t_out_init = $t_out;
+    $con = $this->getDBCon();
+    $l_name = $this->a['db_name'] . '.' . $this->getTablePrefix() . '.write_lock';
+    $rs = $this->queryDB('SELECT IS_FREE_LOCK("' . $l_name. '") AS success', $con);
+    if ($rs) {
+      $row = mysql_fetch_array($rs);
+      if (!$row['success']) {
+        if ($t_out) {
+          sleep(1);
+          return $this->getLock($t_out - 1, $t_out_init);
+        }
+      }
+      else {
+        $rs = $this->queryDB('SELECT GET_LOCK("' . $l_name. '", ' . $t_out_init. ') AS success', $con);
+        if ($rs) {
+          $row = mysql_fetch_array($rs);
+          return $row['success'];
+        }
+      }
+    }
+    return 0;   
+  }
+  
+  function releaseLock() {
+    $con = $this->getDBCon();
+    return $this->queryDB('DO RELEASE_LOCK("' . $this->a['db_name'] . '.' . $this->getTablePrefix() . '.write_lock")', $con);
+  }
+
+  /*  */
+
+  function processTables($level = 2, $operation = 'optimize') {/* 1: triple + g2t, 2: triple + *2val, 3: all tables */
+    $con = $this->getDBCon();
+    $pre = $this->getTablePrefix();
+    $tbls = $this->getTables();
+    $sql = '';
+    foreach ($tbls as $tbl) {
+      if (($level < 3) && preg_match('/(backup|setting)$/', $tbl)) continue;
+      if (($level < 2) && preg_match('/(val)$/', $tbl)) continue;
+      $sql .= $sql ? ', ' : strtoupper($operation) . ' TABLE ';
+      $sql .= $pre . $tbl;
+    }
+    $this->queryDB($sql, $con);
+    $err = mysql_error($con);
+    if ($err) {
+      $this->addError($err . ' in ' . $sql);
+    }
+  }
+
+  function optimizeTables($level = 2) {
+    if ($this->v('ignore_optimization')) return 1;
+    return $this->processTables($level, 'optimize');
+  }
+
+  function checkTables($level = 2) {
+    return $this->processTables($level, 'check');
+  }
+
+  function repairTables($level = 2) {
+    return $this->processTables($level, 'repair');
+  }
+
+  /*  */
+
+  function changeNamespaceURI($old_uri, $new_uri) {
+    ARC2::inc('StoreHelper');
+    $c = new ARC2_StoreHelper($this->a, $this);
+    return $c->changeNamespaceURI($old_uri, $new_uri);
+  }
+  
+  /*  */
+  
+  function getResourceLabel($res, $unnamed_label = 'An unnamed resource') {
+    if (!isset($this->resource_labels)) $this->resource_labels = array();
+    if (isset($this->resource_labels[$res])) return $this->resource_labels[$res];
+    if (!preg_match('/^[a-z0-9\_]+\:[^\s]+$/si', $res)) return $res;/* literal */
+    $ps = $this->getLabelProps();
+    if ($this->getSetting('store_label_properties', '-') != md5(serialize($ps))) {
+      $this->inferLabelProps($ps);
+    }
+    //$sub_q .= $sub_q ? ' || ' : '';
+    //$sub_q .= 'REGEX(str(?p), "(last_name|name|fn|title|label)$", "i")';
+    $q = 'SELECT ?label WHERE { <' . $res . '> ?p ?label . ?p a <http://semsol.org/ns/arc#LabelProperty> } LIMIT 3';
+    $r = '';
+    $rows = $this->query($q, 'rows');
+    foreach ($rows as $row) {
+      $r = strlen($row['label']) > strlen($r) ? $row['label'] : $r;
+    }
+    if (!$r && preg_match('/^\_\:/', $res)) {
+      return $unnamed_label;
+    }
+    $r = $r ? $r : preg_replace("/^(.*[\/\#])([^\/\#]+)$/", '\\2', str_replace('#self', '', $res));
+    $r = str_replace('_', ' ', $r);
+    $r = preg_replace('/([a-z])([A-Z])/e', '"\\1 " . strtolower("\\2")', $r);
+    $this->resource_labels[$res] = $r;
+    return $r;
+  }
+  
+  function getLabelProps() {
+    return array_merge(
+      $this->v('rdf_label_properties' , array(), $this->a),
+      array(
+        'http://www.w3.org/2000/01/rdf-schema#label',
+        'http://xmlns.com/foaf/0.1/name',
+        'http://purl.org/dc/elements/1.1/title',
+        'http://purl.org/rss/1.0/title',
+        'http://www.w3.org/2004/02/skos/core#prefLabel',
+        'http://xmlns.com/foaf/0.1/nick',
+      )
+    );
+  }
+  
+  function inferLabelProps($ps) {
+    $this->query('DELETE FROM <label-properties>');
+    $sub_q = '';
+    foreach ($ps as $p) {
+      $sub_q .= ' <' . $p . '> a <http://semsol.org/ns/arc#LabelProperty> . ';
+    }
+    $this->query('INSERT INTO <label-properties> { ' . $sub_q. ' }');
+    $this->setSetting('store_label_properties', md5(serialize($ps)));
+  }
+  
+  /*  */
+
+  function getResourcePredicates($res) {
+    $r = array();
+    $rows = $this->query('SELECT DISTINCT ?p WHERE { <' . $res . '> ?p ?o . }', 'rows');
+    foreach ($rows as $row) {
+      $r[$row['p']] = array();
+    }
+    return $r;
+  }
+  
+  function getDomains($p) {
+    $r = array();
+    foreach($this->query('SELECT DISTINCT ?type WHERE {?s <' . $p . '> ?o ; a ?type . }', 'rows') as $row) {
+      $r[] = $row['type'];
+    }
+    return $r;
+  }
+
+  function getPredicateRange($p) {
+    $row = $this->query('SELECT ?val WHERE {<' . $p . '> rdfs:range ?val . } LIMIT 1', 'row');
+    return $row ? $row['val'] : '';
+  }
+
+  /*  */
+  
+  function logQuery($q) {
+    $fp = @fopen("arc_query_log.txt", "a");
+    @fwrite($fp, date('Y-m-d\TH:i:s\Z', time()) . ' : ' . $q . '' . "\n\n");
+    @fclose($fp);
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreAskQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,53 @@
+<?php
+/**
+ * ARC2 SPARQL ASK query handler
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('StoreSelectQueryHandler');
+
+class ARC2_StoreAskQueryHandler extends ARC2_StoreSelectQueryHandler {
+
+  function __construct($a, &$caller) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->store = $this->caller;
+  }
+
+  /*  */
+  
+  function runQuery($infos) {
+    $infos['query']['limit'] = 1;
+    $this->infos = $infos;
+    $this->buildResultVars();
+    return parent::runQuery($this->infos);
+  }
+  
+  /*  */
+  
+  function buildResultVars() {
+    $this->infos['query']['result_vars'][] = array('var' => '1', 'aggregate' => '', 'alias' => 'success');
+  }
+
+  /*  */
+  
+  function getFinalQueryResult($q_sql, $tmp_tbl) {
+    $con = $this->store->getDBCon();
+    $rs = mysql_query('SELECT success FROM ' . $tmp_tbl, $con);
+    $r = ($row = mysql_fetch_array($rs)) ? $row['success'] : 0;
+    return $r ? true : false;
+  }
+
+  /*  */
+  
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreAtomLoader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,32 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Store Atom(2) Loader
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('AtomParser');
+
+class ARC2_StoreAtomLoader extends ARC2_AtomParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function addT($t) {
+    $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
+    $this->t_count++;
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreCBJSONLoader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,38 @@
+<?php
+/**
+ * ARC2 Store CrunchBase API JSON Loader
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('CBJSONParser');
+
+class ARC2_StoreCBJSONLoader extends ARC2_CBJSONParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function done() {
+    $this->extractRDF();
+  }
+  
+  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
+    $o = $this->toUTF8($o);
+    $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
+    $this->t_count++;
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreConstructQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,115 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 RDF Store CONSTRUCT Query Handler
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('StoreSelectQueryHandler');
+
+class ARC2_StoreConstructQueryHandler extends ARC2_StoreSelectQueryHandler {
+
+  function __construct($a, &$caller) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->store = $this->caller;
+  }
+
+  /*  */
+  
+  function runQuery($infos) {
+    $this->infos = $infos;
+    $this->buildResultVars();
+    $this->infos['query']['distinct'] = 1;
+    $sub_r = parent::runQuery($this->infos);
+    $rf = $this->v('result_format', '', $infos);
+    if (in_array($rf, array('sql', 'structure', 'index'))) {
+      return $sub_r;
+    }
+    return $this->getResultIndex($sub_r);
+  }
+  
+  /*  */
+  
+  function buildResultVars() {
+    $r = array();
+    foreach ($this->infos['query']['construct_triples'] as $t) {
+      foreach (array('s', 'p', 'o') as $term) {
+        if ($t[$term . '_type'] == 'var') {
+          if (!in_array($t[$term], $r)) {
+            $r[] = array('var' => $t[$term], 'aggregate' => '', 'alias' => '');
+          }
+        }
+      }
+    }
+    $this->infos['query']['result_vars'] = $r;
+  }
+
+  /*  */
+
+  function getResultIndex($qr) {
+    $r = array();
+    $added = array();
+    $rows = $this->v('rows', array(), $qr);
+    $cts = $this->infos['query']['construct_triples'];
+    $bnc = 0;
+    foreach ($rows as $row) {
+      $bnc++;
+      foreach ($cts as $ct) {
+        $skip_t = 0;
+        $t = array();
+        foreach (array('s', 'p', 'o') as $term) {
+          $val = $ct[$term];
+          $type = $ct[$term . '_type'];
+          $val = ($type == 'bnode') ? $val . $bnc : $val;
+          if ($type == 'var') {
+            $skip_t = !isset($row[$val]) ? 1 : $skip_t;
+            $type = !$skip_t ? $row[$val . ' type'] : '';
+            $val = (!$skip_t) ? $row[$val] : '';
+          }
+          $t[$term] = $val;
+          $t[$term . '_type'] = $type;
+          if (isset($row[$ct[$term] . ' lang'])) {
+            $t[$term . '_lang'] = $row[$ct[$term] . ' lang'];
+          }
+          if (isset($row[$ct[$term] . ' datatype'])) {
+            $t[$term . '_datatype'] = $row[$ct[$term] . ' datatype'];
+          }
+        }
+        if (!$skip_t) {
+          $s = $t['s'];
+          $p = $t['p'];
+          $o = $t['o'];
+          if (!isset($r[$s])) {
+            $r[$s] = array();
+          }
+          if (!isset($r[$s][$p])) {
+            $r[$s][$p] = array();
+          }
+          $o = array('value' => $o);
+          foreach (array('lang', 'type', 'datatype') as $suffix) {
+            if (isset($t['o_' . $suffix]) && $t['o_' . $suffix]) {
+              $o[$suffix] = $t['o_' . $suffix];
+            }
+          }
+          if (!isset($added[md5($s . ' ' . $p . ' ' . serialize($o))])) {
+            $r[$s][$p][] = $o;
+            $added[md5($s . ' ' . $p . ' ' . serialize($o))] = 1;
+          }
+        }
+      }
+    }
+    return $r;
+  }
+  
+  /*  */
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreDeleteQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,233 @@
+<?php
+/**
+ * ARC2 RDF Store DELETE Query Handler
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+*/
+
+ARC2::inc('StoreQueryHandler');
+
+class ARC2_StoreDeleteQueryHandler extends ARC2_StoreQueryHandler {
+
+  function __construct($a, &$caller) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->store = $this->caller;
+    $this->handler_type = 'delete';
+  }
+
+  /*  */
+  
+  function runQuery($infos) {
+    $this->infos = $infos;
+    $con = $this->store->getDBCon();
+    $t1 = ARC2::mtime();
+    /* delete */
+    $this->refs_deleted = false;
+    /* graph(s) only */
+    if (!$this->v('construct_triples', array(), $this->infos['query'])) {
+      $tc = $this->deleteTargetGraphs();
+    }
+    /* graph(s) + explicit triples */
+    elseif (!$this->v('pattern', array(), $this->infos['query'])) {
+      $tc = $this->deleteTriples();
+    }
+    /* graph(s) + constructed triples */
+    else {
+      $tc = $this->deleteConstructedGraph();
+    }
+    $t2 = ARC2::mtime();
+    /* clean up */
+    if ($tc && ($this->refs_deleted || (rand(1, 100) == 1))) $this->cleanTableReferences();
+    if ($tc && (rand(1, 100) == 1)) $this->store->optimizeTables();
+    if ($tc && (rand(1, 500) == 1)) $this->cleanValueTables();
+    $t3 = ARC2::mtime();
+    $index_dur = round($t3 - $t2, 4);
+    $dur = round($t3 - $t1, 4);
+    return array(
+      't_count' => $tc,
+      'delete_time' => $dur,
+      'index_update_time' => $index_dur,
+    );
+  }
+  
+  /*  */
+
+  function deleteTargetGraphs() {
+    $tbl_prefix = $this->store->getTablePrefix();
+    $r = 0;
+    $con = $this->store->getDBCon();
+    foreach ($this->infos['query']['target_graphs'] as $g) {
+      if ($g_id = $this->getTermID($g, 'g')) {
+        $rs = mysql_query('DELETE FROM ' . $tbl_prefix . 'g2t WHERE g = ' .$g_id, $con);
+        $r += mysql_affected_rows($con);
+      }
+    }
+    $this->refs_deleted = $r ? 1 : 0;
+    return $r;
+  }
+  
+  /*  */
+  
+  function deleteTriples() {
+    $r = 0;
+    $dbv = $this->store->getDBVersion();
+    $tbl_prefix = $this->store->getTablePrefix();
+    $con = $this->store->getDBCon();
+    /* graph restriction */
+    $tgs = $this->infos['query']['target_graphs'];
+    $gq = '';
+    foreach ($tgs as $g) {
+      if ($g_id = $this->getTermID($g, 'g')) {
+        $gq .= $gq ? ', ' . $g_id : $g_id;
+      }
+    }
+    $gq = $gq ? ' AND G.g IN (' . $gq . ')' : '';
+    /* triples */
+    foreach ($this->infos['query']['construct_triples'] as $t) {
+      $q = '';
+      $skip = 0;
+      foreach (array('s', 'p', 'o') as $term) {
+        if (isset($t[$term . '_type']) && preg_match('/(var)/', $t[$term . '_type'])) {
+          //$skip = 1;
+        }
+        else {
+          $term_id = $this->getTermID($t[$term], $term);
+          $q .= ($q ? ' AND ' : '') . 'T.' . $term . '=' . $term_id;
+          /* explicit lang/dt restricts the matching */
+          if ($term == 'o') {
+            $o_lang = $this->v1('o_lang', '', $t);
+            $o_lang_dt = $this->v1('o_datatype', $o_lang, $t);
+            if ($o_lang_dt) {
+              $q .= ($q ? ' AND ' : '') . 'T.o_lang_dt=' . $this->getTermID($o_lang_dt, 'lang_dt');
+            }
+          }
+        }
+      }
+      if ($skip) {
+        continue;
+      }
+      if ($gq) {
+        $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'g2t' : 'DELETE G';
+        $sql .= '
+          FROM ' . $tbl_prefix . 'g2t G 
+          JOIN ' . $this->getTripleTable() . ' T ON (T.t = G.t' . $gq . ')
+          WHERE ' . $q . '
+        ';
+        $this->refs_deleted = 1;
+      }
+      else {/* triples only */
+        $sql = ($dbv < '04-01') ? 'DELETE ' . $this->getTripleTable() : 'DELETE T';
+        $sql .= ' FROM ' . $this->getTripleTable() . ' T WHERE ' . $q;
+      }
+      //$rs = mysql_query($sql, $con);
+      $rs = $this->queryDB($sql, $con);
+      if ($er = mysql_error($con)) {
+        $this->addError($er .' in ' . $sql);
+      }
+      $r += mysql_affected_rows($con);
+    }
+    return $r;
+  }
+  
+  /*  */
+  
+  function deleteConstructedGraph() {
+    ARC2::inc('StoreConstructQueryHandler');
+    $h = new ARC2_StoreConstructQueryHandler($this->a, $this->store);
+    $sub_r = $h->runQuery($this->infos);
+    $triples = ARC2::getTriplesFromIndex($sub_r);
+    $tgs = $this->infos['query']['target_graphs'];
+    $this->infos = array('query' => array('construct_triples' => $triples, 'target_graphs' => $tgs));
+    return $this->deleteTriples();
+  }
+  
+  /*  */
+  
+  function cleanTableReferences() {
+    /* lock */
+    if (!$this->store->getLock()) return $this->addError('Could not get lock in "cleanTableReferences"');
+    $con = $this->store->getDBCon();
+    $tbl_prefix = $this->store->getTablePrefix();
+    $dbv = $this->store->getDBVersion();
+    /* check for unconnected triples */
+    $sql = '
+      SELECT T.t FROM '. $tbl_prefix . 'triple T LEFT JOIN '. $tbl_prefix . 'g2t G ON ( G.t = T.t )
+      WHERE G.t IS NULL LIMIT 1
+    ';
+    if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs)) {
+      /* delete unconnected triples */
+      $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'triple' : 'DELETE T';
+      $sql .= '
+        FROM ' . $tbl_prefix . 'triple T 
+        LEFT JOIN ' . $tbl_prefix . 'g2t G ON (G.t = T.t)
+        WHERE G.t IS NULL
+      ';
+      mysql_query($sql, $con);
+    }
+    /* check for unconnected graph refs */
+    if ((rand(1, 10) == 1)) {
+      $sql = '
+        SELECT G.g FROM '. $tbl_prefix . 'g2t G LEFT JOIN '. $tbl_prefix . 'triple T ON ( T.t = G.t )
+        WHERE T.t IS NULL LIMIT 1
+      ';
+      if (($rs = mysql_query($sql, $con)) && mysql_num_rows($rs)) {
+        /* delete unconnected graph refs */
+        $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'g2t' : 'DELETE G';
+        $sql .= '
+          FROM ' . $tbl_prefix . 'g2t G 
+          LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.t = G.t)
+          WHERE T.t IS NULL
+        ';
+        mysql_query($sql, $con);
+      }
+    }
+    /* release lock */
+    $this->store->releaseLock();
+  }
+  
+  /*  */
+
+  function cleanValueTables() {
+    /* lock */
+    if (!$this->store->getLock()) return $this->addError('Could not get lock in "cleanValueTables"');
+    $con = $this->store->getDBCon();
+    $tbl_prefix = $this->store->getTablePrefix();
+    $dbv = $this->store->getDBVersion();
+    /* o2val */
+    $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'o2val' : 'DELETE V';
+    $sql .= '
+      FROM ' . $tbl_prefix . 'o2val V 
+      LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.o = V.id)
+      WHERE T.t IS NULL
+    ';
+    mysql_query($sql, $con);
+    /* s2val */
+    $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 's2val' : 'DELETE V';
+    $sql .= '
+      FROM ' . $tbl_prefix . 's2val V 
+      LEFT JOIN ' . $tbl_prefix . 'triple T ON (T.s = V.id)
+      WHERE T.t IS NULL
+    ';
+    mysql_query($sql, $con);
+    /* id2val */
+    $sql = ($dbv < '04-01') ? 'DELETE ' . $tbl_prefix . 'id2val' : 'DELETE V';
+    $sql .= '
+      FROM ' . $tbl_prefix . 'id2val V 
+      LEFT JOIN ' . $tbl_prefix . 'g2t G ON (G.g = V.id)
+      LEFT JOIN ' . $tbl_prefix . 'triple T1 ON (T1.p = V.id)
+      LEFT JOIN ' . $tbl_prefix . 'triple T2 ON (T2.o_lang_dt = V.id)
+      WHERE G.g IS NULL AND T1.t IS NULL AND T2.t IS NULL
+    ';
+    //mysql_query($sql, $con);
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreDescribeQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,119 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Store DESCRIBE Query Handler
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('StoreSelectQueryHandler');
+
+class ARC2_StoreDescribeQueryHandler extends ARC2_StoreSelectQueryHandler {
+
+  function __construct($a, &$caller) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->store = $this->caller;
+    $this->detect_labels = $this->v('detect_describe_query_labels', 0, $this->a);
+  }
+
+  /*  */
+  
+  function runQuery($infos) {
+    $ids = $infos['query']['result_uris'];
+    if ($vars = $infos['query']['result_vars']) {
+      $sub_r = parent::runQuery($infos);
+      $rf = $this->v('result_format', '', $infos);
+      if (in_array($rf, array('sql', 'structure', 'index'))) {
+        return $sub_r;
+      }
+      $rows = $this->v('rows', array(), $sub_r);
+      foreach ($rows as $row) {
+        foreach ($vars as $info) {
+          $val = isset($row[$info['var']]) ? $row[$info['var']] : '';
+          if ($val && ($row[$info['var'] . ' type'] != 'literal') && !in_array($val, $ids)) {
+            $ids[] = $val;
+          }
+        }
+      }
+    }
+    $this->r = array();
+    $this->described_ids = array();
+    $this->ids = $ids;
+    $this->added_triples = array();
+    $is_sub_describe = 0;
+    while ($this->ids) {
+      $id = $this->ids[0];
+      $this->described_ids[] = $id;
+      if ($this->detect_labels) {
+        $q = '
+          CONSTRUCT { 
+            <' . $id . '> ?p ?o . 
+            ?o ?label_p ?o_label . 
+            ?o <http://arc.semsol.org/ns/arc#label> ?o_label .
+          } WHERE { 
+            <' . $id . '> ?p ?o .
+            OPTIONAL {
+              ?o ?label_p ?o_label .
+              FILTER REGEX(str(?label_p), "(name|label|title|summary|nick|fn)$", "i") 
+            }
+          }
+        ';
+      }
+      else {
+        $q = '
+          CONSTRUCT { 
+            <' . $id . '> ?p ?o . 
+          } WHERE { 
+            <' . $id . '> ?p ?o .
+          }
+        ';
+      }
+      $sub_r = $this->store->query($q);
+      $sub_index = is_array($sub_r['result']) ? $sub_r['result'] : array();
+      $this->mergeSubResults($sub_index, $is_sub_describe);
+      $is_sub_describe = 1;
+    }
+    return $this->r;
+  }
+  
+  /*  */
+  
+  function mergeSubResults($index, $is_sub_describe = 1) {
+    foreach ($index as $s => $ps) {
+      if (!isset($this->r[$s])) $this->r[$s] = array();
+      foreach ($ps as $p => $os) {
+        if (!isset($this->r[$s][$p])) $this->r[$s][$p] = array();
+        foreach ($os as $o) {
+          $id = md5($s . ' ' . $p . ' ' . serialize($o));
+          if (!isset($this->added_triples[$id])) {
+            if (1 || !$is_sub_describe) {
+              $this->r[$s][$p][] = $o;
+              if (is_array($o) && ($o['type'] == 'bnode') && !in_array($o['value'], $this->ids)) $this->ids[] = $o['value'];
+            }
+            elseif (!is_array($o) || ($o['type'] != 'bnode')) {
+              $this->r[$s][$p][] = $o;
+            }
+            $this->added_triples[$id] = 1;
+          }
+        }
+      }
+    }
+    /* adjust ids */
+    $ids = $this->ids;
+    $this->ids = array();
+    foreach ($ids as $id) {
+      if (!in_array($id, $this->described_ids)) $this->ids[] = $id;
+    }
+  }
+  
+  /*  */
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreDumpQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,37 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 RDF Store DUMP Query Handler
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('StoreQueryHandler');
+
+class ARC2_StoreDumpQueryHandler extends ARC2_StoreQueryHandler {
+
+  function __construct($a, &$caller) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->store = $this->caller;
+  }
+
+  /*  */
+  
+  function runQuery($infos, $keep_bnode_ids = 0) {
+    $this->infos = $infos;
+    $con = $this->store->getDBCon();
+    ARC2::inc('StoreDumper');
+    $d = new ARC2_StoreDumper($this->a, $this->store);
+    $d->dumpSPOG();
+    return 1;
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreDumper.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,222 @@
+<?php
+/**
+ * ARC2 Store Dumper
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_StoreDumper extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->store = $this->caller;
+    $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
+    $this->limit = 100000;
+  }
+
+  /*  */
+  
+  function dumpSPOG() {
+    header('Content-Type: application/sparql-results+xml');
+    if ($this->v('store_use_dump_dir', 0, $this->a)) {
+      $path = $this->v('store_dump_dir', 'dumps', $this->a);
+      /* default: monthly dumps */
+      $path_suffix = $this->v('store_dump_suffix', date('Y_m'), $this->a);
+      $path .= '/dump_' . $path_suffix . '.spog';
+      if (!file_exists($path)) {
+        $this->saveSPOG($path);
+      }
+      readfile($path);
+      exit;
+    }
+    echo $this->getHeader();
+    $offset = 0;
+    do {
+      $proceed = 0;
+      $rs = $this->getRecordset($offset);
+      if (!$rs) break;
+      while ($row = mysql_fetch_array($rs)) {
+        echo $this->getEntry($row);
+        $proceed = 1;
+      }
+      $offset += $this->limit;
+    } while ($proceed);
+    echo $this->getFooter();
+  }
+
+  /*  */
+
+  function saveSPOG($path, $q = '') {
+    if ($q) return $this->saveCustomSPOG($path, $q);
+    if (!$fp = @fopen($path, 'w')) return $this->addError('Could not create backup file at ' . realpath($path));
+    fwrite($fp, $this->getHeader());
+    $offset = 0;
+    do {
+      $proceed = 0;
+      $rs = $this->getRecordset($offset);
+      if (!$rs) break;
+      while ($row = mysql_fetch_array($rs)) {
+        fwrite($fp, $this->getEntry($row));
+        $proceed = 1;
+      }
+      $offset += $this->limit;
+    } while ($proceed);
+    fwrite($fp, $this->getFooter());
+    @fclose($fp);
+    return 1;
+  }
+
+  /*  */
+
+  function saveCustomSPOG($path, $q) {
+    if (!$fp = @fopen($path, 'w')) return $this->addError('Could not create backup file at ' . realpath($path));
+    fwrite($fp, $this->getHeader());
+    $rows = $this->store->query($q, 'rows');
+    foreach ($rows as $row) {
+      fwrite($fp, $this->getEntry($row));
+    }
+    fwrite($fp, $this->getFooter());
+    @fclose($fp);
+  }
+  
+  /*  */
+
+  function getRecordset($offset) {
+    $prefix = $this->store->getTablePrefix();
+    $con = $this->store->getDBCon();
+    $sql = '
+      SELECT 
+        VS.val AS s,
+        T.s_type AS `s type`,
+        VP.val AS p,
+        0 AS `p type`,
+        VO.val AS o,
+        T.o_type AS `o type`,
+        VLDT.val as `o lang_dt`,
+        VG.val as g,
+        0 AS `g type`
+      FROM
+        ' . $prefix . 'triple T
+        JOIN ' . $prefix . 's2val VS ON (T.s = VS.id)
+        JOIN ' . $prefix . 'id2val VP ON (T.p = VP.id)
+        JOIN ' . $prefix . 'o2val VO ON (T.o = VO.id)
+        JOIN ' . $prefix . 'id2val VLDT ON (T.o_lang_dt = VLDT.id)
+        JOIN ' . $prefix . 'g2t G2T ON (T.t = G2T.t)
+        JOIN ' . $prefix . 'id2val VG ON (G2T.g = VG.id)
+    ';
+    if ($this->limit) $sql .= ' LIMIT ' . $this->limit;
+    if ($offset) $sql .= ' OFFSET ' . $offset;
+    $rs = mysql_unbuffered_query($sql, $con);
+    if (($err = mysql_error($con))) {
+      return $this->addError($err);
+    }
+    return $rs;
+  }
+
+  /*  */
+  
+  function getHeader() {
+    $n = "\n";
+    return '' .
+      '<?xml version="1.0"?>' . 
+      $n . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
+      $n . '  <head>' .
+      $n . '    <variable name="s"/>' .
+      $n . '    <variable name="p"/>' .
+      $n . '    <variable name="o"/>' .
+      $n . '    <variable name="g"/>' .
+      $n . '  </head>' .
+      $n . '  <results>' .
+    '';
+  }
+
+  function getEntry($row) {
+    if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 1200, $this->a));
+    $n = "\n";
+    $r = '';
+    $r .= $n . '    <result>';
+    foreach (array('s', 'p', 'o', 'g') as $var) {
+      if (isset($row[$var])) {
+        $type = (string) $row[$var . ' type'];
+        $r .= $n . '      <binding name="' . $var . '">';
+        $val = $this->toUTF8($row[$var]);
+        if (($type == '0') || ($type == 'uri')) {
+          $r .= $n . '        <uri>' . $this->getSafeValue($val) . '</uri>';
+        }
+        elseif (($type == '1') || ($type == 'bnode')) {
+          $r .= $n . '        <bnode>' . substr($val, 2) . '</bnode>';
+        }
+        else {
+          $lang_dt = '';
+          foreach (array('o lang_dt', 'o lang', 'o datatype') as $k) {
+            if (($var == 'o') && isset($row[$k]) && $row[$k]) $lang_dt = $row[$k];
+          }
+          $is_lang = preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt);
+          list($lang, $dt) = $is_lang ? array($lang_dt, '') : array('', $lang_dt);
+          $lang = $lang ? ' xml:lang="' . $lang . '"' : '';
+          $dt = $dt ? ' datatype="' . htmlspecialchars($dt) . '"' : '';
+          $r .= $n . '        <literal' . $dt . $lang . '>' . $this->getSafeValue($val) . '</literal>';
+        }
+        $r .= $n . '      </binding>';
+      }
+    }
+    $r .= $n . '    </result>';
+    return $r;
+  }
+
+  function getSafeValue($val) {/* mainly for fixing json_decode bugs */
+    $mappings = array(
+      '%00' => '',
+      '%01' => '',
+      '%02' => '',
+      '%03' => '',
+      '%04' => '',
+      '%05' => '',
+      '%06' => '',
+      '%07' => '',
+      '%08' => '',
+      '%09' => '',
+      '%0B' => '',
+      '%0C' => '',
+      '%0E' => '',
+      '%0F' => '',
+      '%15' => '',
+      '%17' => 'Ä—',
+      '%1A' => ',',
+      '%1F' => '',
+    );
+    $froms = array_keys($mappings);
+    $tos = array_values($mappings);
+    foreach ($froms as $i => $from) $froms[$i] = urldecode($from);
+    $val = str_replace($froms, $tos, $val);
+    if (strpos($val, '</') !== false) {
+      $val = "\n<![CDATA[\n" . $val . "\n]]>\n";
+    }
+    else {
+      $val = htmlspecialchars($val);
+    }
+    return $val;
+  }
+
+  function getFooter() {
+    $n = "\n";
+    return '' .
+      $n . '  </results>' .
+      $n . '</sparql>' . 
+      $n .
+    '';
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreEndpoint.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1080 @@
+<?php
+/**
+ * ARC2 SPARQL Endpoint
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Store');
+
+class ARC2_StoreEndpoint extends ARC2_Store {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->headers = array('http' => 'HTTP/1.1 200 OK', 'vary' => 'Vary: Accept');
+    $this->read_key = $this->v('endpoint_read_key', '', $this->a);
+    $this->write_key = $this->v('endpoint_write_key', '', $this->a);
+    $this->timeout = $this->v('endpoint_timeout', 0, $this->a);
+    $this->a['store_allow_extension_functions'] = $this->v('store_allow_extension_functions', 0, $this->a);    
+    $this->allow_sql = $this->v('endpoint_enable_sql_output', 0, $this->a);
+    $this->result = '';
+  }
+
+  /*  */
+  
+  function getQueryString($mthd = '') {
+    $r = '';
+    if (!$mthd || ($mthd == 'post')) {
+      $r = @file_get_contents('php://input');
+    }
+    $r = !$r ?$this->v1('QUERY_STRING', '', $_SERVER) : $r;
+    return $r;
+  }
+
+  function p($name='', $mthd = '', $multi = '', $default = '') {
+    $mthd = strtolower($mthd);
+    if($multi){
+      $qs = $this->getQueryString($mthd);
+      if (preg_match_all('/\&' . $name . '=([^\&]+)/', $qs, $m)){
+        foreach ($m[1] as $i => $val) {
+          $m[1][$i] = stripslashes($val);
+        }
+        return $m[1];
+      }
+      return $default ? $default : array();
+    }
+    $args = array_merge($_GET, $_POST);
+    $r = isset($args[$name]) ? $args[$name] : $default;
+    return is_array($r) ? $r : stripslashes($r);
+  }
+  
+  /*  */
+
+  function getFeatures() {
+    return $this->v1('endpoint_features', array(), $this->a);
+  }
+
+  function setHeader($k, $v) {
+    $this->headers[$k] = $v;
+  }
+  
+  function sendHeaders() {
+    if (!isset($this->is_dump) || !$this->is_dump) {
+      $this->setHeader('content-length', 'Content-Length: ' . strlen($this->getResult()));
+      foreach ($this->headers as $k => $v) {
+        header($v);
+      }
+    }
+  }
+  
+  function getResult() {
+    return $this->result;
+  }
+  
+  /*  */
+  
+  function handleRequest($auto_setup = 0) {
+    if (!$this->isSetUp()) {
+      if ($auto_setup) {
+        $this->setUp();
+        return $this->handleRequest(0);
+      }
+      else {
+        $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
+        $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+        $this->result = 'Missing configuration or the endpoint store was not set up yet.';
+      }
+    }
+    elseif (($img = $this->p('img'))) {
+      $this->handleImgRequest($img);
+    }
+    elseif (($q = $this->p('query'))) {
+      $this->checkProcesses();
+      $this->handleQueryRequest($q);
+      if ($this->p('show_inline')) {
+        $this->query_result = '
+          <div class="results">
+            ' . ($this->p('output') != 'htmltab' ? '<pre>' . htmlspecialchars($this->getResult()) . '</pre>' : $this->getResult()) . '
+          </div>
+        ';
+        $this->handleEmptyRequest(1);
+      }
+    }
+    else {
+      $this->handleEmptyRequest();
+    }
+  }
+  
+  function go($auto_setup = 0) {
+    $this->handleRequest($auto_setup);
+    $this->sendHeaders();
+    echo $this->getResult();
+  }
+  
+  /*  */
+  
+  function handleImgRequest($img) {
+    $this->setHeader('content-type', 'Content-type: image/gif');
+    $imgs = array(
+      'bg_body' => base64_decode('R0lGODlhAQBkAMQAAPf39/Hx8erq6vPz8/Ly8u/v7+np6fT09Ovr6/b29u3t7ejo6Pz8/Pv7+/39/fr6+vj4+P7+/vn5+f///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABAGQAAAUp4GIIiFIExHAkAAC9cAxJdG3TT67vTe//jKBQ6Cgaj5GkcpmcOJ/QZwgAOw=='),
+    );
+    $this->result = isset($imgs[$img]) ? $imgs[$img] : '';
+    $this->sendHeaders();
+    echo $this->getResult();
+    exit;
+  }
+  
+  /*  */
+  
+  function handleEmptyRequest($force = 0) {
+    /* service description */
+    $formats = array(
+      'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 'html' => 'HTML'
+    );
+    if (!$force && $this->getResultFormat($formats, 'html') != 'HTML') {
+      $this->handleServiceDescriptionRequest();
+    }
+    else {
+      $this->setHeader('content-type', 'Content-type: text/html; charset=utf-8');
+      $this->result = $this->getHTMLFormDoc();
+    }
+  }
+
+  /*  */
+
+  function handleServiceDescriptionRequest() {
+    $q = '
+      PREFIX void: <http://rdfs.org/ns/void#>
+      CONSTRUCT {
+        <> void:sparqlEndpoint <> .
+      }
+      WHERE {
+        ?s ?p ?o .
+      } LIMIT 1
+    ';
+    $this->handleQueryRequest($q);
+  }
+
+  /*  */
+
+  function checkProcesses() {
+    if (method_exists($this->caller, 'checkSPARQLEndpointProcesses')) {
+      $sub_r = $this->caller->checkSPARQLEndpointProcesses();
+    }
+    elseif ($this->timeout) {
+      $this->killDBProcesses('', $this->timeout);
+    }
+  }
+  
+  /*  */
+
+  function handleQueryRequest($q) {
+    if (preg_match('/^dump/i', $q)) {
+      $infos = array('query' => array('type' => 'dump'));
+      $this->is_dump = 1;
+    }
+    else {
+      ARC2::inc('SPARQLPlusParser');
+      $p = new ARC2_SPARQLPlusParser($this->a, $this);
+      $p->parse($q);
+      $infos = $p->getQueryInfos();
+    }
+    /* errors? */
+    if ($errors = $this->getErrors()) {
+      $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
+      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+      $this->result = htmlspecialchars(join("\n", $errors));
+      return true;
+    }
+    $qt = $infos['query']['type'];
+    /* wrong read key? */
+    if ($this->read_key && ($this->p('key') != $this->read_key) && preg_match('/^(select|ask|construct|describe|dump)$/', $qt)) {
+      $this->setHeader('http', 'HTTP/1.1 401 Access denied');
+      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+      $this->result = 'Access denied. Missing or wrong "key" parameter.';
+      return true;
+    }
+    /* wrong write key? */
+    if ($this->write_key && ($this->p('key') != $this->write_key) && preg_match('/^(load|insert|delete|update)$/', $qt)) {
+      $this->setHeader('http', 'HTTP/1.1 401 Access denied');
+      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+      $this->result = 'Access denied. Missing or wrong "key" parameter.';
+      return true;
+    }
+    /* non-allowed query type? */
+    if (!in_array($qt, $this->getFeatures())) {
+      $this->setHeader('http', 'HTTP/1.1 401 Access denied');
+      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+      $this->result = 'Access denied for "' .$qt. '" query';
+      return true;
+    }
+    /* load/insert/delete via GET */
+    if (in_array($qt, array('load', 'insert', 'delete')) && isset($_GET['query'])) {
+      $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
+      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+      $this->result = 'Query type "' .$qt. '" not supported via GET';
+      return true;
+    }
+    /* unsupported query type */
+    if (!in_array($qt, array('select', 'ask', 'describe', 'construct', 'load', 'insert', 'delete', 'dump'))) {
+      $this->setHeader('http', 'HTTP/1.1 501 Not Implemented');
+      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+      $this->result = 'Unsupported query type "' .$qt. '"';
+      return true;
+    }
+    /* adjust infos */
+    $infos = $this->adjustQueryInfos($infos);
+    $t1 = ARC2::mtime();
+    $r = array('result' => $this->runQuery($infos, $qt));
+    $t2 = ARC2::mtime();
+    $r['query_time'] = $t2 - $t1;
+    /* query errors? */
+    if ($errors = $this->getErrors()) {
+      $this->setHeader('http', 'HTTP/1.1 400 Bad Request');
+      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+      $this->result = 'Error: ' . join("\n", $errors);
+      return true;
+    }
+    /* result */
+    $m = 'get' . ucfirst($qt) . 'ResultDoc';
+    if (method_exists($this, $m)) {
+      $this->result = $this->$m($r);
+    }
+    else {
+      $this->setHeader('content-type', 'Content-type: text/plain; charset=utf-8');
+      $this->result = 'Result serializer not available, dumping raw data:' . "\n" . print_r($r, 1);
+    }
+  }
+  
+  /*  */
+
+  function adjustQueryInfos($infos) {
+    /* limit */
+    if ($max_l = $this->v('endpoint_max_limit', 0, $this->a)) {
+      if ($this->v('limit', $max_l + 1, $infos['query']) > $max_l) {
+        $infos['query']['limit'] = $max_l;
+      }
+    }
+    /* default-graph-uri / named-graph-uri */
+    $dgs = $this->p('default-graph-uri', '', 1);
+    $ngs = $this->p('named-graph-uri', '', 1);
+    if (count(array_merge($dgs, $ngs))) {
+      $ds = array();
+      foreach ($dgs as $g) {
+        $ds[] = array('graph' => $this->calcURI($g), 'named' => 0);
+      }
+      foreach ($ngs as $g) {
+        $ds[] = array('graph' => $this->calcURI($g), 'named' => 1);
+      }
+      $infos['query']['dataset'] = $ds;
+    }
+    /* infos result format */
+    if (($this->p('format') == 'infos') || ($this->p('output') == 'infos')) {
+      $infos['result_format'] = 'structure';
+    }
+    /* sql result format */
+    if (($this->p('format') == 'sql') || ($this->p('output') == 'sql')) {
+      $infos['result_format'] = 'sql';
+    }
+    return $infos;
+  }
+  
+  /*  */
+
+  function getResultFormat($formats, $default) {
+    $prefs = array();
+    /* arg */
+    if (($v = $this->p('format')) || ($v = $this->p('output'))) {
+      $prefs[] = $v;
+    }
+    /* accept header */
+    $vals = explode(',', $_SERVER['HTTP_ACCEPT']);
+    if ($vals) {
+      $o_vals = array();
+      foreach ($vals as $val) {
+        if (preg_match('/(rdf\+n3|x\-turtle|rdf\+xml|sparql\-results\+xml|sparql\-results\+json|json)/', $val, $m)) {
+          $o_vals[$m[1]] = 1;
+          if (preg_match('/\;q\=([0-9\.]+)/', $val, $sub_m)) {
+            $o_vals[$m[1]] = 1 * $sub_m[1];
+          }
+        }
+      }
+      arsort($o_vals);
+      foreach ($o_vals as $val => $prio) {
+        $prefs[] = $val;
+      }
+    }
+    /* default */
+    $prefs[] = $default;
+    foreach ($prefs as $pref) {
+      if (isset($formats[$pref])) {
+        return $formats[$pref];
+      }
+    }
+  }
+
+  /* SELECT */
+
+  function getSelectResultDoc($r) {
+    $formats = array(
+      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
+      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+      'php_ser' => 'PHPSER', 'plain' => 'Plain', 
+      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+      'infos' => 'Plain',
+      'htmltab' => 'HTMLTable',
+      'tsv' => 'TSV',
+    );
+    if ($f = $this->getResultFormat($formats, 'xml')) {
+      $m = 'get' . $f . 'SelectResultDoc';
+      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+    }
+    return '';
+  }
+  
+  function getSPARQLXMLSelectResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+    $vars = $r['result']['variables'];
+    $rows = $r['result']['rows'];
+    $dur = $r['query_time'];
+    $nl = "\n";
+    /* doc */
+    $r = '' .
+      '<?xml version="1.0"?>' . 
+      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
+    '';
+    /* head */
+    $r .= $nl . '  <head>';
+    $r .= $nl . '    <!-- query time: '. round($dur, 4) .' sec -->';
+    if (is_array($vars)) {
+      foreach ($vars as $var) {
+        $r .= $nl . '    <variable name="' .$var. '"/>';
+      }
+    }
+    $r .= $nl . '  </head>';
+    /* results */
+    $r .= $nl . '  <results>';
+    if (is_array($rows)) {
+      foreach ($rows as $row) {
+        $r .= $nl . '    <result>';
+        foreach ($vars as $var) {
+          if (isset($row[$var])) {
+            $r .= $nl . '      <binding name="' .$var. '">';
+            if ($row[$var . ' type'] == 'uri') {
+              $r .= $nl . '        <uri>' .htmlspecialchars($row[$var]). '</uri>';
+            }
+            elseif ($row[$var . ' type'] == 'bnode') {
+              $r .= $nl . '        <bnode>' .substr($row[$var], 2). '</bnode>';
+            }
+            else {
+              $dt = isset($row[$var . ' datatype']) ? ' datatype="' .htmlspecialchars($row[$var . ' datatype']). '"' : '';
+              $lang = isset($row[$var . ' lang']) ? ' xml:lang="' .htmlspecialchars($row[$var . ' lang']). '"' : '';
+              $r .= $nl . '        <literal' . $dt . $lang . '>' .htmlspecialchars($row[$var]). '</literal>';
+            }
+            $r .= $nl . '      </binding>';
+          }
+        }
+        $r .= $nl . '    </result>';
+      }
+    }
+    $r .= $nl . '  </results>';
+    /* /doc */
+    $r .= $nl . '</sparql>';
+    return $r;
+  }
+  
+  function getSPARQLJSONSelectResultDoc($r) {
+    $con = $this->getDBCon();
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+    $vars = $r['result']['variables'];
+    $rows = $r['result']['rows'];
+    $dur = $r['query_time'];
+    $nl = "\n";
+    /* doc */
+    $r = '{';
+    /* head */
+    $r .= $nl . '  "head": {';
+    $r .= $nl . '    "vars": [';
+    $first_var = 1;
+    foreach ($vars as $var) {
+      $r .= $first_var ? $nl : ',' . $nl;
+      $r .= '      "' .$var. '"';
+      $first_var = 0;
+    }
+    $r .= $nl . '    ]';
+    $r .= $nl . '  },';
+    /* results */
+    $r .= $nl . '  "results": {';
+    $r .= $nl . '    "bindings": [';
+    $first_row = 1;
+    foreach ($rows as $row) {
+      $r .= $first_row ? $nl : ',' . $nl;
+      $r .= '      {';
+      $first_var = 1;
+      foreach ($vars as $var) {
+        if (isset($row[$var])) {
+          $r .= $first_var ? $nl : ',' . $nl . $nl;
+          $r .= '        "' .$var. '": {';
+          if ($row[$var . ' type'] == 'uri') {
+            $r .= $nl . '          "type": "uri",';
+            $r .= $nl . '          "value": "' .mysql_real_escape_string($row[$var], $con). '"';
+          }
+          elseif ($row[$var . ' type'] == 'bnode') {
+            $r .= $nl . '          "type": "bnode",';
+            $r .= $nl . '          "value": "' . substr($row[$var], 2) . '"';
+          }
+          else {
+            $dt = isset($row[$var . ' datatype']) ? ',' . $nl .'          "datatype": "' .mysql_real_escape_string($row[$var . ' datatype'], $con). '"' : '';
+            $lang = isset($row[$var . ' lang']) ? ',' . $nl .'          "xml:lang": "' .mysql_real_escape_string($row[$var . ' lang'], $con). '"' : '';
+            $type = $dt ? 'typed-literal' : 'literal';
+            $r .= $nl . '          "type": "' . $type . '",';
+            $r .= $nl . '          "value": "' . $this->jsonEscape($row[$var]) . '"';
+            $r .= $dt . $lang;
+          }
+          $r .= $nl . '        }';
+          $first_var = 0;
+        }
+      }
+      $r .= $nl . '      }';
+      $first_row = 0;
+    }
+    $r .= $nl . '    ]';
+    $r .= $nl . '  }';
+    /* /doc */
+    $r .= $nl . '}';
+    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+      $r = $v . '(' . $r . ')';
+    }
+    return $r;
+  }
+  
+  function getPHPSERSelectResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return serialize($r);
+  }
+
+  function getPlainSelectResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return print_r($r['result'], 1);
+  }
+
+  function getHTMLTableSelectResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/html; charset=utf-8');
+    $vars = $r['result']['variables'];
+    $rows = $r['result']['rows'];
+    $dur = $r['query_time'];
+    if ($this->p('show_inline')) return '<table>' . $this->getHTMLTableRows($rows, $vars) . '</table>';
+    return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+      <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+      ' .$this->getHTMLDocHead() . '
+      <body>
+        <table>
+          ' . $this->getHTMLTableRows($rows, $vars) . '
+        </table>
+      </body>
+      </html>
+    ';
+  }
+
+  function getHTMLTableRows($rows, $vars) {
+    $r = '';
+    foreach ($rows as $row) {
+      $hr = '';
+      $rr = '';
+      foreach ($vars as $var) {
+        $hr .= $r ? '' : '<th>' . htmlspecialchars($var) . '</th>';
+        $rr .= '<td>' . @htmlspecialchars($row[$var]) . '</td>';
+      }
+      $r .= $hr ? '<tr>' . $hr . '</tr>' : '';
+      $r .= '<tr>' . $rr . '</tr>';
+    }
+    return $r ? $r : '<em>No results found</em>';
+  }
+
+  function getTSVSelectResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain; charset=utf-8');
+    $vars = $r['result']['variables'];
+    $rows = $r['result']['rows'];
+    $dur = $r['query_time'];
+    return $this->getTSVRows($rows, $vars);
+  }
+
+  function getTSVRows($rows, $vars) {
+    $r = '';
+    $delim = "\t";
+    $esc_delim = "\\t";
+    foreach ($rows as $row) {
+      $hr = '';
+      $rr = '';
+      foreach ($vars as $var) {
+        $hr .= $r ? '' : ($hr ? $delim . $var : $var);
+        $val = isset($row[$var]) ? str_replace($delim, $esc_delim, $row[$var]) : '';
+        $rr .= $rr ? $delim . $val : $val;
+      }
+      $r .= $hr . "\n" . $rr;
+    }
+    return $r ? $r : 'No results found';
+  }
+
+  /* ASK */
+  
+  function getAskResultDoc($r) {
+    $formats = array(
+      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
+      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+      'plain' => 'Plain',
+      'php_ser' => 'PHPSER',
+      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+      'infos' => 'Plain',
+    );
+    if ($f = $this->getResultFormat($formats, 'xml')) {
+      $m = 'get' . $f . 'AskResultDoc';
+      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+    }
+    return '';
+  }
+
+  function getSPARQLXMLAskResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+    $r_val = $r['result'] ? 'true' : 'false';
+    $dur = $r['query_time'];
+    $nl = "\n";
+    return '' .
+      '<?xml version="1.0"?>' .
+      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
+      $nl . '  <head>' .
+      $nl . '    <!-- query time: '. round($dur, 4) .' sec -->' .
+      $nl . '  </head>' .
+      $nl . '  <boolean>' .$r_val. '</boolean>' .
+      $nl . '</sparql>' .
+    '';
+  }
+  
+  function getSPARQLJSONAskResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+    $r_val = $r['result'] ? 'true' : 'false';
+    $dur = $r['query_time'];
+    $nl = "\n";
+    $r = '' .
+      $nl . '{' .
+      $nl . '  "head": {' .
+      $nl . '  },' .
+      $nl . '  "boolean" : ' . $r_val . 
+      $nl . '}' . 
+    '';
+    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+      $r = $v . '(' . $r . ')';
+    }
+    return $r;
+  }    
+  
+  function getPHPSERAskResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return serialize($r);
+  }
+
+  function getPlainAskResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return $r['result'] ? 'true' : 'false';
+  }
+
+  /* CONSTRUCT */
+
+  function getConstructResultDoc($r) {
+    $formats = array(
+      'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 
+      'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
+      'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
+      'php_ser' => 'PHPSER',
+      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+      'infos' => 'Plain',
+    );
+    if ($f = $this->getResultFormat($formats, 'rdfxml')) {
+      $m = 'get' . $f . 'ConstructResultDoc';
+      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+    }
+    return '';
+  }
+  
+  function getRDFXMLConstructResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
+    $index = $r['result'];
+    $ser = ARC2::getRDFXMLSerializer($this->a);
+    $dur = $r['query_time'];
+    return $ser->getSerializedIndex($index) . "\n" . '<!-- query time: ' . $dur . ' -->';
+  }
+  
+  function getTurtleConstructResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/x-turtle');
+    $index = $r['result'];
+    $ser = ARC2::getTurtleSerializer($this->a);
+    $dur = $r['query_time'];
+    return '# query time: ' . $dur . "\n" . $ser->getSerializedIndex($index);
+  }
+  
+  function getRDFJSONConstructResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/json');
+    $index = $r['result'];
+    $ser = ARC2::getRDFJSONSerializer($this->a);
+    $dur = $r['query_time'];
+    $r = $ser->getSerializedIndex($index);
+    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+      $r = $v . '(' . $r . ')';
+    }
+    return $r;
+  }
+
+  function getPHPSERConstructResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return serialize($r);
+  }
+
+  function getPlainConstructResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return print_r($r['result'], 1);
+  }
+
+  /* DESCRIBE */
+  
+  function getDescribeResultDoc($r) {
+    $formats = array(
+      'rdfxml' => 'RDFXML', 'rdf+xml' => 'RDFXML', 
+      'json' => 'RDFJSON', 'rdf+json' => 'RDFJSON',
+      'turtle' => 'Turtle', 'x-turtle' => 'Turtle', 'rdf+n3' => 'Turtle',
+      'php_ser' => 'PHPSER',
+      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+      'infos' => 'Plain'
+    );
+    if ($f = $this->getResultFormat($formats, 'rdfxml')) {
+      $m = 'get' . $f . 'DescribeResultDoc';
+      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+    }
+    return '';
+  }
+  
+  function getRDFXMLDescribeResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/rdf+xml');
+    $index = $r['result'];
+    $ser = ARC2::getRDFXMLSerializer($this->a);
+    $dur = $r['query_time'];
+    return $ser->getSerializedIndex($index) . "\n" . '<!-- query time: ' . $dur . ' -->';
+  }
+  
+  function getTurtleDescribeResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/x-turtle');
+    $index = $r['result'];
+    $ser = ARC2::getTurtleSerializer($this->a);
+    $dur = $r['query_time'];
+    return '# query time: ' . $dur . "\n" . $ser->getSerializedIndex($index);
+  }
+  
+  function getRDFJSONDescribeResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/json');
+    $index = $r['result'];
+    $ser = ARC2::getRDFJSONSerializer($this->a);
+    $dur = $r['query_time'];
+    $r = $ser->getSerializedIndex($index);
+    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+      $r = $v . '(' . $r . ')';
+    }
+    return $r;
+  }
+
+  function getPHPSERDescribeResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return serialize($r);
+  }
+  
+  function getPlainDescribeResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return print_r($r['result'], 1);
+  }
+
+  /* DUMP */
+  
+  function getDumpResultDoc() {
+    $this->headers = array();
+    return '';
+  }
+  
+  /* LOAD */
+  
+  function getLoadResultDoc($r) {
+    $formats = array(
+      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
+      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+      'plain' => 'Plain',
+      'php_ser' => 'PHPSER',
+      'sql' => ($this->allow_sql ? 'Plain' : 'xSQL'),
+      'infos' => 'Plain',
+    );
+    if ($f = $this->getResultFormat($formats, 'xml')) {
+      $m = 'get' . $f . 'LoadResultDoc';
+      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+    }
+    return '';
+  }
+
+  function getSPARQLXMLLoadResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+    $r_val = $r['result']['t_count'];
+    $dur = $r['query_time'];
+    $nl = "\n";
+    return '' .
+      '<?xml version="1.0"?>' .
+      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
+      $nl . '  <head>' .
+      $nl . '    <!-- query time: '. round($dur, 4) .' sec -->' .
+      $nl . '  </head>' .
+      $nl . '  <inserted>' .$r_val. '</inserted>' .
+      $nl . '</sparql>' .
+    '';
+  }
+  
+  function getSPARQLJSONLoadResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+    $r_val = $r['result']['t_count'];
+    $dur = $r['query_time'];
+    $nl = "\n";
+    $r = '' .
+      $nl . '{' .
+      $nl . '  "head": {' .
+      $nl . '  },' .
+      $nl . '  "inserted" : ' . $r_val . 
+      $nl . '}' . 
+    '';
+    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+      $r = $v . '(' . $r . ')';
+    }
+    return $r;
+  }    
+  
+  function getPHPSERLoadResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return serialize($r);
+  }
+
+  function getPlainLoadResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return print_r($r['result'], 1);
+  }
+
+  /* DELETE */
+  
+  function getDeleteResultDoc($r) {
+    $formats = array(
+      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
+      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+      'plain' => 'Plain',
+      'php_ser' => 'PHPSER'
+    );
+    if ($f = $this->getResultFormat($formats, 'xml')) {
+      $m = 'get' . $f . 'DeleteResultDoc';
+      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+    }
+    return '';
+  }
+
+  function getSPARQLXMLDeleteResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+    $r_val = $r['result']['t_count'];
+    $dur = $r['query_time'];
+    $nl = "\n";
+    return '' .
+      '<?xml version="1.0"?>' .
+      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
+      $nl . '  <head>' .
+      $nl . '    <!-- query time: '. round($dur, 4) .' sec -->' .
+      $nl . '  </head>' .
+      $nl . '  <deleted>' .$r_val. '</deleted>' .
+      $nl . '</sparql>' .
+    '';
+  }
+  
+  function getSPARQLJSONDeleteResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+    $r_val = $r['result']['t_count'];
+    $dur = $r['query_time'];
+    $nl = "\n";
+    $r = '' .
+      $nl . '{' .
+      $nl . '  "head": {' .
+      $nl . '  },' .
+      $nl . '  "deleted" : ' . $r_val . 
+      $nl . '}' . 
+    '';
+    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+      $r = $v . '(' . $r . ')';
+    }
+    return $r;
+  }    
+  
+  function getPHPSERDeleteResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return serialize($r);
+  }
+
+  function getPlainDeleteResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return print_r($r['result'], 1);
+  }
+
+  /* INSERT */
+  
+  function getInsertResultDoc($r) {
+    $formats = array(
+      'xml' => 'SPARQLXML', 'sparql-results+xml' => 'SPARQLXML', 
+      'json' => 'SPARQLJSON', 'sparql-results+json' => 'SPARQLJSON',
+      'plain' => 'Plain',
+      'php_ser' => 'PHPSER'
+    );
+    if ($f = $this->getResultFormat($formats, 'xml')) {
+      $m = 'get' . $f . 'InsertResultDoc';
+      return method_exists($this, $m) ? $this->$m($r) : 'not implemented';
+    }
+    return '';
+  }
+
+  function getSPARQLXMLInsertResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+xml');
+    $r_val = $r['result']['t_count'];
+    $dur = $r['query_time'];
+    $nl = "\n";
+    return '' .
+      '<?xml version="1.0"?>' .
+      $nl . '<sparql xmlns="http://www.w3.org/2005/sparql-results#">' .
+      $nl . '  <head>' .
+      $nl . '    <!-- query time: '. round($dur, 4) .' sec -->' .
+      $nl . '  </head>' .
+      $nl . '  <inserted>' .$r_val. '</inserted>' .
+      $nl . '</sparql>' .
+    '';
+  }
+  
+  function getSPARQLJSONInsertResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: application/sparql-results+json');
+    $r_val = $r['result']['t_count'];
+    $dur = $r['query_time'];
+    $nl = "\n";
+    $r = '' .
+      $nl . '{' .
+      $nl . '  "head": {' .
+      $nl . '  },' .
+      $nl . '  "inserted" : ' . $r_val . 
+      $nl . '}' . 
+    '';
+    if (($v = $this->p('jsonp')) || ($v = $this->p('callback'))) {
+      $r = $v . '(' . $r . ')';
+    }
+    return $r;
+  }    
+  
+  function getPHPSERInsertResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return serialize($r);
+  }
+
+  function getPlainInsertResultDoc($r) {
+    $this->setHeader('content-type', 'Content-Type: text/plain');
+    return print_r($r['result'], 1);
+  }
+
+  /*  */  
+  
+  function jsonEscape($v) {
+    if (function_exists('json_encode')) return trim(json_encode($v), '"');
+    $from = array("\\", "\r", "\t", "\n", '"', "\b", "\f", "/");
+    $to = array('\\\\', '\r', '\t', '\n', '\"', '\b', '\f', '\/');
+    return str_replace($from, $to, $v);
+  }
+    
+  /*  */
+
+  function getHTMLFormDoc() {
+    return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+      <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+      ' . $this->getHTMLDocHead() . '
+      ' . $this->getHTMLDocBody() . '
+      </html>
+    ';
+  }
+
+  function getHTMLDocHead() {
+    return '
+    	<head>
+    		<title>' . $this->getHTMLDocTitle() . '</title>
+    		<style type="text/css">
+        ' . $this->getHTMLDocCSS() . '
+    		</style>
+    	</head>
+    ';
+  }
+  
+  function getHTMLDocTitle() {
+    return $this->v('endpoint_title', 'ARC SPARQL+ Endpoint', $this->a);
+  }
+  
+  function getHTMLDocHeading() {
+    return $this->v('endpoint_heading', 'ARC SPARQL+ Endpoint (v' . ARC2::getVersion() . ')', $this->a);
+  }
+  
+  function getHTMLDocCSS() {
+    $default = '
+      body {
+        font-size: 14px;
+      	font-family: Trebuchet MS, Verdana, Geneva, sans-serif;
+        background: #fff url(?img=bg_body) top center repeat-x;
+        padding: 5px 20px 20px 20px;
+        color: #666;
+      }
+      h1 { font-size: 1.6em; font-weight: normal; }
+      a { color: #c00000; }
+      th, td {
+        border: 1px dotted #eee;
+        padding: 2px 4px; 
+      }
+      #sparql-form {
+        margin-bottom: 30px;
+      }
+      #query { 
+        float: left;
+        width: 60%;
+        display: block; 
+        height: 265px; 
+        margin-bottom: 10px;
+      }
+      .options {
+        float: right;
+        font-size: 0.9em;
+        width: 35%;
+        border-top: 1px solid #ccc;
+      }
+      .options h3 {
+        margin: 5px;
+      }
+      .options dl{
+        margin: 0px;
+        padding: 0px 10px 5px 20px;
+      }
+      .options dl dt {
+        border-top: 1px dotted #ddd;
+        padding-top: 10px;
+      }
+      .options dl dt.first {
+        border: none;
+      }
+      .options dl dd {
+        padding: 5px 0px 7px 0px;
+      }
+      .options-2 {
+        clear: both;
+        margin: 10px 0px;
+      }
+      .form-buttons {
+      }
+      .results {
+        border: 1px solid #eee;
+        padding: 5px;
+        background-color: #fcfcfc;
+      }
+    ';
+    return $this->v('endpoint_css', $default, $this->a);
+  }
+  
+  function getHTMLDocBody() {
+    return '
+    	<body>
+        <h1>' . $this->getHTMLDocHeading() . '</h1>
+        <div class="intro">
+          <p>
+            <a href="?">This interface</a> implements 
+            <a href="http://www.w3.org/TR/rdf-sparql-query/">SPARQL</a> and
+            <a href="https://github.com/semsol/arc2/wiki/SPARQL%2B">SPARQL+</a> via <a href="http://www.w3.org/TR/rdf-sparql-protocol/#query-bindings-http">HTTP Bindings</a>. 
+          </p>
+          <p>
+            Enabled operations: ' . join(', ', $this->getFeatures()) . '
+          </p>
+          <p>
+            Max. number of results : ' . $this->v('endpoint_max_limit', '<em>unrestricted</em>', $this->a) . '
+          </p>
+        </div>
+        ' . $this->getHTMLDocForm() .'
+        ' . ($this->p('show_inline') ? $this->query_result : '') . '
+    	</body>
+    ';
+  }
+  
+  function getHTMLDocForm() {
+    $q = $this->p('query') ? htmlspecialchars($this->p('query')) : "SELECT * WHERE {\n  GRAPH ?g { ?s ?p ?o . }\n}\nLIMIT 10";
+    return '
+      <form id="sparql-form" action="?" enctype="application/x-www-form-urlencoded" method="' . ($_SERVER['REQUEST_METHOD'] == 'GET' ? 'get' : 'post' ) . '">
+        <textarea id="query" name="query" rows="20" cols="80">' . $q . '</textarea>
+        ' . $this->getHTMLDocOptions() . '
+        <div class="form-buttons">
+          <input type="submit" value="Send Query" />
+          <input type="reset" value="Reset" />
+        </div>
+      </form>
+    ';
+  }
+  
+  function getHTMLDocOptions() {
+    $sel = $this->p('output');
+    $sel_code = ' selected="selected"';
+    return '
+      <div class="options">
+        <h3>Options</h3>
+        <dl>
+          <dt class="first">Output format (if supported by query type):</dt>
+          <dd>
+            <select id="output" name="output">
+              <option value="" ' . (!$sel ? $sel_code : '') . '>default</option>
+              <option value="xml" ' . ($sel == 'xml' ? $sel_code : '') . '>XML</option>
+              <option value="json" ' . ($sel == 'json' ? $sel_code : '') . '>JSON</option>
+              <option value="plain" ' . ($sel == 'plain' ? $sel_code : '') . '>Plain</option>
+              <option value="php_ser" ' . ($sel == 'php_ser' ? $sel_code : '') . '>Serialized PHP</option>
+              <option value="turtle" ' . ($sel == 'turtle' ? $sel_code : '') . '>Turtle</option>
+              <option value="rdfxml" ' . ($sel == 'rdfxml' ? $sel_code : '') . '>RDF/XML</option>
+              <option value="infos" ' . ($sel == 'infos' ? $sel_code : '') . '>Query Structure</option>
+              ' . ($this->allow_sql ? '<option value="sql" ' . ($sel == 'sql' ? $sel_code : '') . '>SQL</option>' : '') . '
+              <option value="htmltab" ' . ($sel == 'htmltab' ? $sel_code : '') . '>HTML Table</option>
+              <option value="tsv" ' . ($sel == 'tsv' ? $sel_code : '') . '>TSV</option>
+            </select>
+          </dd>
+          
+          <dt>jsonp/callback (for JSON results)</dt>
+          <dd>
+            <input type="text" id="jsonp" name="jsonp" value="' . htmlspecialchars($this->p('jsonp')) . '" />
+          </dd>
+          
+          <dt>API key (if required)</dt>
+          <dd>
+            <input type="text" id="key" name="key" value="' . htmlspecialchars($this->p('key')) . '" />
+          </dd>
+          
+          <dt>Show results inline: </dt>
+          <dd>
+            <input type="checkbox" name="show_inline" value="1" ' . ($this->p('show_inline') ? ' checked="checked"' : '') . ' />
+          </dd>
+          
+        </dl>
+      </div>
+      <div class="options-2">
+        Change HTTP method: 
+            <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'get\'">GET</a> 
+            <a href="javascript:;" onclick="javascript:document.getElementById(\'sparql-form\').method=\'post\'">POST</a> 
+       </div>
+    ';
+  }
+  
+  /*  */
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreHelper.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 RDF Store Helper
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_StoreHelper extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->store = $this->caller;
+  }
+
+  /*  */
+
+  function changeNamespaceURI($old_uri, $new_uri) {
+    $id_changes = 0;
+    $t_changes = 0;
+    /* table lock */
+    if ($this->store->getLock()) {
+      $con = $this->store->getDBCon();
+      foreach (array('id', 's', 'o') as $id_col) {
+        $tbl = $this->store->getTablePrefix() . $id_col . '2val';
+        $sql = 'SELECT id, val FROM ' . $tbl . ' WHERE val LIKE "' . mysql_real_escape_string($old_uri, $con). '%"';
+        $rs = mysql_query($sql, $con);
+        if (!$rs) continue;
+        while ($row = mysql_fetch_array($rs)) {
+          $new_val = str_replace($old_uri, $new_uri, $row['val']);
+          $new_id = $this->store->getTermID($new_val, $id_col);
+          if (!$new_id) {/* unknown ns uri, overwrite current id value */
+            $sub_sql = "UPDATE " . $tbl . " SET val = '" . mysql_real_escape_string($new_val, $con) . "' WHERE id = " . $row['id'];
+            $sub_r = mysql_query($sub_sql, $con);
+            $id_changes++;
+          }
+          else {/* replace ids */
+            $t_tbls = $this->store->getTables();
+            foreach ($t_tbls as $t_tbl) {
+              if (preg_match('/^triple/', $t_tbl)) {
+                foreach (array('s', 'p', 'o', 'o_lang_dt') as $t_col) {
+                  $sub_sql = "UPDATE " . $this->store->getTablePrefix() . $t_tbl . " SET " . $t_col . " = " . $new_id . " WHERE " . $t_col . " = " . $row['id'];
+                  $sub_r = mysql_query($sub_sql, $con);
+                  $t_changes += mysql_affected_rows($con);
+                }
+              }
+            }
+          }
+        }
+      }
+      $this->store->releaseLock();
+    }
+    return array('id_replacements' => $id_changes, 'triple_updates' => $t_changes);
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreInsertQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,54 @@
+<?php
+/**
+ * ARC2 RDF Store INSERT Query Handler
+ *
+ * @author Benjamin Nowack <bnowack@semsol.com>
+ * @license http://arc.semsol.org/license
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+*/
+
+ARC2::inc('StoreQueryHandler');
+
+class ARC2_StoreInsertQueryHandler extends ARC2_StoreQueryHandler {
+
+  function __construct($a, &$caller) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->store = $this->caller;
+  }
+
+  /*  */
+  
+  function runQuery($infos, $keep_bnode_ids = 0) {
+    $this->infos = $infos;
+    $con = $this->store->getDBCon();
+    /* insert */
+    if (!$this->v('pattern', array(), $this->infos['query'])) {
+      $triples = $this->infos['query']['construct_triples'];
+      /* don't execute empty INSERTs as they trigger a LOAD on the graph URI */
+      if ($triples) {
+        return $this->store->insert($triples, $this->infos['query']['target_graph'], $keep_bnode_ids);
+      }
+      else {
+        return array('t_count' => 0, 'load_time' => 0);
+      }
+    }
+    else {
+      $keep_bnode_ids = 1;
+      ARC2::inc('StoreConstructQueryHandler');
+      $h = new ARC2_StoreConstructQueryHandler($this->a, $this->store);
+      $sub_r = $h->runQuery($this->infos);
+      if ($sub_r) {
+        return $this->store->insert($sub_r, $this->infos['query']['target_graph'], $keep_bnode_ids);
+      }
+      return array('t_count' => 0, 'load_time' => 0);
+    }
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreLoadQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,464 @@
+<?php
+/**
+ * ARC2 RDF Store LOAD Query Handler
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+*/
+
+ARC2::inc('StoreQueryHandler');
+
+class ARC2_StoreLoadQueryHandler extends ARC2_StoreQueryHandler {
+
+  function __construct($a, &$caller) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con, store_log_inserts */
+    parent::__init();
+    $this->store = $this->caller;
+    $this->write_buffer_size = $this->v('store_write_buffer', 2500, $this->a);
+    $this->split_threshold = $this->v('store_split_threshold', 0, $this->a);
+    $this->strip_mb_comp_str = $this->v('store_strip_mb_comp_str', 0, $this->a);
+  }
+
+  /*  */
+  
+  function runQuery($infos, $data = '', $keep_bnode_ids = 0) {
+    $url = $infos['query']['url'];
+    $graph = $infos['query']['target_graph'];
+    $this->target_graph = $graph ? $this->calcURI($graph) : $this->calcURI($url);
+    $this->fixed_target_graph = $graph ? $this->target_graph : '';
+    $this->keep_bnode_ids = $keep_bnode_ids;
+    /* reader */
+    ARC2::inc('Reader');
+    $reader = new ARC2_Reader($this->a, $this);
+    $reader->activate($url, $data);
+    /* format detection */
+    $mappings = array(
+      'rdfxml' => 'RDFXML', 
+      'sparqlxml' => 'SPOG', 
+      'turtle' => 'Turtle', 
+      'ntriples' => 'Turtle', 
+      'rss' => 'RSS',
+      'atom' => 'Atom',
+      'n3' => 'Turtle', 
+      'html' => 'SemHTML',
+      'sgajson' => 'SGAJSON',
+      'cbjson' => 'CBJSON'
+    );
+    $format = $reader->getFormat();
+    if (!$format || !isset($mappings[$format])) {
+      return $this->addError('No loader available for "' .$url. '": ' . $format);
+    }
+    /* format loader */
+    $suffix = 'Store' . $mappings[$format] . 'Loader';
+    ARC2::inc($suffix);
+    $cls = 'ARC2_' . $suffix;
+    $loader = new $cls($this->a, $this);
+    $loader->setReader($reader);
+    /* lock */
+    if (!$this->store->getLock()) {
+      $l_name = $this->a['db_name'] . '.' . $this->store->getTablePrefix() . '.write_lock';
+      return $this->addError('Could not get lock in "runQuery" (' . $l_name . ')');
+    }
+    $this->has_lock = 1;
+    /* logging */
+    $this->t_count = 0;
+    $this->t_start = ARC2::mtime();
+    $this->log_inserts = $this->v('store_log_inserts', 0, $this->a);
+    if ($this->log_inserts) {
+      @unlink("arc_insert_log.txt");
+      $this->inserts = array();
+      $this->insert_times = array();
+      $this->t_prev = $this->t_start;
+      $this->t_count_prev = 0 ;
+    }
+    /* load and parse */
+    $this->max_term_id = $this->getMaxTermID();
+    $this->max_triple_id = $this->getMaxTripleID();
+    $this->column_type = $this->store->getColumnType();
+    //$this->createMergeTable();
+    $this->term_ids = array();
+    $this->triple_ids = array();
+    $this->sql_buffers = array();
+    $r = $loader->parse($url, $data);
+    /* done */
+    $this->checkSQLBuffers(1);
+    if ($this->log_inserts) {
+      $this->logInserts();
+    }
+    $this->store->releaseLock();
+    //$this->dropMergeTable();
+    if ((rand(1, 100) == 1)) $this->store->optimizeTables();
+    $t2 = ARC2::mtime();
+    $dur = round($t2 - $this->t_start, 4);
+    $r = array(
+      't_count' => $this->t_count,
+      'load_time' => $dur,
+    );
+    if ($this->log_inserts) {
+      $r['inserts'] = $this->inserts;
+      $r['insert_times'] = $this->insert_times;
+    }
+    return $r;
+  }
+  
+  /*  */
+
+  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
+    if (!$this->has_lock) return 0;
+    $type_ids = array ('uri' => '0', 'bnode' => '1' , 'literal' => '2');
+    $g = $this->getStoredTermID($this->target_graph, '0', 'id');
+    $s = (($s_type == 'bnode') && !$this->keep_bnode_ids) ? '_:b' . abs(crc32($g . $s)) . '_' . (strlen($s) > 12 ? substr(substr($s, 2) , -10) : substr($s, 2)) : $s;
+    $o = (($o_type == 'bnode') && !$this->keep_bnode_ids) ? '_:b' . abs(crc32($g . $o)) . '_' . (strlen($o) > 12 ? substr(substr($o, 2), -10) : substr($o, 2)) : $o;
+    /* triple */
+    $t = array(
+      's' => $this->getStoredTermID($s, $type_ids[$s_type], 's'),
+      'p' => $this->getStoredTermID($p, '0', 'id'),
+      'o' => $this->getStoredTermID($o, $type_ids[$o_type], 'o'),
+      'o_lang_dt' => $this->getStoredTermID($o_dt . $o_lang, $o_dt ? '0' : '2', 'id'),
+      'o_comp' => $this->getOComp($o),
+      's_type' => $type_ids[$s_type], 
+      'o_type' => $type_ids[$o_type],
+    );
+    $t['t'] = $this->getTripleID($t);
+    if (is_array($t['t'])) {/* t exists already */
+      $t['t'] = $t['t'][0];
+    }
+    else {
+      $this->bufferTripleSQL($t);
+    }
+    /* g2t */
+    $g2t = array('g' => $g, 't' => $t['t']);
+    $this->bufferGraphSQL($g2t);
+    $this->t_count++;
+    /* check buffers */
+    if (($this->t_count % $this->write_buffer_size) == 0) {
+      $force_write = 1;
+      $reset_buffers = (($this->t_count % ($this->write_buffer_size * 2)) == 0);
+      $refresh_lock = (($this->t_count % 25000) == 0);
+      $split_tables = (($this->t_count % ($this->write_buffer_size * 10)) == 0);
+      if ($this->log_inserts) $this->logInserts();
+      $this->checkSQLBuffers($force_write, $reset_buffers, $refresh_lock, $split_tables);
+    }
+  }
+
+  /*  */
+  
+  function getMaxTermID() {
+    $con = $this->store->getDBCon();
+    $sql = '';
+    foreach (array('id2val', 's2val', 'o2val') as $tbl) {
+      $sql .= $sql ? ' UNION ' : '';
+      $sql .= "(SELECT MAX(id) as `id` FROM " . $this->store->getTablePrefix() . $tbl . ')';
+    }
+    $r = 0;
+    if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs)) {
+      while ($row = mysql_fetch_array($rs)) {
+        $r = ($r < $row['id']) ? $row['id'] : $r;
+      }
+    }
+    return $r + 1;
+  }
+  
+  function getMaxTripleID() {
+    $con = $this->store->getDBCon();
+    $sql = "SELECT MAX(t) AS `id` FROM " . $this->store->getTablePrefix() . "triple";
+    if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
+      return $row['id'] + 1;
+    }
+    return 1;
+  }
+
+  function getStoredTermID($val, $type_id, $tbl) {
+    $con = $this->store->getDBCon();
+    /* buffered */
+    if (isset($this->term_ids[$val])) {
+      if (!isset($this->term_ids[$val][$tbl])) {
+        foreach (array('id', 's', 'o') as $other_tbl) {
+          if (isset($this->term_ids[$val][$other_tbl])) {
+            $this->term_ids[$val][$tbl] = $this->term_ids[$val][$other_tbl];
+            $this->bufferIDSQL($tbl, $this->term_ids[$val][$tbl], $val, $type_id);
+            break;
+          }
+        }
+      }
+      return $this->term_ids[$val][$tbl];
+    }
+    /* db */
+    $tbl_prefix = $this->store->getTablePrefix();
+    $sub_tbls = ($tbl == 'id') ? array('id2val', 's2val', 'o2val') : ($tbl == 's' ? array('s2val', 'id2val', 'o2val') : array('o2val', 'id2val', 's2val'));
+    foreach ($sub_tbls as $sub_tbl) {
+      $id = 0;
+      //$sql = "SELECT id AS `id`, '" . $sub_tbl . "' AS `tbl` FROM " . $tbl_prefix . $sub_tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "'";
+      /* via hash */
+      if (preg_match('/^(s2val|o2val)$/', $sub_tbl) && $this->hasHashColumn($sub_tbl)) {
+        $sql = "SELECT id AS `id`, val AS `val` FROM " . $tbl_prefix . $sub_tbl . " WHERE val_hash = BINARY '" . $this->getValueHash($val) . "'";
+        if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs)) {
+          while ($row = mysql_fetch_array($rs)) {
+            if ($row['val'] == $val) {
+              $id = $row['id'];
+              break;
+            }
+          }
+        }
+      }
+      else {
+        $sql = "SELECT id AS `id` FROM " . $tbl_prefix . $sub_tbl . " WHERE val = BINARY '" . mysql_real_escape_string($val, $con) . "'";
+        if (($rs = $this->queryDB($sql . ' LIMIT 1', $con)) && mysql_num_rows($rs)) {
+          $row = mysql_fetch_array($rs);
+          $id = $row['id'];
+        }
+      }
+      if ($id) {
+        $this->term_ids[$val] = array($tbl => $id);
+        if ($sub_tbl != $tbl . '2val') {
+          $this->bufferIDSQL($tbl, $id, $val, $type_id);
+        }
+        break;
+      }
+    }
+    /* new */
+    if (!isset($this->term_ids[$val])) {
+      $this->term_ids[$val] = array($tbl => $this->max_term_id);
+      $this->bufferIDSQL($tbl, $this->max_term_id, $val, $type_id);
+      $this->max_term_id++;
+      /* upgrade tables ? */
+      if (($this->column_type == 'mediumint') && ($this->max_term_id >= 16750000)) {
+        $this->store->extendColumns();
+        $this->column_type = 'int';
+      }
+    }
+    return $this->term_ids[$val][$tbl];
+  }
+
+  function getTripleID($t) {
+    $con = $this->store->getDBCon();
+    $val = serialize($t);
+    /* buffered */
+    if (isset($this->triple_ids[$val])) {
+      return array($this->triple_ids[$val]);/* hack for "don't insert this triple" */
+    }
+    /* db */
+    $sql = "SELECT t FROM " . $this->store->getTablePrefix() . "triple WHERE 
+      s = " . $t['s'] . " AND p = " . $t['p'] . " AND o = " . $t['o'] . " AND o_lang_dt = " . $t['o_lang_dt'] . " AND s_type = " . $t['s_type'] . " AND o_type = " . $t['o_type'] . "
+      LIMIT 1
+    ";
+    if (($rs = $this->queryDB($sql, $con)) && mysql_num_rows($rs) && ($row = mysql_fetch_array($rs))) {
+      $this->triple_ids[$val] = $row['t'];/* hack for "don't insert this triple" */
+      return array($row['t']);/* hack for "don't insert this triple" */
+    }
+    /* new */
+    else {
+      $this->triple_ids[$val] = $this->max_triple_id;
+      $this->max_triple_id++;
+      /* split tables ? */
+      if (0 && $this->split_threshold && !($this->max_triple_id % $this->split_threshold)) {
+        $this->store->splitTables();
+        $this->dropMergeTable();
+        $this->createMergeTable();
+      }
+      /* upgrade tables ? // Thanks to patch by Mark Fichtner (https://github.com/Knurg) */
+      if (($this->column_type == 'mediumint') && ($this->max_triple_id >= 16750000)) {
+        $this->store->extendColumns();
+        $this->column_type = 'int';
+      }
+      return $this->triple_ids[$val];
+    }
+  }
+  
+  function getOComp($val) {
+    /* try date (e.g. 21 August 2007) */
+    if (preg_match('/^[0-9]{1,2}\s+[a-z]+\s+[0-9]{4}/i', $val) && ($uts = strtotime($val)) && ($uts !== -1)) {
+      return date("Y-m-d\TH:i:s", $uts);
+    }
+    /* xsd date (e.g. 2009-05-28T18:03:38+09:00 2009-05-28T18:03:38GMT) */
+    if (preg_match('/^([0-9]{4}\-[0-9]{2}\-[0-9]{2}\T)([0-9\:]+)?([0-9\+\-\:\Z]+)?(\s*[a-z]{2,3})?$/si', $val, $m)) {
+      /* yyyy-mm-dd */
+      $val = $m[1];
+      /* hh:ss */
+      if ($m[2]) {
+        $val .= $m[2];
+        /* timezone offset */
+        if (isset($m[3]) && ($m[3] != 'Z')) {
+          $uts = strtotime(str_replace('T', ' ', $val));
+          if (preg_match('/([\+\-])([0-9]{2})\:?([0-9]{2})$/', $m[3], $sub_m)) {
+            $diff_mins = (3600 * ltrim($sub_m[2], '0')) + ltrim($sub_m[3], '0');
+            $uts = ($sub_m[1] == '-') ? $uts + $diff_mins : $uts - $diff_mins;
+            $val = date('Y-m-d\TH:i:s\Z', $uts);
+          }
+        }
+        else {
+          $val .= 'Z';
+        }
+      }
+      return $val;
+    }
+    /* fallback & backup w/o UTC calculation, to be removed in later revision */
+    if (preg_match('/^[0-9]{4}[0-9\-\:\T\Z\+]+([a-z]{2,3})?$/i', $val)) {
+      return $val;
+    }
+    if (is_numeric($val)) {
+      $val = sprintf("%f", $val);
+      if (preg_match("/([\-\+])([0-9]*)\.([0-9]*)/", $val, $m)) {
+        return $m[1] . sprintf("%018s", $m[2]) . "." . sprintf("%-015s", $m[3]);
+      }
+      if (preg_match("/([0-9]*)\.([0-9]*)/", $val, $m)) {
+        return "+" . sprintf("%018s", $m[1]) . "." . sprintf("%-015s", $m[2]);
+      }
+      return $val;
+    }
+    /* any other string: remove tags, linebreaks etc., but keep MB-chars  */
+    //$val = substr(trim(preg_replace('/[\W\s]+/is', '-', strip_tags($val))), 0, 35);
+    // [\PL\s]+ ( = non-Letters) kills digits
+    $re = $this->has_pcre_unicode ? '/[\PL\s]+/isu' : '/[\s\'\"\´\`]+/is';
+    $re = '/[\s\'\"\´\`]+/is';
+    $val = trim(preg_replace($re, '-', strip_tags($val)));
+    if (strlen($val) > 35) {
+      $fnc = function_exists("mb_substr") ? 'mb_substr' : 'substr';
+      $val = $fnc($val, 0, 17) . '-' . $fnc($val, -17);
+    }
+    if ($this->strip_mb_comp_str) {
+      $val = urldecode(preg_replace('/\%[0-9A-F]{2}/', '', urlencode($val)));
+    }
+    return $this->toUTF8($val);
+  }
+
+  /*  */
+  
+  function bufferTripleSQL($t) {
+    $con = $this->store->getDBCon();
+    $tbl = 'triple';
+    $sql = ", ";
+    if (!isset($this->sql_buffers[$tbl])) {
+      $this->sql_buffers[$tbl] = "INSERT IGNORE INTO " . $this->store->getTablePrefix() . $tbl . " (t, s, p, o, o_lang_dt, o_comp, s_type, o_type) VALUES";
+      $sql = " ";
+    }
+    $this->sql_buffers[$tbl] .= $sql . "(" . $t['t'] . ", " . $t['s'] . ", " . $t['p'] . ", " . $t['o'] . ", " . $t['o_lang_dt'] . ", '" . mysql_real_escape_string($t['o_comp'], $con) . "', " . $t['s_type'] . ", " . $t['o_type'] . ")";
+  }
+  
+  function bufferGraphSQL($g2t) {
+    $tbl = 'g2t';
+    $sql = ", ";
+    if (!isset($this->sql_buffers[$tbl])) {
+      $this->sql_buffers[$tbl] = "INSERT IGNORE INTO " . $this->store->getTablePrefix() . $tbl . " (g, t) VALUES";
+      $sql = " ";
+    }
+    $this->sql_buffers[$tbl] .= $sql . "(" . $g2t['g'] . ", " . $g2t['t'] . ")";
+  }
+  
+  function bufferIDSQL($tbl, $id, $val, $val_type) {
+    $con = $this->store->getDBCon();
+    $tbl = $tbl . '2val';
+    if ($tbl == 'id2val') {
+      $cols = "id, val, val_type";
+      $vals = "(" . $id . ", '" . mysql_real_escape_string($val, $con) . "', " . $val_type . ")";
+    }
+    elseif (preg_match('/^(s2val|o2val)$/', $tbl) && $this->hasHashColumn($tbl)) {
+      $cols = "id, val_hash, val";
+      $vals = "(" . $id . ", '" . $this->getValueHash($val). "', '" . mysql_real_escape_string($val, $con) . "')";
+    }
+    else {
+      $cols = "id, val";
+      $vals = "(" . $id . ", '" . mysql_real_escape_string($val, $con) . "')";
+    }
+    if (!isset($this->sql_buffers[$tbl])) {
+      $this->sql_buffers[$tbl] = '';
+      $sql = "INSERT IGNORE INTO " . $this->store->getTablePrefix() . $tbl . "(" . $cols . ") VALUES ";
+    }
+    else {
+      $sql = ", ";
+    }
+    $sql .= $vals;
+    $this->sql_buffers[$tbl] .= $sql;
+  }
+  
+  /*  */
+
+  function checkSQLBuffers($force_write = 0, $reset_id_buffers = 0, $refresh_lock = 0, $split_tables = 0) {
+    $con = $this->store->getDBCon();
+    if (!$this->keep_time_limit) @set_time_limit($this->v('time_limit', 60, $this->a));
+    foreach (array('triple', 'g2t', 'id2val', 's2val', 'o2val') as $tbl) {
+      $buffer_size = isset($this->sql_buffers[$tbl]) ? 1 : 0;
+      if ($buffer_size && $force_write) {
+        $t1 = ARC2::mtime();
+        $this->queryDB($this->sql_buffers[$tbl], $con);
+        /* table error */
+        if ($er = mysql_error($con)) {
+          $this->autoRepairTable($er, $con, $this->sql_buffers[$tbl]);
+        }
+        unset($this->sql_buffers[$tbl]);
+        if ($this->log_inserts) {
+          $t2 = ARC2::mtime();
+          $this->inserts[$tbl] = $this->v($tbl, 0, $this->inserts) + max(0, mysql_affected_rows($con));
+          $dur = round($t2 - $t1, 4);
+          $this->insert_times[$tbl] = isset($this->insert_times[$tbl]) ? $this->insert_times[$tbl] : array('min' => $dur, 'max' => $dur, 'sum' => $dur);
+          $this->insert_times[$tbl] = array('min' => min($dur, $this->insert_times[$tbl]['min']), 'max' => max($dur, $this->insert_times[$tbl]['max']), 'sum' => $dur + $this->insert_times[$tbl]['sum']);
+        }
+        /* reset term id buffers */
+        if ($reset_id_buffers) {
+          $this->term_ids = array();
+          $this->triple_ids = array();
+        }
+        /* refresh lock */
+        if ($refresh_lock) {
+          $this->store->releaseLock();
+          $this->has_lock = 0;
+          sleep(1);
+          if (!$this->store->getLock(5)) return $this->addError('Could not re-obtain lock in "checkSQLBuffers"');
+          $this->has_lock = 1;
+        }
+      }
+    }
+    return 1;
+  }
+
+  function autoRepairTable($er, $con, $sql = '') {
+    $this->addError('MySQL error: ' . $er . ' (' . $sql . ')');
+    if (preg_match('/Table \'[^\']+\/([a-z0-9\_\-]+)\' .*(crashed|repair)/i', $er, $m)) {
+      $rs = $this->queryDB('REPAIR TABLE ' . rawurlencode($m[1]), $con);
+      $msg = $rs ? mysql_fetch_array($rs) : array();
+      if ($this->v('Msg_type', 'error', $msg) == 'error') {
+        /* auto-reset */
+        if ($this->v('store_reset_on_table_crash', 0, $this->a)) {
+          $this->store->drop();
+          $this->store->setUp();
+        }
+        else {
+          $er = $this->v('Msg_text', 'unknown error', $msg);
+          $this->addError('Auto-repair failed on ' . rawurlencode($m[1]) . ': ' . $er);
+        }
+        //die("Fatal errors: \n" . print_r($this->getErrors(), 1));
+      }
+    }
+  }
+
+  /* speed log */
+  
+  function logInserts() {
+    $t_start = $this->t_start;
+    $t_prev = $this->t_prev;
+    $t_now = ARC2::mtime();
+    $tc_prev = $this->t_count_prev;
+    $tc_now = $this->t_count;
+    $tc_diff = $tc_now - $tc_prev;
+    
+    $dur_full = $t_now - $t_start;
+    $dur_diff = $t_now - $t_prev;
+
+    $speed_full = round($tc_now / $dur_full);
+    $speed_now = round($tc_diff / $dur_diff);
+
+    $r = $tc_diff . ' in ' . round($dur_diff, 5) . ' = ' . $speed_now . ' t/s  (' .$tc_now. ' in ' . round($dur_full, 5). ' = ' . $speed_full . ' t/s )'; 
+    $fp = @fopen("arc_insert_log.txt", "a");
+    @fwrite($fp, $r . "\r\n");
+    @fclose($fp);
+    
+    $this->t_prev = $t_now;
+    $this->t_count_prev = $tc_now;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,94 @@
+<?php
+/**
+ * ARC2 RDF Store Query Handler
+ *
+ * @author Benjamin Nowack
+ * @license <http://arc.semsol.org/license>
+ * @homepage <http://arc.semsol.org/>
+ * @package ARC2
+ * @version 2010-11-16
+*/
+
+ARC2::inc('Class');
+
+class ARC2_StoreQueryHandler extends ARC2_Class {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->xsd = 'http://www.w3.org/2001/XMLSchema#';
+    $this->allow_extension_functions = $this->v('store_allow_extension_functions', 1, $this->a);    
+    $this->keep_time_limit = $this->v('keep_time_limit', 0, $this->a);
+    $this->handler_type = '';
+  }
+
+  /*  */
+
+  function getTermID($val, $term = '') {
+    return $this->store->getTermID($val, $term);
+  }
+
+  function hasHashColumn($tbl) {
+    return $this->store->hasHashColumn($tbl);
+  }
+
+  function getValueHash($val) {
+    return $this->store->getValueHash($val);
+  }
+  
+  /*  */
+
+  function getTripleTable() {
+    $r = $this->store->getTablePrefix() . 'triple';
+    return $r;
+  }
+
+  /*  */
+
+  function createMergeTable() {
+    $split_ps = $this->store->getSetting('split_predicates', array());
+    if (!$split_ps) return 1;
+    $this->mrg_table_id = 'MRG_' . $this->store->getTablePrefix() . crc32(uniqid(rand()));
+    $con = $this->store->getDBCon();
+    $this->queryDB("FLUSH TABLES", $con);
+    $indexes = $this->v('store_indexes', array('sp (s,p)', 'os (o,s)', 'po (p,o)'), $this->a);
+    $index_code = $indexes ? 'KEY ' . join(', KEY ',  $indexes) . ', ' : '';
+    $prefix = $this->store->getTablePrefix();
+    $sql = "
+      CREATE TEMPORARY TABLE IF NOT EXISTS " . $prefix . "triple_all (
+        t mediumint UNSIGNED NOT NULL,
+        s mediumint UNSIGNED NOT NULL,
+        p mediumint UNSIGNED NOT NULL,
+        o mediumint UNSIGNED NOT NULL,
+        o_lang_dt mediumint UNSIGNED NOT NULL,
+        o_comp char(35) NOT NULL,                   /* normalized value for ORDER BY operations */
+        s_type tinyint(1) NOT NULL default 0,       /* uri/bnode => 0/1 */
+        o_type tinyint(1) NOT NULL default 0,       /* uri/bnode/literal => 0/1/2 */
+        misc tinyint(1) NOT NULL default 0,         /* temporary flags */
+        UNIQUE KEY (t), " . $index_code . " KEY (misc)
+      ) 
+    ";
+    $v = $this->store->getDBVersion();
+    $sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
+    $sql .= "=MERGE UNION=(" . $prefix . "triple" ;
+    foreach ($split_ps as $pos => $p) {
+      $sql .= ',' . $prefix . 'triple_' . abs(crc32($p));
+    }
+    $sql .= ")";
+    //$sql .= ($v >= '04-00-00') ? " CHARACTER SET utf8" : "";
+    //$sql .= ($v >= '04-01-00') ? " COLLATE utf8_unicode_ci" : "";
+    //echo $sql;
+    return $this->queryDB($sql, $con);
+  }
+
+  function dropMergeTable() {
+    return 1;
+    $sql = "DROP TABLE IF EXISTS " . $this->store->getTablePrefix() . "triple_all";
+    //echo $sql;
+    return $this->queryDB($sql, $this->store->getDBCon());
+  }
+  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreRDFXMLLoader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,32 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Store RDF/XML Loader
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('RDFXMLParser');
+
+class ARC2_StoreRDFXMLLoader extends ARC2_RDFXMLParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
+    $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
+    $this->t_count++;
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreRSSLoader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,32 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Store RSS(2) Loader
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('RSSParser');
+
+class ARC2_StoreRSSLoader extends ARC2_RSSParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function addT($t) {
+    $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
+    $this->t_count++;
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreSGAJSONLoader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Store SG API JSON Loader
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('SGAJSONParser');
+
+class ARC2_StoreSGAJSONLoader extends ARC2_SGAJSONParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function done() {
+    $this->extractRDF();
+  }
+  
+  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '') {
+    $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
+    $this->t_count++;
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreSPOGLoader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,38 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Store SPOG Loader
+author:   Morten H�ybye Frederiksen / Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('SPOGParser');
+
+class ARC2_StoreSPOGLoader extends ARC2_SPOGParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function addT($s, $p, $o, $s_type, $o_type, $o_dt = '', $o_lang = '', $g) {
+    if (!($s && $p && $o)) return 0;
+    if (!$g) $g = $this->caller->target_graph;
+    if ($this->caller->fixed_target_graph) $g = $this->caller->fixed_target_graph;
+    $prev_g = $this->caller->target_graph;
+    $this->caller->target_graph = $g;
+    $this->caller->addT($s, $p, $o, $s_type, $o_type, $o_dt, $o_lang);
+    $this->caller->target_graph = $prev_g;
+    $this->t_count++;
+  }
+  
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreSelectQueryHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1799 @@
+<?php
+/**
+ * ARC2 RDF Store SELECT Query Handler
+ *
+ * @author    Benjamin Nowack
+ * @license   http://arc.semsol.org/license
+ * @homepage  <http://arc.semsol.org/>
+ * @package   ARC2
+ * @version   2010-11-16
+ *
+*/
+
+ARC2::inc('StoreQueryHandler');
+
+class ARC2_StoreSelectQueryHandler extends ARC2_StoreQueryHandler {
+
+  function __construct($a, &$caller) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->store = $this->caller;
+    $con = $this->store->getDBCon();
+    $this->handler_type = 'select';
+    $this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
+    $this->cache_results = $this->v('store_cache_results', 0, $this->a);
+  }
+
+  /*  */
+
+  function runQuery($infos) {
+    $con = $this->store->getDBCon();
+    $rf = $this->v('result_format', '', $infos);
+    $this->infos = $infos;
+    $this->infos['null_vars'] = array();
+    $this->indexes = array();
+    $this->pattern_order_offset = 0;
+    $q_sql = $this->getSQL();
+
+    /* debug result formats */
+    if ($rf == 'sql') return $q_sql;
+    if ($rf == 'structure') return $this->infos;
+    if ($rf == 'index') return $this->indexes;
+    /* create intermediate results (ID-based) */
+    $tmp_tbl = $this->createTempTable($q_sql);
+    /* join values */
+    $r = $this->getFinalQueryResult($q_sql, $tmp_tbl);
+    /* remove intermediate results */
+    if (!$this->cache_results) {
+      $this->queryDB('DROP TABLE IF EXISTS ' . $tmp_tbl, $con);
+    }
+    return $r;
+  }
+
+  function getSQL() {
+    $r = '';
+    $nl = "\n";
+    $this->buildInitialIndexes();
+    foreach ($this->indexes as $i => $index) {
+      $this->index = array_merge($this->getEmptyIndex(), $index);
+      $this->analyzeIndex($this->getPattern('0'));
+      $sub_r = $this->getQuerySQL();
+      $r .= $r ? $nl . 'UNION' . $this->getDistinctSQL() . $nl : '';
+      $r .= $this->is_union_query ? '(' . $sub_r . ')' : $sub_r;
+      $this->indexes[$i] = $this->index;
+    }
+    $r .= $this->is_union_query ? $this->getLIMITSQL() : '';
+    if ($this->v('order_infos', 0, $this->infos['query'])) {
+      $r = preg_replace('/SELECT(\s+DISTINCT)?\s*/', 'SELECT\\1 NULL AS `_pos_`, ', $r);
+    }
+    $pd_count = $this->problematicDependencies();
+    if ($pd_count) {
+      /* re-arranging the patterns sometimes reduces the LEFT JOIN dependencies */
+      $set_sql = 0;
+      if (!$this->pattern_order_offset) $set_sql = 1;
+      if (!$set_sql && ($pd_count < $this->opt_sql_pd_count)) $set_sql = 1;
+      if (!$set_sql && ($pd_count == $this->opt_sql_pd_count) && (strlen($r) < strlen($this->opt_sql))) $set_sql = 1;
+      if ($set_sql) {
+        $this->opt_sql = $r;
+        $this->opt_sql_pd_count = $pd_count;
+      }
+      $this->pattern_order_offset++;
+      if ($this->pattern_order_offset > 5) {
+        return $this->opt_sql;
+      }
+      return $this->getSQL();
+    }
+    return $r;
+  }
+
+  function buildInitialIndexes() {
+    $this->dependency_log = array();
+    $this->index = $this->getEmptyIndex();
+    $this->buildIndex($this->infos['query']['pattern'], 0);
+    $tmp = $this->index;
+    $this->analyzeIndex($this->getPattern('0'));
+    $this->initial_index = $this->index;
+    $this->index = $tmp;
+    $this->is_union_query = $this->index['union_branches'] ? 1 : 0;
+    $this->indexes = $this->is_union_query ? $this->getUnionIndexes($this->index) : array($this->index);
+  }
+
+  function createTempTable($q_sql) {
+    $con = $this->store->getDBCon();
+    $v = $this->store->getDBVersion();
+    if ($this->cache_results) {
+      $tbl = $this->store->getTablePrefix() . 'Q' . md5($q_sql);
+    }
+    else {
+      $tbl = $this->store->getTablePrefix() . 'Q' . md5($q_sql . time() . uniqid(rand()));
+    }
+    if (strlen($tbl) > 64) $tbl = 'Q' . md5($tbl);
+    $tmp_sql = 'CREATE TEMPORARY TABLE ' . $tbl . ' ( ' . $this->getTempTableDef($tbl, $q_sql) . ') ';
+    $tmp_sql .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
+    $tmp_sql .= '=' . $this->engine_type;/* HEAP doesn't support AUTO_INCREMENT, and MySQL breaks on MEMORY sometimes */
+    if (!$this->queryDB($tmp_sql, $con) && !$this->queryDB(str_replace('CREATE TEMPORARY', 'CREATE', $tmp_sql), $con)) {
+      return $this->addError(mysql_error($con));
+    }
+    mysql_unbuffered_query('INSERT INTO ' . $tbl . ' ' . "\n" . $q_sql, $con);
+    if ($er = mysql_error($con)) $this->addError($er);
+    return $tbl;
+  }
+
+  function getEmptyIndex() {
+    return array(
+      'from' => array(),
+      'join' => array(),
+      'left_join' => array(),
+      'vars' => array(), 'graph_vars' => array(), 'graph_uris' => array(),
+      'bnodes' => array(),
+      'triple_patterns' => array(),
+      'sub_joins' => array(),
+      'constraints' => array(),
+      'union_branches'=> array(),
+      'patterns' => array(),
+      'havings' => array()
+    );
+  }
+
+  function getTempTableDef($tmp_tbl, $q_sql) {
+    $col_part = preg_replace('/^SELECT\s*(DISTINCT)?(.*)FROM.*$/s', '\\2', $q_sql);
+    $parts = explode(',', $col_part);
+    $has_order_infos = $this->v('order_infos', 0, $this->infos['query']);
+    $r = '';
+    $added = array();
+    foreach ($parts as $part) {
+      if (preg_match('/\.?(.+)\s+AS\s+`(.+)`/U', trim($part), $m) && !isset($added[$m[2]])) {
+        $col = $m[1];
+        $alias = $m[2];
+        if ($alias == '_pos_') continue;
+        $r .= $r ? ',' : '';
+        $r .= "\n `" . $alias . "` int UNSIGNED";
+        $added[$alias] = 1;
+      }
+    }
+    if ($has_order_infos) {
+      $r = "\n" . '`_pos_` mediumint NOT NULL AUTO_INCREMENT PRIMARY KEY, ' . $r;
+    }
+    return  $r ? $r . "\n" : ''; 
+  }
+    
+  function getFinalQueryResult($q_sql, $tmp_tbl) {
+    /* var names */
+    $vars = array();
+    $aggregate_vars = array();
+    foreach ($this->infos['query']['result_vars'] as $entry) {
+      if ($entry['aggregate']) {
+        $vars[] = $entry['alias'];
+        $aggregate_vars[] = $entry['alias'];
+      }
+      else {
+        $vars[] = $entry['var'];
+      }
+    }
+    /* result */
+    $r = array('variables' => $vars);
+    $v_sql = $this->getValueSQL($tmp_tbl, $q_sql);
+    //echo "\n\n" . $v_sql;
+    $t1 = ARC2::mtime();
+    $con = $this->store->getDBCon();
+    $rs = mysql_unbuffered_query($v_sql, $con);
+    if ($er = mysql_error($con)) {
+      $this->addError($er);
+    }
+    $t2 = ARC2::mtime();
+    $rows = array();
+    $types = array(0 => 'uri', 1 => 'bnode', 2 => 'literal');
+    if ($rs) {
+  		while ($pre_row = mysql_fetch_array($rs)) {
+        $row = array();
+        foreach ($vars as $var) {
+          if (isset($pre_row[$var])) {
+            $row[$var] = $pre_row[$var];
+            $row[$var . ' type'] = isset($pre_row[$var . ' type']) ? $types[$pre_row[$var . ' type']] : (in_array($var, $aggregate_vars) ? 'literal' : 'uri');
+            if (isset($pre_row[$var . ' lang_dt']) && ($lang_dt = $pre_row[$var . ' lang_dt'])) {
+              if (preg_match('/^([a-z]+(\-[a-z0-9]+)*)$/i', $lang_dt)) {
+                $row[$var . ' lang'] = $lang_dt;
+              }
+              else {
+                $row[$var . ' datatype'] = $lang_dt;
+              }
+            }
+          }
+        }
+        if ($row || !$vars) {
+          $rows[] = $row;
+        }
+      }
+    }
+    $r['rows'] = $rows;
+    return $r;
+  }
+  
+  /*  */
+  
+  function buildIndex($pattern, $id) {
+    $pattern['id'] = $id;
+    $type = $this->v('type', '', $pattern);
+    if (($type == 'filter') && $this->v('constraint', 0, $pattern)) {
+      $sub_pattern = $pattern['constraint'];
+      $sub_pattern['parent_id'] = $id;
+      $sub_id = $id . '_0';
+      $this->buildIndex($sub_pattern, $sub_id);
+      $pattern['constraint'] = $sub_id;
+    }
+    else {
+      $sub_patterns = $this->v('patterns', array(), $pattern);
+      $keys = array_keys($sub_patterns);
+      $spc = count($sub_patterns);
+      if (($spc > 4) && $this->pattern_order_offset) {
+        $keys = array();
+        for ($i = 0 ; $i < $spc; $i++) {
+          $keys[$i] = $i + $this->pattern_order_offset;
+          while ($keys[$i] >= $spc) $keys[$i] -= $spc;
+        }
+      }
+      foreach ($keys as $i => $key) {
+        $sub_pattern = $sub_patterns[$key];
+        $sub_pattern['parent_id'] = $id;
+        $sub_id = $id . '_' . $key;
+        $this->buildIndex($sub_pattern, $sub_id);
+        $pattern['patterns'][$i] = $sub_id;
+        if ($type == 'union') {
+          $this->index['union_branches'][] = $sub_id;
+        }
+      }
+    }
+    $this->index['patterns'][$id] = $pattern;
+  }
+  
+  /*  */
+
+  function analyzeIndex($pattern) {
+    $type = $this->v('type', '', $pattern);
+    if (!$type) {
+      //echo '<!-- ' . var_export($this->infos, 1) . ' -->';
+      return false;
+    }
+    $type = $pattern['type'];
+    $id = $pattern['id'];
+    /* triple */
+    if ($type == 'triple') {
+      foreach (array('s', 'p', 'o') as $term) {
+        if ($pattern[$term . '_type'] == 'var') {
+          $val = $pattern[$term];
+          $this->index['vars'][$val] = array_merge($this->v($val, array(), $this->index['vars']), array(array('table' => $pattern['id'], 'col' =>$term)));
+        }
+        if ($pattern[$term . '_type'] == 'bnode') {
+          $val = $pattern[$term];
+          $this->index['bnodes'][$val] = array_merge($this->v($val, array(), $this->index['bnodes']), array(array('table' => $pattern['id'], 'col' =>$term)));
+        }
+      }
+      $this->index['triple_patterns'][] = $pattern['id'];
+      /* joins */
+      if ($this->isOptionalPattern($id)) {
+        $this->index['left_join'][] = $id;
+      }
+      elseif (!$this->index['from']) {
+        $this->index['from'][] = $id;
+      }
+      elseif (!$this->getJoinInfos($id)) {
+        $this->index['from'][] = $id;
+      }
+      else {
+        $this->index['join'][] = $id;
+      }
+      /* graph infos, graph vars */
+      $this->index['patterns'][$id]['graph_infos'] = $this->getGraphInfos($id);
+      foreach ($this->index['patterns'][$id]['graph_infos'] as $info) {
+        if ($info['type'] == 'graph') {
+          if ($info['var']) {
+            $val = $info['var']['value'];
+            $this->index['graph_vars'][$val] = array_merge($this->v($val, array(), $this->index['graph_vars']), array(array('table' => $id)));
+          }
+          elseif ($info['uri']) {
+            $val = $info['uri'];
+            $this->index['graph_uris'][$val] = array_merge($this->v($val, array(), $this->index['graph_uris']), array(array('table' => $id)));
+          }
+        }
+      }
+    }
+    $sub_ids = $this->v('patterns', array(), $pattern);
+    foreach ($sub_ids as $sub_id) {
+      $this->analyzeIndex($this->getPattern($sub_id));
+    }
+  }
+  
+  /*  */
+
+  function getGraphInfos($id) {
+    $r = array();
+    if ($id) {
+      $pattern = $this->index['patterns'][$id];
+      $type = $pattern['type'];
+      /* graph */
+      if ($type == 'graph') {
+        $r[] = array('type' => 'graph', 'var' => $pattern['var'], 'uri' => $pattern['uri']);
+      }
+      $p_pattern = $this->index['patterns'][$pattern['parent_id']];
+      if (isset($p_pattern['graph_infos'])) {
+        return array_merge($p_pattern['graph_infos'], $r);
+      }
+      return array_merge($this->getGraphInfos($pattern['parent_id']), $r);
+    }
+    /* FROM / FROM NAMED */
+    else {
+      if (isset($this->infos['query']['dataset'])) {
+        foreach ($this->infos['query']['dataset'] as $set) {
+          $r[] = array_merge(array('type' => 'dataset'), $set);
+        }
+      }
+    }
+    return $r;
+  }
+  
+  /*  */
+
+  function getPattern($id) {
+    if (is_array($id)) {
+      return $id;
+    }
+    return $this->v($id, array(), $this->index['patterns']);
+  }
+
+  function getInitialPattern($id) {
+    return $this->v($id, array(), $this->initial_index['patterns']);
+  }
+
+  /*  */
+  
+  function getUnionIndexes($pre_index) {
+    $r = array();
+    $branches = array();
+    $min_depth = 1000;
+    /* only process branches with minimum depth */
+    foreach ($pre_index['union_branches'] as $id) {
+      $branches[$id] = count(preg_split('/\_/', $id));
+      $min_depth = min($min_depth, $branches[$id]);
+    }
+    foreach ($branches as $branch_id => $depth) {
+      if ($depth == $min_depth) {
+        $union_id = preg_replace('/\_[0-9]+$/', '', $branch_id);
+        $index = array('keeping' => $branch_id, 'union_branches' => array(), 'patterns' => $pre_index['patterns']);
+        $old_branches = $index['patterns'][$union_id]['patterns'];
+        $skip_id = ($old_branches[0] == $branch_id) ? $old_branches[1] : $old_branches[0];
+        $index['patterns'][$union_id]['type'] = 'group';
+        $index['patterns'][$union_id]['patterns'] = array($branch_id);
+        $has_sub_unions = 0;
+        foreach ($index['patterns'] as $pattern_id => $pattern) {
+          if (preg_match('/^' .$skip_id. '/', $pattern_id)) {
+             unset($index['patterns'][$pattern_id]);
+          }
+          elseif ($pattern['type'] == 'union') {
+            foreach ($pattern['patterns'] as $sub_union_branch_id) {
+              $index['union_branches'][] = $sub_union_branch_id;
+            }
+          }
+        }    
+        if ($index['union_branches']) {
+          $r = array_merge($r, $this->getUnionIndexes($index));
+        }
+        else {
+          $r[] = $index;
+        }
+      }
+    }
+    return $r;
+  }
+
+  /*  */
+
+  function isOptionalPattern($id) {
+    $pattern = $this->getPattern($id);
+    if ($this->v('type', '', $pattern) == 'optional') {
+      return 1;
+    }
+    if ($this->v('parent_id', '0', $pattern) == '0') {
+      return 0;
+    }
+    return $this->isOptionalPattern($pattern['parent_id']);
+  }
+
+  function getOptionalPattern($id) {
+    $pn = $this->getPattern($id);
+    do {
+      $pn = $this->getPattern($pn['parent_id']);
+    } while ($pn['parent_id'] && ($pn['type'] != 'optional'));
+    return $pn['id'];
+  }
+  
+  function sameOptional($id, $id2) {
+    return $this->getOptionalPattern($id) == $this->getOptionalPattern($id2);
+  }
+  
+  /*  */
+
+  function isUnionPattern($id) {
+    $pattern = $this->getPattern($id);
+    if ($this->v('type', '', $pattern) == 'union') {
+      return 1;
+    }
+    if ($this->v('parent_id', '0', $pattern) == '0') {
+      return 0;
+    }
+    return $this->isUnionPattern($pattern['parent_id']);
+  }
+  
+  /*  */
+
+  function getValueTable($col) {
+    return $this->store->getTablePrefix() . (preg_match('/^(s|o)$/', $col) ? $col . '2val' : 'id2val');
+  }
+  
+  function getGraphTable() {
+    return $this->store->getTablePrefix() . 'g2t';
+  }
+  
+  /*  */
+  
+  function getQuerySQL() {
+    $nl = "\n";
+    $where_sql = $this->getWHERESQL();  /* pre-fills $index['sub_joins'] $index['constraints'] */
+    $order_sql = $this->getORDERSQL();  /* pre-fills $index['sub_joins'] $index['constraints'] */
+    return '' .
+      ($this->is_union_query ? 'SELECT' : 'SELECT' . $this->getDistinctSQL()) . $nl .
+      $this->getResultVarsSQL() . $nl . /* fills $index['sub_joins'] */
+      $this->getFROMSQL() . 
+      $this->getAllJoinsSQL() . 
+      $this->getWHERESQL() . 
+      $this->getGROUPSQL() . 
+      $this->getORDERSQL() . 
+      ($this->is_union_query ? '' : $this->getLIMITSQL()) .
+      $nl .
+    '';
+  }
+
+  /*  */
+  
+  function getDistinctSQL() {
+    if ($this->is_union_query) {
+      return ($this->v('distinct', 0, $this->infos['query']) || $this->v('reduced', 0, $this->infos['query'])) ? '' : ' ALL';  
+    }
+    return ($this->v('distinct', 0, $this->infos['query']) || $this->v('reduced', 0, $this->infos['query'])) ? ' DISTINCT' : '';  
+  }
+
+  /*  */
+  
+  function getResultVarsSQL() {
+    $r = '';
+    $vars = $this->infos['query']['result_vars'];
+    $nl = "\n";
+    $added = array();
+    foreach ($vars as $var) {
+      $var_name = $var['var'];
+      $tbl_alias = '';
+      if ($tbl_infos = $this->getVarTableInfos($var_name, 0)) {
+        $tbl = $tbl_infos['table'];
+        $col = $tbl_infos['col'];
+        $tbl_alias = $tbl_infos['table_alias'];
+      }
+      elseif ($var_name == 1) {/* ASK query */
+        $r .= '1 AS `success`';
+      }
+      else {
+        $this->addError('Result variable "' .$var_name. '" not used in query.');
+      }
+      if ($tbl_alias) {
+        /* aggregate */
+        if ($var['aggregate']) {
+          $conv_code = '';
+          if (strtolower($var['aggregate']) != 'count') {
+            $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
+            $conv_code = '0 + ';
+          }
+          if (!isset($added[$var['alias']])) {
+            $r .= $r ? ',' . $nl . '  ' : '  ';
+            $distinct_code = (strtolower($var['aggregate']) == 'count') && $this->v('distinct', 0, $this->infos['query']) ? 'DISTINCT ' : '';
+            $r .= $var['aggregate'] . '(' . $conv_code . $distinct_code . $tbl_alias. ') AS `' . $var['alias'] . '`';
+            $added[$var['alias']] = 1;
+          }
+        }
+        /* normal var */
+        else {
+          if (!isset($added[$var_name])) {
+            $r .= $r ? ',' . $nl . '  ' : '  ';
+            $r .= $tbl_alias . ' AS `' . $var_name . '`';
+            $is_s = ($col == 's');
+            $is_p = ($col == 'p');
+            $is_o = ($col == 'o');
+            if ($tbl_alias == 'NULL') {
+              /* type / add in UNION queries? */
+              if ($is_s || $is_o) {
+                $r .= ', ' . $nl . '    NULL AS `' . $var_name . ' type`';
+              }
+              /* lang_dt / always add it in UNION queries, the var may be used as s/p/o */
+              if ($is_o || $this->is_union_query) {
+                $r .= ', ' . $nl . '    NULL AS `' . $var_name . ' lang_dt`';
+              }
+            }
+            else {
+              /* type */
+              if ($is_s || $is_o) {
+                $r .= ', ' . $nl . '    ' .$tbl_alias . '_type AS `' . $var_name . ' type`';
+              }
+              /* lang_dt / always add it in UNION queries, the var may be used as s/p/o */
+              if ($is_o) {
+                $r .= ', ' . $nl . '    ' .$tbl_alias . '_lang_dt AS `' . $var_name . ' lang_dt`';
+              }
+              elseif ($this->is_union_query) {
+                $r .= ', ' . $nl . '    NULL AS `' . $var_name . ' lang_dt`';
+              }
+            }
+            $added[$var_name] = 1;
+          }
+        }
+        if (!in_array($tbl_alias, $this->index['sub_joins'])) {
+          $this->index['sub_joins'][] = $tbl_alias;
+        }
+      }
+    }
+    return $r ? $r : '1 AS `success`';
+  }
+  
+  function getVarTableInfos($var, $ignore_initial_index = 1) {
+    if ($var == '*') {
+      return array('table' => '', 'col' => '', 'table_alias' => '*');
+    }
+    if ($infos = $this->v($var, 0, $this->index['vars'])) {
+      $infos[0]['table_alias'] = 'T_' . $infos[0]['table'] . '.' . $infos[0]['col'];
+      return $infos[0];
+    }
+    if ($infos = $this->v($var, 0, $this->index['graph_vars'])) {
+      $infos[0]['col'] = 'g';
+      $infos[0]['table_alias'] = 'G_' . $infos[0]['table'] . '.' . $infos[0]['col'];
+      return $infos[0];
+    }
+    if ($this->is_union_query && !$ignore_initial_index) {
+      if (($infos = $this->v($var, 0, $this->initial_index['vars'])) || ($infos = $this->v($var, 0, $this->initial_index['graph_vars']))) {
+        if (!in_array($var, $this->infos['null_vars'])) {
+          $this->infos['null_vars'][] = $var;
+        }
+        $infos[0]['table_alias'] = 'NULL';
+        $infos[0]['col'] = !isset($infos[0]['col']) ? '' : $infos[0]['col'];
+        return $infos[0];
+      }
+    }
+    return 0;
+  }
+  
+  /*  */
+  
+  function getFROMSQL() {
+    $from_ids = $this->index['from'];
+    $r = '';
+    foreach ($from_ids as $from_id) {
+      $r .= $r ? ', ' : '';
+      $r .= $this->getTripleTable($from_id) . ' T_' . $from_id;
+    }
+    /* MySQL 5 requires parentheses in case of multiple tables */
+    /* MySQL >5.5 (?) does not allow parentheses in case of a single table anymore! */
+    $r = (count($from_ids) > 1) ? '(' . $r . ')' : $r;
+    return $r ? 'FROM ' . $r : '';
+  }
+
+  /*  */
+  
+  function getOrderedJoinIDs() {
+    return array_merge($this->index['from'], $this->index['join'], $this->index['left_join']);
+  }
+
+  function getJoinInfos($id) {
+    $r = array();
+    $tbl_ids = $this->getOrderedJoinIDs();
+    $pattern = $this->getPattern($id);
+    foreach ($tbl_ids as $tbl_id) {
+      $tbl_pattern = $this->getPattern($tbl_id);
+      if ($tbl_id != $id) {
+        foreach (array('s', 'p', 'o') as $tbl_term) {
+          foreach (array('var', 'bnode', 'uri') as $term_type) {
+            if ($tbl_pattern[$tbl_term . '_type'] == $term_type) {
+              foreach (array('s', 'p', 'o') as $term) {
+                if (($pattern[$term . '_type'] == $term_type) && ($tbl_pattern[$tbl_term] == $pattern[$term])) {
+                  $r[] = array('term' => $term, 'join_tbl' => $tbl_id, 'join_term' => $tbl_term);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    return $r;
+  }
+  
+  function getAllJoinsSQL() {
+    $js = $this->getJoins();
+    $ljs = $this->getLeftJoins();
+    $entries = array_merge($js, $ljs);
+    $id2code = array();
+    foreach ($entries as $entry) {
+      if (preg_match('/([^\s]+) ON (.*)/s', $entry, $m)) {
+        $id2code[$m[1]] = $entry;
+      }
+    }
+    $deps = array();
+    foreach ($id2code as $id => $code) {
+      $deps[$id]['rank'] = 0;
+      foreach ($id2code as $other_id => $other_code) {
+        $deps[$id]['rank'] += ($id != $other_id) && preg_match('/' . $other_id . '/', $code) ? 1 : 0;
+        $deps[$id][$other_id] = ($id != $other_id) && preg_match('/' . $other_id . '/', $code) ? 1 : 0;
+      }
+    }
+    $r = '';
+    do {
+      /* get next 0-rank */
+      $next_id = 0;
+      foreach ($deps as $id => $infos) {
+        if ($infos['rank'] == 0) {
+          $next_id = $id;
+          break;
+        }
+      }
+      if ($next_id) {
+        $r .= "\n" . $id2code[$next_id];
+        unset($deps[$next_id]);
+        foreach ($deps as $id => $infos) {
+          $deps[$id]['rank'] = 0;
+          unset($deps[$id][$next_id]);
+          foreach ($infos as $k => $v) {
+            if (!in_array($k, array('rank', $next_id))) {
+              $deps[$id]['rank'] += $v;
+              $deps[$id][$k] = $v;
+            }
+          }
+        }
+      }
+    }
+    while ($next_id);
+    if ($deps) {
+      $this->addError('Not all patterns could be rewritten to SQL JOINs');
+    }
+    return $r;
+  }
+  
+  function getJoins() {
+    $r = array();
+    $nl = "\n";
+    foreach ($this->index['join'] as $id) {
+      $sub_r = $this->getJoinConditionSQL($id);
+      $r[] = 'JOIN ' . $this->getTripleTable($id) . ' T_' . $id . ' ON (' . $sub_r . $nl . ')';
+    }
+    foreach (array_merge($this->index['from'], $this->index['join']) as $id) {
+      if ($sub_r = $this->getRequiredSubJoinSQL($id)) {
+        $r[] = $sub_r;
+      }
+    }
+    return $r;
+  }
+  
+  function getLeftJoins() {
+    $r = array();
+    $nl = "\n";
+    foreach ($this->index['left_join'] as $id) {
+      $sub_r = $this->getJoinConditionSQL($id);
+      $r[] = 'LEFT JOIN ' . $this->getTripleTable($id) . ' T_' . $id . ' ON (' . $sub_r . $nl . ')';
+    }
+    foreach ($this->index['left_join'] as $id) {
+      if ($sub_r = $this->getRequiredSubJoinSQL($id, 'LEFT')) {
+        $r[] = $sub_r;
+      }
+    }
+    return $r;
+  }
+  
+  function getJoinConditionSQL($id) {
+    $r = '';
+    $nl = "\n";
+    $infos = $this->getJoinInfos($id);
+    $pattern = $this->getPattern($id);
+    
+    $tbl = 'T_' . $id;
+    /* core dependency */
+    $d_tbls = $this->getDependentJoins($id);
+    foreach ($d_tbls as $d_tbl) {
+      if (preg_match('/^T_([0-9\_]+)\.[spo]+/', $d_tbl, $m) && ($m[1] != $id)) {
+        if ($this->isJoinedBefore($m[1], $id) && !in_array($m[1], array_merge($this->index['from'], $this->index['join']))) {
+          $r .= $r ? $nl . '  AND ' : $nl . '  ';
+          $r .= '(' . $d_tbl . ' IS NOT NULL)';
+        }
+        $this->logDependency($id, $d_tbl);
+      }
+    }
+    /* triple-based join info */
+    foreach ($infos as $info) {
+      if ($this->isJoinedBefore($info['join_tbl'], $id) && $this->joinDependsOn($id, $info['join_tbl'])) {
+        $r .= $r ? $nl . '  AND ' : $nl . '  ';
+        $r .= '(' . $tbl . '.' . $info['term'] . ' = T_' . $info['join_tbl'] . '.' . $info['join_term'] . ')';
+      }
+    }
+    /* filters etc */
+    if ($sub_r = $this->getPatternSQL($pattern, 'join__T_' . $id)) {
+      $r .= $r ? $nl . '  AND ' . $sub_r  : $nl . '  ' . '(' . $sub_r . ')';
+    }
+    return $r;
+  }
+
+  /**
+   * A log of identified table join dependencies in getJoinConditionSQL
+   *
+  */
+
+  function logDependency($id, $tbl) {
+    if (!isset($this->dependency_log[$id])) $this->dependency_log[$id] = array();
+    if (!in_array($tbl, $this->dependency_log[$id])) {
+      $this->dependency_log[$id][] = $tbl;
+    }
+  }
+
+  /**
+   * checks whether entries in the dependecy log could perhaps be optimized
+   * (triggers re-ordering of patterns
+  */
+
+  function problematicDependencies() {
+    foreach ($this->dependency_log as $id => $tbls) {
+      if (count($tbls) > 1) return count($tbls);
+    }
+    return 0;
+  }
+  
+  function isJoinedBefore($tbl_1, $tbl_2) {
+    $tbl_ids = $this->getOrderedJoinIDs();
+    foreach ($tbl_ids as $id) {
+      if ($id == $tbl_1) {
+        return 1;
+      }
+      if ($id == $tbl_2) {
+        return 0;
+      }
+    }
+  }
+  
+  function joinDependsOn($id, $id2) {
+    if (in_array($id2, array_merge($this->index['from'], $this->index['join']))) {
+      return 1;
+    }
+    $d_tbls = $this->getDependentJoins($id2);
+    //echo $id . ' :: ' . $id2 . '=>' . print_r($d_tbls, 1);
+    foreach ($d_tbls as $d_tbl) {
+      if (preg_match('/^T_' .$id. '\./', $d_tbl)) {
+        return 1;
+      }
+    }
+    return 0;
+  }
+  
+  function getDependentJoins($id) {
+    $r = array();
+    /* sub joins */
+    foreach ($this->index['sub_joins'] as $alias) {
+      if (preg_match('/^(T|V|G)_' . $id . '/', $alias)) {
+        $r[] = $alias;
+      }
+    }
+    /* siblings in shared optional */
+    $o_id = $this->getOptionalPattern($id);
+    foreach ($this->index['sub_joins'] as $alias) {
+      if (preg_match('/^(T|V|G)_' . $o_id . '/', $alias) && !in_array($alias, $r)) {
+        $r[] = $alias;
+      }
+    }
+    foreach ($this->index['left_join'] as $alias) {
+      if (preg_match('/^' . $o_id . '/', $alias) && !in_array($alias, $r)) {
+        $r[] = 'T_' . $alias . '.s';
+      }
+    }
+    return $r;
+  }
+  
+  /*  */
+  
+  function getRequiredSubJoinSQL($id, $prefix = '') {/* id is a triple pattern id. Optional FILTERS and GRAPHs are getting added to the join directly */
+    $nl = "\n";
+    $r = '';
+    foreach ($this->index['sub_joins'] as $alias) {
+      if (preg_match('/^V_' . $id . '_([a-z\_]+)\.val$/', $alias, $m)) {
+        $col = $m[1];
+        $sub_r = '';
+        if ($this->isOptionalPattern($id)) {
+          $pattern = $this->getPattern($id);
+          do {
+            $pattern = $this->getPattern($pattern['parent_id']);
+          } while ($pattern['parent_id'] && ($pattern['type'] != 'optional'));
+          $sub_r = $this->getPatternSQL($pattern, 'sub_join__V_' . $id);
+        }
+        $sub_r = $sub_r ? $nl . '  AND (' . $sub_r . ')' : '';
+        /* lang dt only on literals */
+        if ($col == 'o_lang_dt') {
+          $sub_sub_r = 'T_' . $id . '.o_type = 2'; 
+          $sub_r .= $nl . '  AND (' . $sub_sub_r . ')';
+        }
+        //$cur_prefix = $prefix ? $prefix . ' ' : 'STRAIGHT_';
+        $cur_prefix = $prefix ? $prefix . ' ' : '';
+        if ($col == 'g') {
+          $r .= trim($cur_prefix . 'JOIN '. $this->getValueTable($col) . ' V_' .$id . '_' . $col. ' ON (' .$nl. '  (G_' . $id . '.' . $col. ' = V_' . $id. '_' . $col. '.id) ' . $sub_r . $nl . ')');
+        }
+        else {
+          $r .= trim($cur_prefix . 'JOIN '. $this->getValueTable($col) . ' V_' .$id . '_' . $col. ' ON (' .$nl. '  (T_' . $id . '.' . $col. ' = V_' . $id. '_' . $col. '.id) ' . $sub_r . $nl . ')');
+        }
+      }
+      elseif (preg_match('/^G_' . $id . '\.g$/', $alias, $m)) {
+        $pattern = $this->getPattern($id);
+        $sub_r = $this->getPatternSQL($pattern, 'graph_sub_join__G_' . $id);
+        $sub_r = $sub_r ? $nl . '  AND ' . $sub_r : '';
+        /* dataset restrictions */
+        $gi = $this->getGraphInfos($id);
+        $sub_sub_r = '';
+        $added_gts = array();
+        foreach ($gi as $set) {
+          if (isset($set['graph']) && !in_array($set['graph'], $added_gts)) {
+            $sub_sub_r .= $sub_sub_r !== '' ? ',' : '';
+            $sub_sub_r .= $this->getTermID($set['graph'], 'g'); 
+            $added_gts[] = $set['graph'];
+          }
+        }
+        $sub_r .= ($sub_sub_r !== '') ? $nl . ' AND (G_' . $id . '.g IN (' . $sub_sub_r . '))' : ''; // /* ' . str_replace('#' , '::', $set['graph']) . ' */';
+        /* other graph join conditions */
+        foreach ($this->index['graph_vars'] as $var => $occurs) {
+          $occur_tbls = array();
+          foreach ($occurs as $occur) {
+            $occur_tbls[] = $occur['table'];
+            if ($occur['table'] == $id) break;
+          }
+          foreach($occur_tbls as $tbl) {
+            if (($tbl != $id) && in_array($id, $occur_tbls) && $this->isJoinedBefore($tbl, $id)) {
+              $sub_r .= $nl . '  AND (G_' .$id. '.g = G_' .$tbl. '.g)'; 
+            }
+          }
+        }
+        //$cur_prefix = $prefix ? $prefix . ' ' : 'STRAIGHT_';
+        $cur_prefix = $prefix ? $prefix . ' ' : '';
+        $r .= trim($cur_prefix . 'JOIN '. $this->getGraphTable() . ' G_' .$id . ' ON (' .$nl. '  (T_' . $id . '.t = G_' .$id. '.t)' . $sub_r . $nl . ')');
+      }
+    }
+    return $r;
+  }
+
+  /*  */
+
+  function getWHERESQL() {
+    $r = '';
+    $nl = "\n";
+    /* standard constraints */
+    $sub_r = $this->getPatternSQL($this->getPattern('0'), 'where');
+    /* additional constraints */
+    foreach ($this->index['from'] as $id) {
+      if ($sub_sub_r = $this->getConstraintSQL($id)) {
+        $sub_r .= $sub_r ? $nl . ' AND ' . $sub_sub_r : $sub_sub_r;
+      }
+    }
+    $r .= $sub_r ? $sub_r : '';
+    /* left join dependencies */
+    foreach ($this->index['left_join'] as $id) {
+      $d_joins = $this->getDependentJoins($id);
+      $added = array();
+      $d_aliases = array();
+      //echo $id . ' =>' . print_r($d_joins, 1);
+      $id_alias = 'T_' . $id . '.s';
+      foreach ($d_joins as $alias) {
+        if (preg_match('/^(T|V|G)_([0-9\_]+)(_[spo])?\.([a-z\_]+)/', $alias, $m)) {
+          $tbl_type = $m[1];
+          $tbl_pattern_id = $m[2];
+          $suffix = $m[3];
+          if (($tbl_pattern_id >= $id) && $this->sameOptional($tbl_pattern_id, $id)) {/* get rid of dependency permutations and nested optionals */
+            if (!in_array($tbl_type . '_' . $tbl_pattern_id . $suffix, $added)) {
+              $sub_r .= $sub_r ? ' AND ' : '';
+              $sub_r .= $alias . ' IS NULL';
+              $d_aliases[] = $alias;
+              $added[] = $tbl_type . '_' . $tbl_pattern_id . $suffix;
+              $id_alias = ($tbl_pattern_id == $id) ? $alias : $id_alias;
+            }
+          }
+        }
+      }
+      if (count($d_aliases) > 2) {/* @@todo fix this! */
+        $sub_r1 = '  /* '.$id_alias.' dependencies */';
+        $sub_r2 = '((' . $id_alias . ' IS NULL) OR (CONCAT(' . join(', ', $d_aliases) . ') IS NOT NULL))';
+        $r .= $r ? $nl . $sub_r1 . $nl . '  AND ' .$sub_r2 : $sub_r1 . $nl . $sub_r2;
+      }
+    }
+    return $r ? $nl . 'WHERE ' . $r : '';
+  }
+
+  /*  */
+  
+  function addConstraintSQLEntry($id, $sql) {
+    if (!isset($this->index['constraints'][$id])) {
+      $this->index['constraints'][$id] = array();
+    }
+    if (!in_array($sql, $this->index['constraints'][$id])) {
+      $this->index['constraints'][$id][] = $sql;
+    }
+  }
+  
+  function getConstraintSQL($id) {
+    $r = '';
+    $nl = "\n";
+    $constraints = $this->v($id, array(), $this->index['constraints']);
+    foreach ($constraints as $constraint) {
+      $r .= $r ? $nl . '  AND ' . $constraint : $constraint;
+    }
+    return $r;
+  }
+  
+  /*  */
+  
+  function getPatternSQL($pattern, $context) {
+    $type = $this->v('type', '', $pattern);
+    if (!$type) {
+      return '';
+    }
+    $m = 'get' . ucfirst($type) . 'PatternSQL';
+    return method_exists($this, $m) ? $this->$m($pattern, $context) : $this->getDefaultPatternSQL($pattern, $context);
+  }
+
+  function getDefaultPatternSQL($pattern, $context) {
+    $r = '';
+    $nl = "\n";
+    $sub_ids = $this->v('patterns', array(), $pattern);
+    foreach ($sub_ids as $sub_id) {
+      $sub_r = $this->getPatternSQL($this->getPattern($sub_id), $context);
+      $r .= ($r && $sub_r) ? $nl . '  AND (' . $sub_r . ')' : ($sub_r ? $sub_r  : '');
+    }
+    return $r ? $r : '';
+  }
+  
+  function getTriplePatternSQL($pattern, $context) {
+    $r = '';
+    $nl = "\n";
+    $id = $pattern['id'];
+    /* s p o */
+    $vars = array();
+    foreach (array('s', 'p', 'o') as $term) {
+      $sub_r = '';
+      $type = $pattern[$term . '_type'];
+      if ($type == 'uri') {
+        $term_id = $this->getTermID($pattern[$term], $term);
+        $sub_r = '(T_' . $id . '.' . $term . ' = ' . $term_id . ') /* ' . preg_replace('/[\#\*\>]/' , '::', $pattern[$term]) . ' */';
+      }
+      elseif ($type == 'literal') {
+        $term_id = $this->getTermID($pattern[$term], $term);
+        $sub_r = '(T_' . $id . '.' . $term . ' = ' . $term_id . ') /* ' . preg_replace('/[\#\n\*\>]/' , ' ', $pattern[$term]) . ' */';
+        if (($lang_dt = $this->v1($term . '_lang', '', $pattern)) || ($lang_dt = $this->v1($term . '_datatype', '', $pattern))) {
+          $lang_dt_id = $this->getTermID($lang_dt);
+          $sub_r .= $nl . '  AND (T_' . $id . '.' .$term. '_lang_dt = ' . $lang_dt_id . ') /* ' . preg_replace('/[\#\*\>]/' , '::', $lang_dt) . ' */';
+        }
+      }
+      elseif ($type == 'var') {
+        $val = $pattern[$term];
+        if (isset($vars[$val])) {/* repeated var in pattern */
+          $sub_r = '(T_' . $id . '.' . $term . '=' . 'T_' . $id . '.' . $vars[$val] . ')';
+        }
+        $vars[$val] = $term;
+        if ($infos = $this->v($val, 0, $this->index['graph_vars'])) {/* graph var in triple pattern */
+          $sub_r .= $sub_r ? $nl . '  AND ' : '';
+          $tbl = $infos[0]['table'];
+          $sub_r .= 'G_' . $tbl . '.g = T_' . $id . '.' . $term;
+        }
+      }
+      if ($sub_r) {
+        if (preg_match('/^(join)/', $context) || (preg_match('/^where/', $context) && in_array($id, $this->index['from']))) {
+          $r .= $r ? $nl . '  AND ' . $sub_r  : $sub_r;
+        }
+      }
+    }
+    /* g */
+    if ($infos = $pattern['graph_infos']) {
+      $tbl_alias = 'G_' . $id . '.g';
+      if (!in_array($tbl_alias, $this->index['sub_joins'])) {
+        $this->index['sub_joins'][] = $tbl_alias;
+      }
+      $sub_r = array('graph_var' => '', 'graph_uri' => '', 'from' => '', 'from_named' => '');
+      foreach ($infos as $info) {
+        $type = $info['type'];
+        if ($type == 'graph') {
+          if ($info['uri']) {
+            $term_id = $this->getTermID($info['uri'], 'g');
+            $sub_r['graph_uri'] .= $sub_r['graph_uri'] ? $nl . ' AND ' : '';
+            $sub_r['graph_uri'] .= '(' .$tbl_alias. ' = ' . $term_id . ') /* ' . preg_replace('/[\#\*\>]/' , '::', $info['uri']) . ' */';
+          }
+        }
+      }
+      if ($sub_r['from'] && $sub_r['from_named']) {
+        $sub_r['from_named'] = '';
+      }
+      if (!$sub_r['from'] && !$sub_r['from_named']) {
+        $sub_r['graph_var'] = '';
+      }
+      if (preg_match('/^(graph_sub_join)/', $context)) {
+        foreach ($sub_r as $g_type => $g_sql) {
+          if ($g_sql) {
+            $r .= $r ? $nl . '  AND ' . $g_sql  : $g_sql;
+          }
+        }
+      }
+    }
+    /* optional sibling filters? */
+    if (preg_match('/^(join|sub_join)/', $context) && $this->isOptionalPattern($id)) {
+      $o_pattern = $pattern;
+      do {
+        $o_pattern = $this->getPattern($o_pattern['parent_id']);
+      } while ($o_pattern['parent_id'] && ($o_pattern['type'] != 'optional'));
+      if ($sub_r = $this->getPatternSQL($o_pattern, 'optional_filter' . preg_replace('/^(.*)(__.*)$/', '\\2', $context))) {
+        $r .= $r ? $nl . '  AND ' . $sub_r  : $sub_r;
+      }
+      /* created constraints */
+      if ($sub_r = $this->getConstraintSQL($id)) {
+        $r .= $r ? $nl . '  AND ' . $sub_r  : $sub_r;
+      }
+    }
+    /* result */
+    if (preg_match('/^(where)/', $context) && $this->isOptionalPattern($id)) {
+      return '';
+    }
+    return $r;
+  }
+  
+  /*  */
+  
+  function getFilterPatternSQL($pattern, $context) {
+    $r = '';
+    $id = $pattern['id'];
+    $constraint_id = $this->v1('constraint', '', $pattern);
+    $constraint = $this->getPattern($constraint_id);
+    $constraint_type = $constraint['type'];
+    if ($constraint_type == 'built_in_call') {
+      $r = $this->getBuiltInCallSQL($constraint, $context);
+    }
+    elseif ($constraint_type == 'expression') {
+      $r = $this->getExpressionSQL($constraint, $context, '', 'filter');
+    }
+    else {
+      $m = 'get' . ucfirst($constraint_type) . 'ExpressionSQL';
+      if (method_exists($this, $m)) {
+        $r = $this->$m($constraint, $context, '', 'filter');
+      }
+    }
+    if ($this->isOptionalPattern($id) && !preg_match('/^(join|optional_filter)/', $context)) {
+      return '';
+    }
+    /* unconnected vars in FILTERs eval to false */
+    $sub_r = $this->hasUnconnectedFilterVars($id);
+    if ($sub_r) {
+      if ($sub_r == 'alias') {
+        if (!in_array($r, $this->index['havings'])) $this->index['havings'][] = $r;
+        return '';
+      }
+      elseif (preg_match('/^T([^\s]+\.)g (.*)$/s', $r, $m)) {/* graph filter */
+        return 'G' . $m[1] . 't ' . $m[2];
+      }
+      elseif (preg_match('/^\(*V[^\s]+_g\.val .*$/s', $r, $m)) {/* graph value filter, @@improveMe */
+        //return $r;
+      }
+      else {
+        return 'FALSE';
+      }
+    }
+    /* some really ugly tweaks */
+    /* empty language filter: FILTER ( lang(?v) = '' ) */
+    $r = preg_replace('/\(\/\* language call \*\/ ([^\s]+) = ""\)/s', '((\\1 = "") OR (\\1 LIKE "%:%"))', $r);
+    return $r;
+  }
+  
+  /**
+   * Checks if vars in the given (filter) pattern are used within the filter's scope.
+   */
+  
+  function hasUnconnectedFilterVars($filter_pattern_id) {
+    $scope_id = $this->getFilterScope($filter_pattern_id);
+    $vars = $this->getFilterVars($filter_pattern_id);
+    $r = 0;
+    foreach ($vars as $var_name) {
+      if ($this->isUsedTripleVar($var_name, $scope_id)) continue;
+      if ($this->isAliasVar($var_name)) {
+        $r = 'alias';
+        break;
+      }
+      $r = 1;
+      break;
+    }
+    return $r;
+  }
+
+  /**
+   * Returns the given filter pattern's scope (the id of the parent group pattern).
+   */
+
+  function getFilterScope($filter_pattern_id) {
+    $patterns = $this->initial_index['patterns'];
+    $r = '';
+    foreach ($patterns as $id => $p) {
+      /* the id has to be sub-part of the given filter id */
+      if (!preg_match('/^' . $id . '.+/', $filter_pattern_id)) continue;
+      /* we are looking for a group or union */
+      if (!preg_match('/^(group|union)$/', $p['type'])) continue;
+      /* we are looking for the longest/deepest match */
+      if (strlen($id) > strlen($r)) $r = $id;
+    }
+    return $r;
+  }
+
+  /**
+   * Builds a list of vars used in the given (filter) pattern.
+   */
+
+  function getFilterVars($filter_pattern_id) {
+    $r = array();
+    $patterns = $this->initial_index['patterns'];
+    /* find vars in the given filter (i.e. the given id is part of their pattern id) */
+    foreach ($patterns as $id => $p) {
+      if (!preg_match('/^' . $filter_pattern_id . '.+/', $id)) continue;
+      $var_name = '';
+      if ($p['type'] == 'var') {
+        $var_name = $p['value'];
+      }
+      elseif (($p['type'] == 'built_in_call') && ($p['call'] == 'bound')) {
+        $var_name = $p['args'][0]['value'];
+      }
+      if ($var_name && !in_array($var_name, $r)) {
+        $r[] = $var_name;
+      }
+    }
+    return $r;
+  }
+
+  /**
+   * Checks if $var_name appears as result projection alias.
+   */
+
+  function isAliasVar($var_name) {
+    foreach ($this->infos['query']['result_vars'] as $r_var) {
+      if ($r_var['alias'] == $var_name) return 1;
+    }
+    return 0;
+  }
+
+  /**
+   * Checks if $var_name is used in a triple pattern in the given scope
+   */
+
+  function isUsedTripleVar($var_name, $scope_id = '0') {
+    $patterns = $this->initial_index['patterns'];
+    foreach ($patterns as $id => $p) {
+      if ($p['type'] != 'triple') continue;
+      if (!preg_match('/^' . $scope_id . '.+/', $id)) continue;
+      foreach (array('s', 'p', 'o') as $term) {
+        if ($p[$term . '_type'] != 'var') continue;
+        if ($p[$term] == $var_name) return 1;
+      }
+    }
+  }
+
+  /*  */
+
+  function getExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
+    $r = '';
+    $nl = "\n";
+    $type = $this->v1('type', '', $pattern);
+    $sub_type = $this->v1('sub_type', $type, $pattern);
+    if (preg_match('/^(and|or)$/', $sub_type)) {
+      foreach ($pattern['patterns'] as $sub_id) {
+        $sub_pattern = $this->getPattern($sub_id);
+        $sub_pattern_type = $sub_pattern['type'];
+        if ($sub_pattern_type == 'built_in_call') {
+          $sub_r = $this->getBuiltInCallSQL($sub_pattern, $context, '', $parent_type);
+        }
+        else {
+          $sub_r = $this->getExpressionSQL($sub_pattern, $context, '', $parent_type);
+        }
+        if ($sub_r) {
+          $r .= $r ? ' ' . strtoupper($sub_type). ' (' .$sub_r. ')' : '(' . $sub_r . ')';
+        }
+      }
+    }
+    elseif ($sub_type == 'built_in_call') {
+      $r = $this->getBuiltInCallSQL($pattern, $context, $val_type, $parent_type);
+    }
+    elseif (preg_match('/literal/', $sub_type)) {
+      $r = $this->getLiteralExpressionSQL($pattern, $context, $val_type, $parent_type);
+    }
+    elseif ($sub_type) {
+      $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
+      if (method_exists($this, $m)) {
+        $r = $this->$m($pattern, $context, '', $parent_type);
+      }
+    }
+    /* skip expressions that reference non-yet-joined tables */
+    if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
+      $context_pattern_id = $m[2];
+      $context_table_type = $m[1];
+      if (preg_match_all('/((T|V|G)(\_[0-9])+)/', $r, $m)) {
+        $aliases = $m[1];
+        $keep = 1;
+        foreach ($aliases as $alias) {
+          if (preg_match('/(T|V|G)_(.*)$/', $alias, $m)) {
+            $tbl_type = $m[1];
+            $tbl = $m[2];
+            if (!$this->isJoinedBefore($tbl, $context_pattern_id)) {
+              $keep = 0;
+            }
+            elseif (($context_pattern_id == $tbl) && preg_match('/(TV)/', $context_table_type . $tbl_type)) {
+              $keep = 0;
+            }
+          }
+        }
+        $r = $keep ? $r : '';
+      }
+    }
+    return $r ? '(' . $r . ')' : $r;
+  }
+  
+  function detectExpressionValueType($pattern_ids) {
+    foreach ($pattern_ids as $id) {
+      $pattern = $this->getPattern($id);
+      $type = $this->v('type', '', $pattern);
+      if (($type == 'literal') && isset($pattern['datatype'])) {
+        if (in_array($pattern['datatype'], array($this->xsd . 'integer', $this->xsd . 'float', $this->xsd . 'double'))) {
+          return 'numeric';
+        }
+      }
+    }
+    return '';
+  }
+
+  /*  */
+
+  function getRelationalExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
+    $r = '';
+    $val_type = $this->detectExpressionValueType($pattern['patterns']);
+    $op = $pattern['operator'];
+    foreach ($pattern['patterns'] as $sub_id) {
+      $sub_pattern = $this->getPattern($sub_id);
+      $sub_pattern['parent_op'] = $op;
+      $sub_type = $sub_pattern['type'];
+      $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
+      $m = str_replace('ExpressionExpression', 'Expression', $m);
+      $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'relational') : '';
+      $r .= $r ? ' ' . $op . ' ' . $sub_r : $sub_r;
+    }
+    return $r ? '(' . $r . ')' : $r;
+  }
+
+  function getAdditiveExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
+    $r = '';
+    $val_type = $this->detectExpressionValueType($pattern['patterns']);
+    foreach ($pattern['patterns'] as $sub_id) {
+      $sub_pattern = $this->getPattern($sub_id);
+      $sub_type = $this->v('type', '', $sub_pattern);
+      $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
+      $m = str_replace('ExpressionExpression', 'Expression', $m);
+      $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'additive') : '';
+      $r .= $r ? ' ' . $sub_r : $sub_r;
+    }
+    return $r;
+  }
+
+  function getMultiplicativeExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
+    $r = '';
+    $val_type = $this->detectExpressionValueType($pattern['patterns']);
+    foreach ($pattern['patterns'] as $sub_id) {
+      $sub_pattern = $this->getPattern($sub_id);
+      $sub_type = $sub_pattern['type'];
+      $m = ($sub_type == 'built_in_call') ? 'getBuiltInCallSQL' : 'get' . ucfirst($sub_type) . 'ExpressionSQL';
+      $m = str_replace('ExpressionExpression', 'Expression', $m);
+      $sub_r = method_exists($this, $m) ? $this->$m($sub_pattern, $context, $val_type, 'multiplicative') : '';
+      $r .= $r ? ' ' . $sub_r : $sub_r;
+    }
+    return $r;
+  }
+
+  /*  */
+
+  function getVarExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
+    $var = $pattern['value'];
+    $info = $this->getVarTableInfos($var);
+    if (!$tbl = $info['table']) {
+      /* might be an aggregate var */
+      $vars = $this->infos['query']['result_vars'];
+      foreach ($vars as $test_var) {
+        if ($test_var['alias'] == $pattern['value']) {
+          return '`' . $pattern['value'] . '`';
+        }
+      }
+      return '';
+    }
+    $col = $info['col'];
+    if (($context == 'order') && ($col == 'o')) {
+      $tbl_alias = 'T_' . $tbl . '.o_comp';
+    }
+    elseif ($context == 'sameterm') {
+      $tbl_alias = 'T_' . $tbl . '.' . $col;
+    }
+    elseif (($parent_type == 'relational') && ($col == 'o') && (preg_match('/[\<\>]/', $this->v('parent_op', '', $pattern)))) {
+      $tbl_alias = 'T_' . $tbl . '.o_comp';
+    }
+    else {
+      $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
+      if (!in_array($tbl_alias, $this->index['sub_joins'])) {
+        $this->index['sub_joins'][] = $tbl_alias;
+      }
+    }
+    $op = $this->v('operator', '', $pattern);
+    if (preg_match('/^(filter|and)/', $parent_type)) {
+      if ($op == '!') {
+        $r = '(((' . $tbl_alias . ' = 0) AND (CONCAT("1", ' . $tbl_alias . ') != 1))'; /* 0 and no string */
+        $r .= ' OR (' . $tbl_alias . ' IN ("", "false")))'; /* or "", or "false" */
+      }
+      else {
+        $r = '((' . $tbl_alias . ' != 0)'; /* not null */
+        $r .= ' OR ((CONCAT("1", ' . $tbl_alias . ') = 1) AND (' . $tbl_alias . ' NOT IN ("", "false"))))'; /* string, and not "" or "false" */
+      }
+    }
+    else {
+      $r = trim($op . ' ' . $tbl_alias);
+      if ($val_type == 'numeric') {
+        if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
+          $context_pattern_id = $m[2];
+          $context_table_type = $m[1];
+        }
+        else {
+          $context_pattern_id = $pattern['id'];
+          $context_table_type = 'T';
+        }
+        if ($this->isJoinedBefore($tbl, $context_pattern_id)) {
+          $add = ($tbl != $context_pattern_id) ? 1 : 0;
+          $add = (!$add && ($context_table_type == 'V')) ? 1 : 0;
+          if ($add) {
+            $this->addConstraintSQLEntry($context_pattern_id, '(' .$r. ' = "0" OR ' . $r . '*1.0 != 0)');
+          }
+        }
+      }
+    }
+    return $r;
+  }
+  
+  /*  */
+
+  function getUriExpressionSQL($pattern, $context, $val_type = '') {
+    $val = $pattern['uri'];
+    $r = $pattern['operator'];
+    $r .= is_numeric($val) ? ' ' . $val : ' "' . mysql_real_escape_string($val, $this->store->getDBCon()) . '"';
+    return $r;
+  }
+  
+  /*  */
+
+  function getLiteralExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
+    $val = $pattern['value'];
+    $r = $pattern['operator'];
+    if (is_numeric($val) && $this->v('datatype', 0, $pattern)) {
+      $r .= ' ' . $val;
+    }
+    elseif (preg_match('/^(true|false)$/i', $val) && ($this->v1('datatype', '', $pattern) == 'http://www.w3.org/2001/XMLSchema#boolean')) {
+      $r .= ' ' . strtoupper($val);
+    }
+    elseif ($parent_type == 'regex') {
+      $sub_r = mysql_real_escape_string($val, $this->store->getDBCon());
+      $r .= ' "' . preg_replace('/\x5c\x5c/', '\\', $sub_r) . '"';
+    }
+    else {
+      $r .= ' "' . mysql_real_escape_string($val, $this->store->getDBCon()) . '"';
+    }
+    if (($lang_dt = $this->v1('lang', '', $pattern)) || ($lang_dt = $this->v1('datatype', '', $pattern))) {
+      /* try table/alias via var in siblings */
+      if ($var = $this->findSiblingVarExpression($pattern['id'])) {
+        if (isset($this->index['vars'][$var])) {
+          $infos = $this->index['vars'][$var];
+          foreach ($infos as $info) {
+            if ($info['col'] == 'o') {
+              $tbl = $info['table'];
+              $term_id = $this->getTermID($lang_dt);
+              if ($pattern['operator'] != '!=') {
+                if (preg_match('/__(T|V|G)_(.+)$/', $context, $m)) {
+                  $context_pattern_id = $m[2];
+                  $context_table_type = $m[1];
+                }
+                elseif ($context == 'where') {
+                  $context_pattern_id = $tbl;
+                }
+                else {
+                  $context_pattern_id = $pattern['id'];
+                }
+                if ($tbl == $context_pattern_id) {/* @todo better dependency check */
+                  if ($term_id || ($lang_dt != 'http://www.w3.org/2001/XMLSchema#integer')) {/* skip if simple int, but no id */
+                    $this->addConstraintSQLEntry($context_pattern_id, 'T_' . $tbl . '.o_lang_dt = ' . $term_id . ' /* ' . preg_replace('/[\#\*\>]/' , '::', $lang_dt) . ' */');
+                  }
+                }
+              }
+              break;
+            }
+          }
+        }
+      }
+    }
+    return trim($r);
+  }
+  
+  function findSiblingVarExpression($id) {
+    $pattern = $this->getPattern($id);
+    do {
+      $pattern = $this->getPattern($pattern['parent_id']);
+    } while ($pattern['parent_id'] && ($pattern['type'] != 'expression'));
+    $sub_patterns = $this->v('patterns', array(), $pattern);
+    foreach ($sub_patterns as $sub_id) {
+      $sub_pattern = $this->getPattern($sub_id);
+      if ($sub_pattern['type'] == 'var') {
+        return $sub_pattern['value'];
+      }
+    }
+    return '';
+  }
+  
+  /*  */
+
+  function getFunctionExpressionSQL($pattern, $context, $val_type = '', $parent_type = '') {
+    $fnc_uri = $pattern['uri'];
+    $op = $this->v('operator', '', $pattern);
+    if ($op) $op .= ' ';
+    if ($this->allow_extension_functions) {
+      /* mysql functions */
+      if (preg_match('/^http\:\/\/web\-semantics\.org\/ns\/mysql\/(.*)$/', $fnc_uri, $m)) {
+        $fnc_name = strtoupper($m[1]);
+        $sub_r = '';
+        foreach ($pattern['args'] as $arg) {
+          $sub_r .= $sub_r ? ', ' : '';
+          $sub_r .= $this->getExpressionSQL($arg, $context, $val_type, $parent_type);
+        }
+        return $op . $fnc_name . '(' . $sub_r . ')';
+      }
+      /* any other: ignore */
+    }
+    /* simple type conversions */
+    if (strpos($fnc_uri, 'http://www.w3.org/2001/XMLSchema#') === 0) {
+      return $op . $this->getExpressionSQL($pattern['args'][0], $context, $val_type, $parent_type);
+    }
+    return '';
+  }
+
+  /*  */
+
+  function getBuiltInCallSQL($pattern, $context) {
+    $call = $pattern['call'];
+    $m = 'get' . ucfirst($call) . 'CallSQL';
+    if (method_exists($this, $m)) {
+      return $this->$m($pattern, $context);
+    }
+    else {
+      $this->addError('Unknown built-in call "' . $call . '"');
+    }
+    return '';
+  }
+  
+  function getBoundCallSQL($pattern, $context) {
+    $r = '';
+    $var = $pattern['args'][0]['value'];
+    $info = $this->getVarTableInfos($var);
+    if (!$tbl = $info['table']) {
+      return '';
+    }
+    $col = $info['col'];
+    $tbl_alias = 'T_' . $tbl . '.' . $col;
+    if ($pattern['operator'] == '!') {
+      return $tbl_alias . ' IS NULL';
+    }
+    return $tbl_alias . ' IS NOT NULL';
+  }
+
+  function getHasTypeCallSQL($pattern, $context, $type) {
+    $r = '';
+    $var = $pattern['args'][0]['value'];
+    $info = $this->getVarTableInfos($var);
+    if (!$tbl = $info['table']) {
+      return '';
+    }
+    $col = $info['col'];
+    $tbl_alias = 'T_' . $tbl . '.' . $col . '_type';
+    return $tbl_alias . ' ' .$this->v('operator', '', $pattern) . '= ' . $type;
+  }
+
+  function getIsliteralCallSQL($pattern, $context) {
+    return $this->getHasTypeCallSQL($pattern, $context, 2);
+  }
+
+  function getIsblankCallSQL($pattern, $context) {
+    return $this->getHasTypeCallSQL($pattern, $context, 1);
+  }
+
+  function getIsiriCallSQL($pattern, $context) {
+    return $this->getHasTypeCallSQL($pattern, $context, 0);
+  }
+
+  function getIsuriCallSQL($pattern, $context) {
+    return $this->getHasTypeCallSQL($pattern, $context, 0);
+  }
+
+  function getStrCallSQL($pattern, $context) {
+    $sub_pattern = $pattern['args'][0];
+    $sub_type = $sub_pattern['type'];
+    $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
+    if (method_exists($this, $m)) {
+      return $this->$m($sub_pattern, $context);
+    }
+  }
+  
+  function getFunctionCallSQL($pattern, $context) {
+    $f_uri = $pattern['uri'];
+    if (preg_match('/(integer|double|float|string)$/', $f_uri)) {/* skip conversions */
+      $sub_pattern = $pattern['args'][0];
+      $sub_type = $sub_pattern['type'];
+      $m = 'get' . ucfirst($sub_type) . 'ExpressionSQL';
+      if (method_exists($this, $m)) {
+        return $this->$m($sub_pattern, $context);
+      }
+    }
+  }
+  
+  function getLangDatatypeCallSQL($pattern, $context) {
+    $r = '';
+    if (isset($pattern['patterns'])) { /* proceed with first argument only (assumed as base type for type promotion) */
+      $sub_pattern = array('args' => array($pattern['patterns'][0]));
+      return $this->getLangDatatypeCallSQL($sub_pattern, $context);
+    }
+    if (!isset($pattern['args'])) {
+      return 'FALSE';
+    }
+    $sub_type = $pattern['args'][0]['type'];
+    if ($sub_type != 'var') {
+      return $this->getLangDatatypeCallSQL($pattern['args'][0], $context);
+    }
+    $var = $pattern['args'][0]['value'];
+    $info = $this->getVarTableInfos($var);
+    if (!$tbl = $info['table']) {
+      return '';
+    }
+    $col = 'o_lang_dt';
+    $tbl_alias = 'V_' . $tbl . '_' . $col . '.val';
+    if (!in_array($tbl_alias, $this->index['sub_joins'])) {
+      $this->index['sub_joins'][] = $tbl_alias;
+    }
+    $op = $this->v('operator', '', $pattern);
+    $r = trim($op . ' ' . $tbl_alias);
+    return $r;
+  }
+
+  function getDatatypeCallSQL($pattern, $context) {
+    return '/* datatype call */ ' . $this->getLangDatatypeCallSQL($pattern, $context);
+  }
+
+  function getLangCallSQL($pattern, $context) {
+    return '/* language call */ ' . $this->getLangDatatypeCallSQL($pattern, $context);
+  }
+  
+  function getLangmatchesCallSQL($pattern, $context) {
+    if (count($pattern['args']) == 2) {
+      $arg_1 = $pattern['args'][0];
+      $arg_2 = $pattern['args'][1];
+      $sub_r_1 = $this->getBuiltInCallSQL($arg_1, $context);/* adds value join */
+      $sub_r_2 = $this->getExpressionSQL($arg_2, $context);
+      $op = $this->v('operator', '', $pattern);
+      if (preg_match('/^([\"\'])([^\'\"]+)/', $sub_r_2, $m)) {
+        if ($m[2] == '*') {
+          $r = ($op == '!') ? 'NOT (' . $sub_r_1 . ' REGEXP "^[a-zA-Z\-]+$"' . ')' : $sub_r_1 . ' REGEXP "^[a-zA-Z\-]+$"';
+        }
+        else {
+          $r = ($op == '!') ? $sub_r_1 . ' NOT LIKE ' . $m[1] . $m[2] . '%' . $m[1] : $sub_r_1 . ' LIKE ' . $m[1] . $m[2] . '%' . $m[1];
+        }
+      }
+      else {
+        $r = ($op == '!') ? $sub_r_1 . ' NOT LIKE CONCAT(' . $sub_r_2 . ', "%")' : $sub_r_1 . ' LIKE CONCAT(' . $sub_r_2 . ', "%")';
+      }
+      return $r;
+    }
+    return '';
+  }
+  
+  function getSametermCallSQL($pattern, $context) {
+    if (count($pattern['args']) == 2) {
+      $arg_1 = $pattern['args'][0];
+      $arg_2 = $pattern['args'][1];
+      $sub_r_1 = $this->getExpressionSQL($arg_1, 'sameterm');
+      $sub_r_2 = $this->getExpressionSQL($arg_2, 'sameterm');
+      $op = $this->v('operator', '', $pattern);
+      $r = $sub_r_1 . ' ' . $op . '= ' . $sub_r_2; 
+      return $r;
+    }
+    return '';
+  }
+  
+  function getRegexCallSQL($pattern, $context) {
+    $ac = count($pattern['args']);
+    if ($ac >= 2) {
+      foreach ($pattern['args'] as $i => $arg) {
+        $var = 'sub_r_' . ($i + 1);
+        $$var = $this->getExpressionSQL($arg, $context, '', 'regex');
+      }
+      $sub_r_3 = (isset($sub_r_3) && preg_match('/[\"\'](.+)[\"\']/', $sub_r_3, $m)) ? strtolower($m[1]) : '';
+      $op = ($this->v('operator', '', $pattern) == '!') ? ' NOT' : '';
+      if (!$sub_r_1 || !$sub_r_2) return '';
+      $is_simple_search = preg_match('/^[\(\"]+(\^)?([a-z0-9\_\-\s]+)(\$)?[\)\"]+$/is', $sub_r_2, $m);
+      $is_simple_search = preg_match('/^[\(\"]+(\^)?([^\\\*\[\]\}\{\(\)\"\'\?\+\.]+)(\$)?[\)\"]+$/is', $sub_r_2, $m);
+      $is_o_search = preg_match('/o\.val\)*$/', $sub_r_1);
+      /* fulltext search (may have "|") */
+      if ($is_simple_search && $is_o_search && !$op && (strlen($m[2]) > 8) && $this->store->hasFulltextIndex()) {
+        /* MATCH variations */
+        if (($val_parts = preg_split('/\|/', $m[2]))) {
+          return 'MATCH(' . trim($sub_r_1, '()') . ') AGAINST("' . join(' ', $val_parts) . '")';
+        }
+        else {
+          return 'MATCH(' . trim($sub_r_1, '()') . ') AGAINST("' . $m[2] . '")';
+        }
+      }
+      if (preg_match('/\|/', $sub_r_2)) $is_simple_search = 0;
+      /* LIKE */
+      if ($is_simple_search && ($sub_r_3 == 'i')) {
+        $sub_r_2 = $m[1] ? $m[2] : '%' . $m[2];
+        $sub_r_2 .= isset($m[3]) && $m[3] ? '' : '%';
+        return $sub_r_1 . $op . ' LIKE "' . $sub_r_2 . '"';
+      }
+      /* REGEXP */
+      $opt = ($sub_r_3 == 'i') ? '' : 'BINARY ';
+      return $sub_r_1 . $op . ' REGEXP ' . $opt . $sub_r_2;
+    }
+    return '';
+  }
+  
+  /*  */
+
+  function getGROUPSQL() {
+    $r = '';
+    $nl = "\n";
+    $infos = $this->v('group_infos', array(), $this->infos['query']);
+    foreach ($infos as $info) {
+      $var = $info['value'];
+      if ($tbl_infos = $this->getVarTableInfos($var, 0)) {
+        $tbl_alias = $tbl_infos['table_alias'];
+        $r .= $r ? ', ' : 'GROUP BY '; 
+        $r .= $tbl_alias;
+      }
+    }
+    $hr = '';
+    foreach ($this->index['havings'] as $having) {
+      $hr .= $hr ? ' AND' : ' HAVING';
+      $hr .= '(' . $having . ')';
+    }
+    $r .= $hr;
+    return $r ? $nl . $r : $r;
+  }
+  
+  /*  */
+  
+  function getORDERSQL() {
+    $r = '';
+    $nl = "\n";
+    $infos = $this->v('order_infos', array(), $this->infos['query']);
+    foreach ($infos as $info) {
+      $type = $info['type'];
+      $ms = array('expression' => 'getExpressionSQL', 'built_in_call' => 'getBuiltInCallSQL', 'function_call' => 'getFunctionCallSQL');
+      $m = isset($ms[$type]) ? $ms[$type] : 'get' . ucfirst($type) . 'ExpressionSQL';
+      if (method_exists($this, $m)) {
+        $sub_r = '(' . $this->$m($info, 'order') . ')';
+        $sub_r .= $this->v('direction', '', $info) == 'desc' ? ' DESC' : '';
+        $r .= $r ? ',' .$nl . $sub_r : $sub_r;
+      }
+    }
+    return $r ? $nl . 'ORDER BY ' . $r : '';
+  }
+  
+  /*  */
+  
+  function getLIMITSQL() {
+    $r = '';
+    $nl = "\n";
+    $limit = $this->v('limit', -1, $this->infos['query']);
+    $offset = $this->v('offset', -1, $this->infos['query']);
+    if ($limit != -1) {
+      $offset = ($offset == -1) ? 0 : mysql_real_escape_string($offset, $this->store->getDBCon());
+      $r = 'LIMIT ' . $offset . ',' . $limit; 
+    }
+    elseif ($offset != -1) {
+      $r = 'LIMIT ' . mysql_real_escape_string($offset, $this->store->getDBCon()) . ',999999999999'; /* mysql doesn't support stand-alone offsets .. */
+    }
+    return $r ? $nl . $r : '';
+  }
+
+  /*  */
+  
+  function getValueSQL($q_tbl, $q_sql) {
+    $r = '';
+    /* result vars */
+    $vars = $this->infos['query']['result_vars'];
+    $nl = "\n";
+    $v_tbls = array('JOIN' => array(), 'LEFT JOIN' => array());
+    $vc = 1;
+    foreach ($vars as $var) {
+      $var_name = $var['var'];
+      $r .= $r ? ',' . $nl . '  ' : '  ';
+      $col = '';
+      $tbl = '';
+      if ($var_name != '*') {
+        if (in_array($var_name, $this->infos['null_vars'])) {
+          if (isset($this->initial_index['vars'][$var_name])) {
+            $col = $this->initial_index['vars'][$var_name][0]['col'];
+            $tbl = $this->initial_index['vars'][$var_name][0]['table'];
+          }
+          if (isset($this->initial_index['graph_vars'][$var_name])) {
+            $col = 'g';
+            $tbl = $this->initial_index['graph_vars'][$var_name][0]['table'];
+          }
+        }
+        elseif (isset($this->index['vars'][$var_name])) {
+          $col = $this->index['vars'][$var_name][0]['col'];
+          $tbl = $this->index['vars'][$var_name][0]['table'];
+        }
+      }
+      if ($var['aggregate']) {
+        $r .= 'TMP.`' . $var['alias'] . '`';
+      }
+      else {
+        $join_type = in_array($tbl, array_merge($this->index['from'], $this->index['join'])) ? 'JOIN' : 'LEFT JOIN';/* val may be NULL */
+        $v_tbls[$join_type][] = array('t_col' => $col, 'q_col' => $var_name, 'vc' => $vc);
+        $r .= 'V' . $vc . '.val AS `' . $var_name . '`';
+        if (in_array($col, array('s', 'o'))) {
+          if (strpos($q_sql, '`' . $var_name . ' type`')) {
+            $r .= ', ' . $nl . '    TMP.`' . $var_name . ' type` AS `' . $var_name . ' type`';
+            //$r .= ', ' . $nl . '    CASE TMP.`' . $var_name . ' type` WHEN 2 THEN "literal" WHEN 1 THEN "bnode" ELSE "uri" END AS `' . $var_name . ' type`';
+          }
+          else {
+            $r .= ', ' . $nl . '    NULL AS `' . $var_name . ' type`';
+          }
+        }
+        $vc++;
+        if ($col == 'o') {
+          $v_tbls[$join_type][] = array('t_col' => 'id', 'q_col' => $var_name . ' lang_dt', 'vc' => $vc);
+          if (strpos($q_sql, '`' . $var_name . ' lang_dt`')) {
+            $r .= ', ' .$nl. '    V' . $vc . '.val AS `' . $var_name . ' lang_dt`';
+            $vc++;
+          }
+          else {
+            $r .= ', ' .$nl. '    NULL AS `' . $var_name . ' lang_dt`';
+          }
+        }
+      }
+    }
+    if (!$r) $r = '*';
+    /* from */
+    $r .= $nl . 'FROM (' . $q_tbl . ' TMP)';
+    foreach (array('JOIN', 'LEFT JOIN') as $join_type) {
+      foreach ($v_tbls[$join_type] as $v_tbl) {
+        $tbl = $this->getValueTable($v_tbl['t_col']);
+        $var_name = preg_replace('/^([^\s]+)(.*)$/', '\\1', $v_tbl['q_col']);
+        $cur_join_type = in_array($var_name, $this->infos['null_vars']) ? 'LEFT JOIN' : $join_type;
+        if (!strpos($q_sql, '`' . $v_tbl['q_col'].'`')) continue;
+        $r .= $nl . ' ' . $cur_join_type . ' ' . $tbl . ' V' . $v_tbl['vc'] . ' ON (
+            (V' . $v_tbl['vc'] . '.id = TMP.`' . $v_tbl['q_col'].'`)
+        )';
+      }
+    }
+    /* create pos columns, id needed */
+    if ($this->v('order_infos', array(), $this->infos['query'])) {
+      $r .= $nl . ' ORDER BY _pos_';
+    }
+    return 'SELECT' . $nl . $r;
+  }
+  
+  /*  */
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreSemHTMLLoader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Store SemHTML Loader
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('SemHTMLParser');
+
+class ARC2_StoreSemHTMLLoader extends ARC2_SemHTMLParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function done() {
+    $this->extractRDF();
+  }
+  
+  function addT($t) {
+    $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
+    $this->t_count++;
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreTableManager.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,290 @@
+<?php
+/**
+ * ARC2 RDF Store Table Manager
+ *
+ * @license   http://arc.semsol.org/license
+ * @author    Benjamin Nowack
+ * @version   2010-11-16
+ *
+*/
+
+ARC2::inc('Store');
+
+class ARC2_StoreTableManager extends ARC2_Store {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {/* db_con */
+    parent::__init();
+    $this->engine_type = $this->v('store_engine_type', 'MyISAM', $this->a);
+  }
+
+  /*  */
+  
+  function getTableOptionsCode() {
+    $v = $this->getDBVersion();
+    $r = "";
+    $r .= (($v < '04-01-00') && ($v >= '04-00-18')) ? 'ENGINE' : (($v >= '04-01-02') ? 'ENGINE' : 'TYPE');
+    $r .= "=" . $this->engine_type;
+    $r .= ($v >= '04-00-00') ? " CHARACTER SET utf8" : "";
+    $r .= ($v >= '04-01-00') ? " COLLATE utf8_unicode_ci" : "";
+    $r .= " DELAY_KEY_WRITE = 1";
+    return $r;
+  }
+  
+  /*  */
+  
+  function createTables() {
+    $con = $this->getDBCon();
+    if(!$this->createTripleTable()) {
+      return $this->addError('Could not create "triple" table (' . mysql_error($con) . ').');
+    }
+    if(!$this->createG2TTable()) {
+      return $this->addError('Could not create "g2t" table (' . mysql_error($con) . ').');
+    }
+    if(!$this->createID2ValTable()) {
+      return $this->addError('Could not create "id2val" table (' . mysql_error($con) . ').');
+    }
+    if(!$this->createS2ValTable()) {
+      return $this->addError('Could not create "s2val" table (' . mysql_error($con) . ').');
+    }
+    if(!$this->createO2ValTable()) {
+      return $this->addError('Could not create "o2val" table (' . mysql_error($con) . ').');
+    }
+    if(!$this->createSettingTable()) {
+      return $this->addError('Could not create "setting" table (' . mysql_error($con) . ').');
+    }
+    return 1;
+  }
+  
+  /*  */
+  
+  function createTripleTable($suffix = 'triple') {
+    /* keep in sync with merge def in StoreQueryHandler ! */
+    $indexes = $this->v('store_indexes', array('sp (s,p)', 'os (o,s)', 'po (p,o)'), $this->a);
+    $index_code = $indexes ? 'KEY ' . join(', KEY ',  $indexes) . ', ' : '';
+    $sql = "
+      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . $suffix . " (
+        t mediumint UNSIGNED NOT NULL,
+        s mediumint UNSIGNED NOT NULL,
+        p mediumint UNSIGNED NOT NULL,
+        o mediumint UNSIGNED NOT NULL,
+        o_lang_dt mediumint UNSIGNED NOT NULL,
+        o_comp char(35) NOT NULL,                   /* normalized value for ORDER BY operations */
+        s_type tinyint(1) NOT NULL default 0,       /* uri/bnode => 0/1 */
+        o_type tinyint(1) NOT NULL default 0,       /* uri/bnode/literal => 0/1/2 */
+        misc tinyint(1) NOT NULL default 0,         /* temporary flags */
+        UNIQUE KEY (t), " . $index_code . " KEY (misc)
+      ) ". $this->getTableOptionsCode() . "
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }
+
+  function extendTripleTableColumns($suffix = 'triple') {
+    $sql = "
+      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+      MODIFY t int(10) UNSIGNED NOT NULL,
+      MODIFY s int(10) UNSIGNED NOT NULL,
+      MODIFY p int(10) UNSIGNED NOT NULL,
+      MODIFY o int(10) UNSIGNED NOT NULL,
+      MODIFY o_lang_dt int(10) UNSIGNED NOT NULL
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }
+  
+  /*  */
+  
+  function createG2TTable() {
+    $sql = "
+      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "g2t (
+        g mediumint UNSIGNED NOT NULL,
+        t mediumint UNSIGNED NOT NULL,
+        UNIQUE KEY gt (g,t), KEY tg (t,g)
+      ) ". $this->getTableOptionsCode() . "
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }  
+  
+  function extendG2tTableColumns($suffix = 'g2t') {
+    $sql = "
+      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+      MODIFY g int(10) UNSIGNED NOT NULL,
+      MODIFY t int(10) UNSIGNED NOT NULL
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }
+
+  /*  */
+  
+  function createID2ValTable() {
+    $sql = "
+      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "id2val (
+        id mediumint UNSIGNED NOT NULL,
+        misc tinyint(1) NOT NULL default 0,
+        val text NOT NULL,
+        val_type tinyint(1) NOT NULL default 0,     /* uri/bnode/literal => 0/1/2 */
+        UNIQUE KEY (id,val_type), KEY v (val(64))
+      ) ". $this->getTableOptionsCode() . "
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }  
+  
+  function extendId2valTableColumns($suffix = 'id2val') {
+    $sql = "
+      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+      MODIFY id int(10) UNSIGNED NOT NULL
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }
+
+  /*  */
+  
+  function createS2ValTable() {
+    //$indexes = 'UNIQUE KEY (id), KEY vh (val_hash), KEY v (val(64))';
+    $indexes = 'UNIQUE KEY (id), KEY vh (val_hash)';
+    $sql = "
+      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "s2val (
+        id mediumint UNSIGNED NOT NULL,
+        misc tinyint(1) NOT NULL default 0,
+        val_hash char(32) NOT NULL,
+        val text NOT NULL,
+        " . $indexes . "
+      ) " . $this->getTableOptionsCode() . "
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }  
+  
+  function extendS2valTableColumns($suffix = 's2val') {
+    $sql = "
+      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+      MODIFY id int(10) UNSIGNED NOT NULL
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }
+
+  /*  */
+  
+  function createO2ValTable() {
+    /* object value index, e.g. "KEY v (val(64))" and/or "FULLTEXT KEY vft (val)" */
+    $val_index = $this->v('store_object_index', 'KEY v (val(64))', $this->a);
+    if ($val_index) $val_index = ', ' . ltrim($val_index, ',');
+    $sql = "
+      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "o2val (
+        id mediumint UNSIGNED NOT NULL,
+        misc tinyint(1) NOT NULL default 0,
+        val_hash char(32) NOT NULL,
+        val text NOT NULL,
+        UNIQUE KEY (id), KEY vh (val_hash)" . $val_index . "
+      ) ". $this->getTableOptionsCode() . "
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }  
+  
+  function extendO2valTableColumns($suffix = 'o2val') {
+    $sql = "
+      ALTER TABLE " . $this->getTablePrefix() . $suffix . "
+      MODIFY id int(10) UNSIGNED NOT NULL
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }
+
+  /*  */
+  
+  function createSettingTable() {
+    $sql = "
+      CREATE TABLE IF NOT EXISTS " . $this->getTablePrefix() . "setting (
+        k char(32) NOT NULL,
+        val text NOT NULL,
+        UNIQUE KEY (k)
+      ) ". $this->getTableOptionsCode() . "
+    ";
+    return mysql_query($sql, $this->getDBCon());
+  }  
+  
+  /*  */
+
+  function extendColumns() {
+    $con = $this->getDBCon();
+    $tbl_prefix = $this->getTablePrefix();
+    $tbls = $this->getTables();
+    foreach ($tbls as $suffix) {
+      if (preg_match('/^(triple|g2t|id2val|s2val|o2val)/', $suffix, $m)) {
+        $mthd = 'extend' . ucfirst($m[1]) . 'TableColumns';
+        $this->$mthd($suffix);
+      }
+    }
+  }
+
+  /*  */
+
+  function splitTables() {
+    $old_ps = $this->getSetting('split_predicates', array());
+    $new_ps = $this->retrieveSplitPredicates();
+    $add_ps = array_diff($new_ps, $old_ps);
+    $del_ps = array_diff($old_ps, $new_ps);
+    $final_ps = array();
+    foreach ($del_ps as $p) {
+      if (!$this->unsplitPredicate($p)) $final_ps[] = $p;
+    }
+    foreach ($add_ps as $p) {
+      if ($this->splitPredicate($p)) $final_ps[] = $p;
+    }
+    $this->setSetting('split_predicates', $new_ps);
+  }
+
+  function unsplitPredicate($p) {
+    $suffix = 'triple_' . abs(crc32($p));
+    $old_tbl = $this->getTablePrefix() . $suffix;
+    $new_tbl = $this->getTablePrefix() . 'triple';
+    $p_id = $this->getTermID($p, 'p');
+    $con = $this->getDBCon();
+    $sql = '
+      INSERT IGNORE INTO ' . $new_tbl .'
+      SELECT * FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id . '
+    ';
+    if ($rs = mysql_query($sql, $con)) {
+      mysql_query('DROP TABLE ' . $old_tbl, $con);
+      return 1;
+    }
+    else {
+      return 0;
+    }
+  }
+
+  function splitPredicate($p) {
+    $suffix = 'triple_' . abs(crc32($p));
+    $this->createTripleTable($suffix);
+    $old_tbl = $this->getTablePrefix() . 'triple';
+    $new_tbl = $this->getTablePrefix() . $suffix;
+    $p_id = $this->getTermID($p, 'p');
+    $con = $this->getDBCon();
+    $sql = '
+      INSERT IGNORE INTO ' . $new_tbl .'
+      SELECT * FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id . '
+    ';
+    if ($rs = mysql_query($sql, $con)) {
+      mysql_query('DELETE FROM ' . $old_tbl . ' WHERE ' . $old_tbl . '.p = ' . $p_id, $con);
+      return 1;
+    }
+    else {
+      mysql_query('DROP TABLE ' . $new_tbl, $con);
+      return 0;
+    }
+  }
+
+  function retrieveSplitPredicates() {
+    $r = $this->split_predicates;
+    $limit = $this->max_split_tables - count($r);
+    $q = 'SELECT ?p COUNT(?p) AS ?pc WHERE { ?s ?p ?o } GROUP BY ?p ORDER BY DESC(?pc) LIMIT ' . $limit;
+    $rows = $this->query($q, 'rows');
+    foreach ($rows as $row) {
+      $r[] = $row['p'];
+    }
+    return $r;
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/store/ARC2_StoreTurtleLoader.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,32 @@
+<?php
+/*
+homepage: http://arc.semsol.org/
+license:  http://arc.semsol.org/license
+
+class:    ARC2 Store Turtle Loader
+author:   Benjamin Nowack
+version:  2010-11-16
+*/
+
+ARC2::inc('TurtleParser');
+
+class ARC2_StoreTurtleLoader extends ARC2_TurtleParser {
+
+  function __construct($a, &$caller) {
+    parent::__construct($a, $caller);
+  }
+  
+  function __init() {
+    parent::__init();
+  }
+
+  /*  */
+  
+  function addT($t) {
+    $this->caller->addT($t['s'], $t['p'], $t['o'], $t['s_type'], $t['o_type'], $t['o_datatype'], $t['o_lang']);
+    $this->t_count++;
+  }
+
+  /*  */
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/ARC2_TestCase.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+<?php
+
+define('ARC2_DIR', __DIR__ . '/../');
+
+require_once ARC2_DIR . 'ARC2.php';
+
+class ARC2_TestCase extends PHPUnit_Framework_TestCase {
+
+    public function __construct() {
+		
+    }
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/ARC2_TestHandler.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,434 @@
+<?php
+/*
+homepage: http://arc.web-semantics.org/
+license:  http://arc.web-semantics.org/license
+
+class:    ARC2 DAWG Test Handler
+author:   Benjamin Nowack
+version:  2011-12-01
+*/
+
+ARC2::inc('Class');
+
+class ARC2_TestHandler extends ARC2_Class {
+
+  function __construct($a, &$caller, &$data_store) {/* caller has to be a store */
+    parent::__construct($a, $caller);
+    $this->data_store = $data_store;
+  }
+  
+  function __init() {
+    parent::__init();
+    $this->store = $this->caller;
+    ARC2::inc('Reader');
+    $this->reader = new ARC2_Reader($this->a, $this);
+  }
+
+  /*  */
+  
+  function runTest($id) {
+    $type = $this->getTestType($id);
+    $m = 'run' . $type;
+    $r = method_exists($this, $m) ? $this->$m($id) : array('pass' => 0, 'info' => 'not supported');
+    sleep(1);
+    return $r;
+  }
+  
+  /*  */
+  
+  function getTestType($id) {
+    $q = 'SELECT ?type WHERE { <' .$id. '> a ?type . }';
+    $qr = $this->store->query($q);
+    $r = isset($qr['result']['rows'][0]) ? $qr['result']['rows'][0]['type'] : '#QueryEvaluationTest';
+    $r = preg_replace('/^.*\#([^\#]+)$/', '$1', $r);
+    return $r;
+  }
+  
+  /*  */
+
+  function getFile($url) {
+    $fname = 'f' . crc32($url) . '.txt';
+    if (!file_exists('tmp/' . $fname)) {
+      $r = '';
+      if (!isset($this->reader)) {
+        $this->reader = new ARC2_Reader($this->a, $this);
+      }
+      $this->reader->activate($url);
+      while ($d = $this->reader->readStream()) {
+        $r .= $d;
+      }
+      $this->reader->closeStream();
+      unset($this->reader);
+      $fp = @fopen('tmp/' . $fname, "w");
+      @fwrite($fp, $r);
+      @fclose($fp);
+      return $r;
+    }
+    return file_get_contents('tmp/' . $fname);
+  }
+  
+  function runPositiveSyntaxTest($id) {
+    $nl = "\n";
+    $r = '';
+    /* get action */
+    $q = '
+      PREFIX mf:      <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+      SELECT DISTINCT ?action WHERE { <' .$id. '> mf:action ?action . }
+    ';
+    $qr = $this->store->query($q);
+    $action = $qr['result']['rows'][0]['action'];
+    /* get code */
+    $q = $this->getFile($action);
+    /* parse */
+    ARC2::inc('SPARQLPlusParser');
+    $parser = new ARC2_SPARQLPlusParser($this->a, $this);
+    $parser->parse($q, $action);
+    $infos = $parser->getQueryInfos();
+    $rest = $parser->getUnparsedCode();
+    $errors = $parser->getErrors();
+    $r .= $nl . '<div style="border: #eee solid 1px ; padding: 5px; ">' . htmlspecialchars($q) . '</div>' . $nl ;
+    if ($errors || $rest) {
+      $pass = 0;
+      $r .= htmlspecialchars($nl . $nl . print_r($errors, 1) . $nl . print_r($rest, 1));
+    }
+    else {
+      $pass = 1;
+      $r .= htmlspecialchars($nl . $nl . print_r($infos, 1));
+    }
+    return array('pass' => $pass, 'info' => $r);
+  }
+  
+  /*  */
+
+  function runNegativeSyntaxTest($id) {
+    $nl = "\n";
+    $r = '';
+    /* get action */
+    $q = '
+      PREFIX mf:      <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+      SELECT DISTINCT ?action WHERE { <' .$id. '> mf:action ?action . }
+    ';
+    $qr = $this->store->query($q);
+    $action = $qr['result']['rows'][0]['action'];
+    /* get code */
+    $q = $this->getFile($action);
+    /* parse */
+    ARC2::inc('SPARQLPlusParser');
+    $parser = new ARC2_SPARQLPlusParser($this->a, $this);
+    $parser->parse($q, $action);
+    $infos = $parser->getQueryInfos();
+    $rest = $parser->getUnparsedCode();
+    $errors = $parser->getErrors();
+    $r .= $nl . '<div style="border: #eee solid 1px ; padding: 5px; ">' . htmlspecialchars($q) . '</div>' . $nl ;
+    if ($errors || $rest) {
+      $pass = 1;
+      $r .= htmlspecialchars($nl . $nl . print_r($errors, 1) . $nl . print_r($rest, 1));
+    }
+    else {
+      $pass = 0;
+      $r .= htmlspecialchars($nl . $nl . print_r($infos, 1));
+    }
+    return array('pass' => $pass, 'info' => $r);
+  }
+
+  /*  */
+
+  function runQueryEvaluationTest($id) {
+    $nl = "\n";
+    $r = '';
+    /* get action */
+    $q = '
+      PREFIX mf:      <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+      PREFIX qt:      <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+      SELECT DISTINCT ?query ?data ?graph_data ?result WHERE { 
+        <' .$id. '> mf:action ?action ;
+                    mf:result ?result .
+        ?action     qt:query  ?query .
+        OPTIONAL {
+          ?action qt:data ?data .
+        }
+        OPTIONAL {
+          ?action qt:graphData ?graph_data .
+        }
+      }
+    ';
+    $qr = $this->store->query($q);
+    $rows = $qr['result']['rows'];
+    $infos = array();
+    foreach (array('query', 'data', 'result', 'graph_data') as $var) {
+      $infos[$var] = array();
+      $infos[$var . '_value'] = array();
+      foreach ($rows as $row) {
+        if (isset($row[$var])) {
+          if (!in_array($row[$var], $infos[$var])) {
+            $infos[$var][] = $row[$var];
+            $infos[$var . '_value'][] = $this->getFile($row[$var]);
+          }
+        }
+      }
+      $$var = $infos[$var];
+      ${$var . '_value'} = $infos[$var . '_value'];
+      if (count($infos[$var]) == 1) {
+        $$var = $infos[$var][0];
+        ${$var . '_value'} = $infos[$var . '_value'][0];
+      }
+      if ($$var && ($var != '-result')) {
+        //echo '<pre>' . $$var . $nl . $nl . htmlspecialchars(${$var . '_value'}) . '</pre><hr />';
+      }
+    }
+    /* query infos */
+    ARC2::inc('SPARQLPlusParser');
+    $parser = new ARC2_SPARQLPlusParser($this->a, $this);
+    $parser->parse($query_value, $query);
+    $infos = $parser->getQueryInfos();
+    $rest = $parser->getUnparsedCode();
+    $errors = $parser->getErrors();
+    $q_type = !$errors ? $infos['query']['type'] : '';
+    /* add data */
+    $dsets = array();
+    $gdsets = array();
+    if ($data) {
+      $dsets = is_array($data) ? array_merge($dsets, $data) : array_merge($dsets, array($data));
+    }
+    if ($graph_data) {
+      $gdsets = is_array($graph_data) ? array_merge($gdsets, $graph_data) : array_merge($gdsets, array($graph_data));
+    }
+    if (!$dsets && !$gdsets) {
+      foreach ($infos['query']['dataset'] as $set) {
+        if ($set['named']) {
+          $gdsets[] = $set['graph'];
+        }
+        else {
+          $dsets[] = $set['graph'];
+        }
+      }
+    }
+    $store = $this->data_store;
+    $store->reset();
+    foreach ($dsets as $graph) {
+      $qr = $store->query('LOAD <' .$graph. '>');
+    }
+    foreach ($gdsets as $graph) {
+      $qr = $store->query('LOAD <' .$graph. '> INTO <' .$graph. '>');
+    }
+    /* run query */
+    if ($query) {
+      $sql = $store->query($query_value, 'sql', $query);
+      $qr = $store->query($query_value, '', $query);
+      $qr_result = $qr['result'];
+      if ($q_type == 'select') {
+        $qr_result = $this->adjustBnodes($qr['result'], $id);
+      }
+      elseif ($q_type == 'construct') {
+        $ser = ARC2::getTurtleSerializer($this->a);
+        $qr_result = $ser->getSerializedIndex($qr_result);    
+      }
+    }
+    //echo '<pre>query result: ' . $nl . htmlspecialchars(print_r($qr_result, 1)) . '</pre>';
+    if (!$query || $errors || $rest) {
+      return array('pass' => 0, 'info' => 'query could not be parsed' . htmlspecialchars($query_value));
+    }
+    $m = 'isSame' . $q_type . 'Result';
+    $sub_r = $this->$m($qr_result, $result_value, $result, $id);
+    $pass = $sub_r['pass'];
+    if (in_array($id, array(
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/sort/manifest#dawg-sort-6',
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/sort/manifest#dawg-sort-8',
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/sort/manifest#dawg-sort-builtin',
+    ))) {
+      $pass = 0; /* manually checked 2007-09-18 */
+    }
+    if (in_array($id, array(
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/sort/manifest#dawg-sort-function',
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/reduced/manifest#reduced-1',
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/reduced/manifest#reduced-2',
+    ))) {
+      $pass = 1; /* manually checked 2007-11-28 */
+    }
+    $pass_info = $sub_r['info'];
+    $info = print_r($pass_info, 1) . $nl;
+    $info .= '<hr />sql: ' . $nl . htmlspecialchars($sql['result']) . '<hr />';
+    $info .= $pass ? '' : print_r($graph_data, 1) . $nl . htmlspecialchars(print_r($graph_data_value, 1)) . '<hr />';
+    $info .= $pass ? '' : print_r($data, 1) . $nl . htmlspecialchars(print_r($data_value, 1)) . '<hr />';
+    $info .= $pass ? '' : $query . $nl . htmlspecialchars($query_value) . '<hr />';
+    $info .= $pass ? '' : '<pre>query result: ' . $nl . htmlspecialchars(print_r($qr_result, 1)) . '</pre>' . '<hr />';
+    $info .= $pass ? '' : print_r($infos, 1);
+    return array('pass' => $pass, 'info' => $info);
+  }
+
+  /*  */
+  
+  function isSameSelectResult($qr, $result, $result_base) {
+    if (strpos($result, 'http://www.w3.org/2001/sw/DataAccess/tests/result-set#')) {
+      $parser = ARC2::getRDFParser($this->a);
+      $parser->parse($result_base, $result);
+      $index = $parser->getSimpleIndex(0);
+      //echo '<pre>' . print_r($index, 1) .'</pre>';
+      $valid_qr = $this->buildTurtleSelectQueryResult($index);
+    }
+    else {
+      $parser = ARC2::getSPARQLXMLResultParser($this->a);
+      $parser->parse('', $result);
+      $valid_qr = $parser->getStructure();
+    }
+    if (isset($valid_qr['boolean'])) {
+      $pass = $valid_qr['boolean'] == $this->v('boolean', '', $qr);
+    }
+    else {
+      $pass = 1;
+      if (count($valid_qr['variables']) != count($qr['variables'])) {
+        $pass = 0;
+      }
+      if (count($valid_qr['rows']) != count($qr['rows'])) {
+        $pass = 0;
+      }
+      if ($pass) {
+        foreach ($valid_qr['variables'] as $var) {
+          if (!in_array($var, $qr['variables'])) {
+            $pass = 0;
+            break;
+          }
+        }
+      }
+      if ($pass) {
+        $index = $this->buildArrayHashIndex($qr['rows']);
+        $valid_index = $this->buildArrayHashIndex($valid_qr['rows']);
+        if (($diff = array_diff($index, $valid_index)) || ($diff = array_diff($valid_index, $index))) {
+          $pass = 0;
+          //echo '<pre>' . print_r($diff, 1) . '</pre>';
+        }
+      }
+    }
+    return array('pass' => $pass, 'info' => $valid_qr);
+  }
+  
+  /*  */
+  
+  function isSameConstructResult($qr, $result, $result_base, $test) {
+    $parser = ARC2::getRDFParser($this->a);
+    $parser->parse('', $result);
+    $valid_triples = $parser->getTriples();
+    $parser = ARC2::getRDFParser($this->a);
+    $parser->parse('', $qr);
+    $triples = $parser->getTriples();
+    $info = '<pre>' . print_r($valid_triples, 1) .'</pre>';
+    $info = '';
+    
+    //echo '<pre>' . print_r($index, 1) .'</pre>';
+    $pass = 0;
+    if (in_array($test, array(/* manually checked 2007-09-21 */
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/construct/manifest#construct-1',
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/construct/manifest#construct-2',
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/construct/manifest#construct-3',
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/construct/manifest#construct-4',
+      'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/construct/manifest#construct-5',
+    ))) {
+      $pass = 1;
+    }
+    return array('pass' => $pass, 'info' => $valid_triples);
+  }
+  
+  /*  */
+  
+  function isSameAskResult($qr, $result, $result_base) {
+    if (preg_match('/(true|false)\.(ttl|n3)$/', $result_base, $m)) {
+      $valid_r = $m[1];
+    }
+    else {
+      $valid_r = preg_match('/boolean\>([^\<]+)/s', $result, $m) ? trim($m[1]) : '-';
+    }
+    $r = ($qr === true) ? 'true' : 'false';
+    $pass = ($r == $valid_r) ? 1 : 0;
+    return array('pass' => $pass, 'info' => $valid_r);
+  }
+  
+  /*  */
+  
+  function buildTurtleSelectQueryResult($index) {
+    $rs = 'http://www.w3.org/2001/sw/DataAccess/tests/result-set#';
+    $rdf = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+    $r = array('variables' => array(), 'rows' => array());
+    foreach ($index as $node => $props) {
+      $types = $this->v($rdf . 'type', array(), $props);
+      foreach ($types as $type) {
+        if ($type['value'] == $rs . 'ResultSet') {
+          $vars = $this->v($rs . 'resultVariable', array(), $props);
+          foreach ($vars as $var) {
+            $r['variables'][] = $var['value'];            
+          }
+        }
+      }
+      $bindings = $this->v($rs . 'binding', array(), $props);
+      if ($bindings) {
+        $row = array();
+        foreach ($bindings as $binding) {
+          $binding_id = $binding['value'];
+          $var = $index[$binding_id][$rs . 'variable'][0]['value'];
+          $val = $index[$binding_id][$rs . 'value'][0]['value'];
+          $val_type = $index[$binding_id][$rs . 'value'][0]['type'];
+          //$val_type = preg_match('/literal/', $val_type) ? 'literal' : $val_type;
+          $row[$var] = $val;
+          $row[$var . ' type'] = $val_type;
+          if ($dt = $this->v('datatype', 0, $index[$binding_id][$rs . 'value'][0])) {
+            $row[$var . ' datatype'] = $dt;
+          }
+          if ($lang = $this->v('lang', 0, $index[$binding_id][$rs . 'value'][0])) {
+            $row[$var . ' lang'] = $lang;
+          }
+        }
+        $r['rows'][] = $row;
+      }
+    }
+    return $r;
+  }
+  
+  /*  */
+
+  function buildArrayHashIndex($rows) {
+    $r = array();
+    foreach ($rows as $row) {
+      $hash = '';
+      ksort($row);
+      foreach ($row as $k => $v) {
+        $hash .= is_numeric($k) ? '' : ' ' . md5($k) . ' ' . md5($v);
+      }
+      $r[] = $hash;
+    }
+    return $r;
+  }
+
+  /*  */
+  
+  function adjustBnodes($result, $data) {
+    $mappings = array(
+      '_:b1371233574_bob' => '_:b10',
+      '_:b1114277307_alice' => '_:b1f',
+      '_:b1368422168_eve' => '_:b20',
+      '_:b1638119969_fred' => '_:b21',
+      
+      '_:b288335586_a' => array(
+        'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest#no-distinct-3' => '_:b0',
+        'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest#distinct-3' => '_:b0',
+        'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest#distinct-9' => '_:b0',
+        'http://www.w3.org/2001/sw/DataAccess/tests/data-r2/distinct/manifest#no-distinct-9' => '_:b0',
+        'default' => '_:bn5',
+      ),
+    );
+    if (isset($result['rows'])) {
+      foreach ($result['rows'] as $i => $row) {
+        foreach ($result['variables'] as $var) {
+          if (isset($row[$var]) && isset($mappings[$row[$var]])) {
+            if (is_array($mappings[$row[$var]])) {
+              $result['rows'][$i][$var] = isset($mappings[$row[$var]][$data]) ? $mappings[$row[$var]][$data] : $mappings[$row[$var]]['default'];
+            }
+            else {
+              $result['rows'][$i][$var] = $mappings[$row[$var]];
+            }
+          }
+        }
+      }
+    }
+    return $result;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/data/atom/feed.atom	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+
+  <title>Example Feed</title>
+  <link href="http://example.org/"/>
+  <updated>2003-12-13T18:30:02Z</updated>
+  <author>
+    <name>John Doe</name>
+  </author>
+  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+
+  <entry>
+    <title>Atom-Powered Robots Run Amok</title>
+    <link href="http://example.org/2003/12/13/atom03"/>
+    <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+    <updated>2003-12-13T18:30:02Z</updated>
+    <summary>Some text.</summary>
+  </entry>
+
+</feed>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/data/json/crunchbase-facebook.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,450 @@
+{"name": "Facebook",
+ "permalink": "facebook",
+ "homepage_url": "http://facebook.com",
+ "blog_url": "http://blog.facebook.com",
+ "blog_feed_url": "http://blog.facebook.com/atom.php",
+ "category_code": "web",
+ "number_of_employees": 450,
+ "founded_year": 2004,
+ "founded_month": 2,
+ "founded_day": 1,
+ "deadpooled_year": null,
+ "deadpooled_month": null,
+ "deadpooled_day": null,
+ "deadpooled_url": "",
+ "tag_list": "social, facebook, college, students, profiles, network, socialnetwork, socialmedia, platform",
+ "email_address": "",
+ "phone_number": "",
+ "overview": "\u003Cp\u003EOn February 4th, 2004 \u003Ca href=\"http://www.crunchbase.com/person/mark-zuckerberg\" title=\"Mark Zuckerberg\"\u003EMark Zuckerberg\u003C/a\u003E launched The Facebook, a social network that was at the time exclusively for Harvard students. It was a huge hit, in 2 weeks, half of the student body at Harvard had signed up.  Other schools in the Boston area began demanding a Facebook network. Zuckerberg immediately recruited his friends \u003Ca href=\"http://www.crunchbase.com/person/dustin-moskovitz\" title=\"Dustin Moskowitz\"\u003EDustin Moskowitz\u003C/a\u003E and Chris Hughes to help build Facebook, and within four months, Facebook added 30 more college networks. \u003C/p\u003E\n\n\u003Cp\u003EThe original idea for the term Facebook came from Zuckerberg\u0026#8217;s high school (Phillips Exeter Academy). The Exeter Face Book was passed around to every student as a way for students to get to know their classmates for the following year. It was a physical paper book until Zuckerberg brought it to the internet.\u003C/p\u003E\n\n\u003Cp\u003EWith this success, Zuckerberg, Moskowitz and Hughes moved out to Palo Alto for the summer and rented a sublet. A few weeks later, Zuckerberg ran into the former cofounder of Napster, Sean Parker. Parker soon moved in to Zuckerberg\u0026#8217;s apartment and they began working together.  Parker provided the introduction to their first investor, Peter Thiel, cofounder of PayPal and managing partner of the Founders Fund. Thiel invested $500,000 into Facebook. \u003C/p\u003E\n\n\u003Cp\u003EWith millions more users, Friendster \u003Ca href=\"http://www.techcrunch.com/2006/12/12/yahoos-project-fraternity-docs-leaked/\" title=\"attempted\"\u003Eattempted\u003C/a\u003E to acquire the company for $10 million in mid 2004. Facebook turned down the offer and subsequently received $12.7 million in funding from Accel Partners, at a valuation of \u003Ca href=\"http://www.techcrunch.com/2005/09/07/85-of-college-students-use-facebook/\" title=\"around $100 million\"\u003Earound $100 million\u003C/a\u003E. Facebook continued to grow, opening up to high school students in September 2005 and adding an immensely popular photo sharing feature the next month. The next spring, Facebook received $25 million in funding from Greylock Partners and Meritech Capital, as well as previous investors Accel Partners and Peter Thiel. The pre-money valuation for this deal was about $525 million. Facebook subsequently \u003Ca href=\"http://www.techcrunch.com/2006/04/26/facebook-goes-beyond-college-high-school-markets/\" title=\"opened\"\u003Eopened\u003C/a\u003E up to work networks, eventually amassing over 20,000 work networks. Finally in September 2006, Facebook \u003Ca href=\"http://www.techcrunch.com/2006/09/26/facebook-just-launched-open-registrations/\" title=\"opened\"\u003Eopened\u003C/a\u003E to anyone with an email address. \u003C/p\u003E\n\n\u003Cp\u003EIn the summer of 2006, Yahoo \u003Ca href=\"http://www.techcrunch.com/2006/09/21/facebook-and-yahoo-in-acquisition-talks-for-1-billion/\" title=\"attempted to acquire\"\u003Eattempted to acquire\u003C/a\u003E the company for $1 billion dollars. \u003Ca href=\"http://www.wired.com/techbiz/startups/news/2007/09/ff_facebook\" title=\"Reports\" rel=\"nofollow\"\u003EReports\u003C/a\u003E actually indicated that Zuckerberg made a verbal agreement to sell Facebook to Yahoo. A few days later when Yahoo\u0026#8217;s stock price took a dive, the offer was lowered to $800 million and Zuckerberg walked away from the deal.  Yahoo later \u003Ca href=\"http://www.techcrunch.com/2006/12/12/yahoos-project-fraternity-docs-leaked/\" title=\"offered\"\u003Eoffered\u003C/a\u003E $1 billion again, this time Zuckerberg turned Yahoo down and earned instant notoriety as the \u0026#8220;kid\u0026#8221; who turned down a billion. This was not the first time Zuckerberg turned down an acquisition offer; Viacom had previously \u003Ca href=\"http://www.techcrunch.com/2006/03/28/facebook-is-doing-the-skype-dance/\" title=\"unsuccessfully\"\u003Eunsuccessfully\u003C/a\u003E attempted to acquire the company for $750 million in March, 2006. \u003C/p\u003E\n\n\u003Cp\u003EOne sour note for Facebook has been the \u003Ca href=\"http://www.techcrunch.com/2007/07/16/the-ghost-of-zuckerbergs-past-may-haunt-facebook-ipo/\" title=\"controversy\"\u003Econtroversy\u003C/a\u003E with social network Uconnect. The founders of Uconnect, former classmates of Mark Zuckerberg at Harvard, allege that Zuckerberg stole their original source code for Facebook. The ordeal has \u003Ca href=\"http://www.techcrunch.com/2007/10/10/facebook-vs-connectu-facebook-makes-untrue-assertions-claims-connectu/\" title=\"gone to court\"\u003Egone to court\u003C/a\u003E, but is still unresolved. \u003C/p\u003E\n\n\u003Cp\u003ENotwithstanding this lingering controversy, Facebook\u0026#8217;s growth in the fall of 2007 was staggering. Over 1 million new users signed up every week, 200,000 daily, totaling over 50 million active users. Facebook received 40 billion page views a month.  Long gone were the days of Facebook as a social network for college students. 11% of users are over the age of 35, and the fastest growing demographic is users over 30. Facebook has also seen huge growth internationally; 15% of the user base is in Canada.  Facebook users\u0026#8217; \u003Ca href=\"http://www.techcrunch.com/2007/11/13/i-just-cant-be-a-college-student-without-facebook/\" title=\"passion\"\u003Epassion\u003C/a\u003E, or \u003Ca href=\"http://www.techcrunch.com/2007/03/09/career-advice-dont-choose-facebook-over-your-job/\" title=\"addiction\"\u003Eaddiction\u003C/a\u003E, to the site is unparalleled: more than half use the product every single day and users spend an average of 19 minutes a day on Facebook. Facebook is 6th most trafficked site in the US and top photo sharing site with \u003Ca href=\"http://www.techcrunch.com/2007/11/13/2-billion-photos-on-flickr/\" title=\"4.1 billion photos uploaded\"\u003E4.1 billion photos uploaded\u003C/a\u003E. \u003C/p\u003E\n\n\u003Cp\u003EBased on these types of numbers, \u003Ca href=\"http://www.techcrunch.com/2007/10/24/facebook-takes-the-microsoft-money-and-runs/\" title=\"Microsoft invested\"\u003EMicrosoft invested\u003C/a\u003E $240 million into Facebook for 1.6 percent of the company in October 2007.  This meant a valuation of over $15 billion, making Facebook the \u003Ca href=\"http://www.techcrunch.com/2007/10/25/perspective-facebook-is-now-5th-most-valuable-us-internet-company/\" title=\"5th most valuable US Internet company\"\u003E5th most valuable US Internet company\u003C/a\u003E, yet with only $150 million in annual revenue. Many explained Microsoft\u0026#8217;s decision as being solely driven by the desire to outbid Google. \u003C/p\u003E\n\n\u003Cp\u003EFacebook\u0026#8217;s competitors include \u003Ca href=\"http://www.crunchbase.com/company/myspace\" title=\"MySpace\"\u003EMySpace\u003C/a\u003E, \u003Ca href=\"http://www.crunchbase.com/company/Bebo\" title=\"Bebo\"\u003EBebo\u003C/a\u003E, \u003Ca href=\"http://www.crunchbase.com/company/Friendster\" title=\"Friendster\"\u003EFriendster\u003C/a\u003E, \u003Ca href=\"http://www.crunchbase.com/company/LinkedIn\" title=\"LinkedIn\"\u003ELinkedIn\u003C/a\u003E, \u003Ca href=\"http://www.crunchbase.com/company/tagged\" title=\"Tagged\"\u003ETagged\u003C/a\u003E, \u003Ca href=\"http://www.techcrunch.com/2007/01/20/hi5-traffic-surges-may-be-second-largest-social-network/\" title=\"Hi5\"\u003EHi5\u003C/a\u003E, \u003Ca href=\"http://www.techcrunch.com/2006/09/25/a-look-at-piczo-and-its-competitors/\" title=\"Piczo\"\u003EPiczo\u003C/a\u003E, and \u003Ca href=\"http://www.techcrunch.com/2007/10/30/details-revealed-google-opensocial-to-be-common-apis-for-building-social-apps/\" title=\"Open Social\"\u003EOpen Social\u003C/a\u003E. \u003C/p\u003E\n\n\u003Cp\u003E\u003Cimg src=\"http://farm3.static.flickr.com/2059/2046940872_73672f2007.jpg\" alt=\"Facebook Traffic\"/\u003E\u003C/p\u003E",
+ "image":
+  {"available_sizes":
+    [[[150,
+       56],
+      "assets/images/resized/0000/4552/4552v2-max-150x150.jpg"],
+     [[250,
+       94],
+      "assets/images/resized/0000/4552/4552v2-max-250x250.jpg"],
+     [[450,
+       169],
+      "assets/images/resized/0000/4552/4552v2-max-450x450.jpg"]],
+   "attribution": null},
+ "products":
+  [{"name": "Facebook Platform",
+    "permalink": "facebook-platform"},
+   {"name": "Facebook News Feed",
+    "permalink": "facebook-news-feed"},
+   {"name": "Facebook Chat",
+    "permalink": "facebook-chat"},
+   {"name": "Facebook Connect",
+    "permalink": "facebook-connect"},
+   {"name": "Facebook iPhone App",
+    "permalink": "facebook-iphone-app"}],
+ "relationships":
+  [{"is_past": false,
+    "title": "Founder and CEO, Board Of Directors",
+    "person":
+     {"first_name": "Mark",
+      "last_name": "Zuckerberg",
+      "permalink": "mark-zuckerberg"}},
+   {"is_past": false,
+    "title": "Co-founder and VP Engineering",
+    "person":
+     {"first_name": "Dustin",
+      "last_name": "Moskovitz",
+      "permalink": "dustin-moskovitz"}},
+   {"is_past": true,
+    "title": "Chief Revenue Officer, VP of Operations",
+    "person":
+     {"first_name": "Owen",
+      "last_name": "Van Natta",
+      "permalink": "owen-van-natta"}},
+   {"is_past": true,
+    "title": "VP of Product Management",
+    "person":
+     {"first_name": "Matt",
+      "last_name": "Cohler",
+      "permalink": "matt-cohler"}},
+   {"is_past": false,
+    "title": "Co-founder",
+    "person":
+     {"first_name": "Chris",
+      "last_name": "Hughes",
+      "permalink": "chris-hughes"}},
+   {"is_past": false,
+    "title": "VP of Product Marketing",
+    "person":
+     {"first_name": "Chamath",
+      "last_name": "Palihapitiya",
+      "permalink": "chamath-palihapitiya"}},
+   {"is_past": false,
+    "title": "CFO",
+    "person":
+     {"first_name": "Gideon",
+      "last_name": "Yu",
+      "permalink": "gideon-yu"}},
+   {"is_past": true,
+    "title": "CTO",
+    "person":
+     {"first_name": "Adam",
+      "last_name": "D'Angelo",
+      "permalink": "adam-d-angelo"}},
+   {"is_past": false,
+    "title": "COO",
+    "person":
+     {"first_name": "Sheryl",
+      "last_name": "Sandberg",
+      "permalink": "sheryl-sandberg"}},
+   {"is_past": false,
+    "title": "Senior Platform Manager",
+    "person":
+     {"first_name": "Dave",
+      "last_name": "Morin",
+      "permalink": "dave-morin"}},
+   {"is_past": false,
+    "title": "Director of Business Development",
+    "person":
+     {"first_name": "Ethan",
+      "last_name": "Beard",
+      "permalink": "ethan-beard"}},
+   {"is_past": false,
+    "title": "Chief Privacy Officer",
+    "person":
+     {"first_name": "Chris",
+      "last_name": "Kelly",
+      "permalink": "chris-kelly"}},
+   {"is_past": false,
+    "title": "",
+    "person":
+     {"first_name": "Justin",
+      "last_name": "Rosenstein",
+      "permalink": "justin-rosenstein"}},
+   {"is_past": false,
+    "title": "VP of Technical Operations",
+    "person":
+     {"first_name": "Jonathan",
+      "last_name": "Heiliger",
+      "permalink": "jonathan-heiliger"}},
+   {"is_past": false,
+    "title": "Director Platform Product Marketing",
+    "person":
+     {"first_name": "Ben",
+      "last_name": "Ling",
+      "permalink": "ben-ling"}},
+   {"is_past": false,
+    "title": "Product Lead for Facebook Platform",
+    "person":
+     {"first_name": "Ruchi",
+      "last_name": "Sanghvi",
+      "permalink": "ruchi-sanghvi"}},
+   {"is_past": false,
+    "title": "Board Of Directors",
+    "person":
+     {"first_name": "Jim",
+      "last_name": "Breyer",
+      "permalink": "jim-breyer"}},
+   {"is_past": false,
+    "title": "VP of Communications and Public Policy",
+    "person":
+     {"first_name": "Elliot",
+      "last_name": "Schrage",
+      "permalink": "elliot-schrage"}},
+   {"is_past": false,
+    "title": "Board Of Directors",
+    "person":
+     {"first_name": "Peter",
+      "last_name": "Thiel",
+      "permalink": "peter-thiel"}},
+   {"is_past": false,
+    "title": "Observer to Board of Directors",
+    "person":
+     {"first_name": "David",
+      "last_name": "Sze",
+      "permalink": "david-sze"}},
+   {"is_past": true,
+    "title": "President, Board of Directors",
+    "person":
+     {"first_name": "Sean",
+      "last_name": "Parker",
+      "permalink": "sean-parker"}},
+   {"is_past": false,
+    "title": "Board of directors",
+    "person":
+     {"first_name": "Marc",
+      "last_name": "Andreessen",
+      "permalink": "marc-andreessen"}}],
+ "competitions":
+  [{"competitor":
+     {"name": "MySpace",
+      "permalink": "myspace"}},
+   {"competitor":
+     {"name": "Friendster",
+      "permalink": "friendster"}},
+   {"competitor":
+     {"name": "Slide",
+      "permalink": "slide"}},
+   {"competitor":
+     {"name": "Zvents",
+      "permalink": "zvents"}},
+   {"competitor":
+     {"name": "FriendFeed",
+      "permalink": "friendfeed"}},
+   {"competitor":
+     {"name": "Qik",
+      "permalink": "qik"}},
+   {"competitor":
+     {"name": "hi5",
+      "permalink": "hi5"}},
+   {"competitor":
+     {"name": "Photobucket",
+      "permalink": "photobucket"}},
+   {"competitor":
+     {"name": "Webshots",
+      "permalink": "webshots"}},
+   {"competitor":
+     {"name": "Flickr",
+      "permalink": "flickr"}},
+   {"competitor":
+     {"name": "Spokeo",
+      "permalink": "spokeo"}},
+   {"competitor":
+     {"name": "HOT or NOT",
+      "permalink": "hotornot"}},
+   {"competitor":
+     {"name": "Piczo",
+      "permalink": "piczo"}},
+   {"competitor":
+     {"name": "Zyb",
+      "permalink": "zyb"}},
+   {"competitor":
+     {"name": "Multiply",
+      "permalink": "multiply"}},
+   {"competitor":
+     {"name": "YouTube",
+      "permalink": "youtube"}},
+   {"competitor":
+     {"name": "badoo",
+      "permalink": "badoo"}},
+   {"competitor":
+     {"name": "openPeople",
+      "permalink": "openpeople"}},
+   {"competitor":
+     {"name": "Bigsight Media Group",
+      "permalink": "bigsight-media-group"}},
+   {"competitor":
+     {"name": "Xiaonei",
+      "permalink": "xiaonei"}},
+   {"competitor":
+     {"name": "Daikana",
+      "permalink": "daikana"}},
+   {"competitor":
+     {"name": "Bebo",
+      "permalink": "bebo"}},
+   {"competitor":
+     {"name": "AOL",
+      "permalink": "aol"}},
+   {"competitor":
+     {"name": "CityIN",
+      "permalink": "cityin"}},
+   {"competitor":
+     {"name": "Xanga",
+      "permalink": "xanga"}},
+   {"competitor":
+     {"name": "Spleak",
+      "permalink": "spleak"}},
+   {"competitor":
+     {"name": "yuwie",
+      "permalink": "yuwie"}},
+   {"competitor":
+     {"name": "Rekatu",
+      "permalink": "rekatu"}},
+   {"competitor":
+     {"name": "5icampus",
+      "permalink": "5icampus"}},
+   {"competitor":
+     {"name": "Tagged",
+      "permalink": "tagged"}}],
+ "providerships":
+  [{"title": "",
+    "is_past": false,
+    "provider":
+     {"name": "OutCast Communications",
+      "permalink": "outcast-communications"}},
+   {"title": "Public Relations",
+    "is_past": false,
+    "provider":
+     {"name": "Blanc \u0026 Otus",
+      "permalink": "blanc-otus"}}],
+ "funding_rounds":
+  [{"round_code": "angel",
+    "source_url": "",
+    "source_description": "",
+    "raised_amount": 500000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2004,
+    "funded_month": 9,
+    "funded_day": 1,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "The Founders Fund",
+         "permalink": "founders-fund"},
+       "person": null}]},
+   {"round_code": "a",
+    "source_url": "http://www.techcrunch.com/2007/11/02/jim-breyer-extra-500-million-round-for-facebook-a-total-fiction/",
+    "source_description": "Jim Breyer: Extra $500 Million Round For Facebook A \u201cTotal Fiction\u201d",
+    "raised_amount": 12700000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2005,
+    "funded_month": 5,
+    "funded_day": 1,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "Accel Partners",
+         "permalink": "accel-partners"},
+       "person": null}]},
+   {"round_code": "b",
+    "source_url": "http://www.facebook.com/press/info.php?factsheet",
+    "source_description": "Facebook Funding",
+    "raised_amount": 27500000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2006,
+    "funded_month": 4,
+    "funded_day": 1,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "Greylock",
+         "permalink": "greylock"},
+       "person": null},
+      {"company": null,
+       "financial_org":
+        {"name": "Meritech Capital Partners",
+         "permalink": "meritech-capital-partners"},
+       "person": null},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Peter",
+         "last_name": "Thiel",
+         "permalink": "peter-thiel"}}]},
+   {"round_code": "c",
+    "source_url": "http://www.techcrunch.com/2007/10/24/liveblogging-the-facebook-press-conference/#more-10260",
+    "source_description": "Liveblogging The Facebook Press Conference",
+    "raised_amount": 300000000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2007,
+    "funded_month": 10,
+    "funded_day": 1,
+    "investments":
+     [{"company":
+        {"name": "Microsoft",
+         "permalink": "microsoft"},
+       "financial_org": null,
+       "person": null},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Li",
+         "last_name": "Ka-shing",
+         "permalink": "li-ka-shing"}},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Marc",
+         "last_name": "Samwer",
+         "permalink": "marc-samwer"}},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Oliver",
+         "last_name": "Samwer",
+         "permalink": "oliver-samwer"}},
+      {"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Alexander",
+         "last_name": "Samwer",
+         "permalink": "alexander-samwer"}}]},
+   {"round_code": "c",
+    "source_url": "http://www.marketwatch.com/news/story/hong-kong-tycoon-li-raises/story.aspx?guid=%7BE4097AA2-9EA3-4773-9100-456E68EE1C9A%7D",
+    "source_description": "",
+    "raised_amount": 40000000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2008,
+    "funded_month": 3,
+    "funded_day": null,
+    "investments":
+     [{"company": null,
+       "financial_org": null,
+       "person":
+        {"first_name": "Li",
+         "last_name": "Ka-shing",
+         "permalink": "li-ka-shing"}}]},
+   {"round_code": "c",
+    "source_url": "",
+    "source_description": "Reneigh is sexy",
+    "raised_amount": 15000000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2008,
+    "funded_month": 1,
+    "funded_day": 15,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "European Founders Fund",
+         "permalink": "european-founders-fund"},
+       "person": null}]},
+   {"round_code": "debt_round",
+    "source_url": "http://www.businessweek.com/technology/content/may2008/tc2008059_855064.htm",
+    "source_description": "",
+    "raised_amount": 100000000.0,
+    "raised_currency_code": "USD",
+    "funded_year": 2008,
+    "funded_month": 5,
+    "funded_day": null,
+    "investments":
+     [{"company": null,
+       "financial_org":
+        {"name": "TriplePoint Capital",
+         "permalink": "triplepoint-capital"},
+       "person": null}]}],
+ "investments":
+  [],
+ "acquisition": null,
+ "acquisitions":
+  [{"price_amount": null,
+    "price_currency_code": "USD",
+    "term_code": "cash",
+    "source_url": null,
+    "source_description": null,
+    "acquired_year": 2007,
+    "acquired_month": 7,
+    "acquired_day": 1,
+    "company":
+     {"name": "Parakey",
+      "permalink": "parakey"}}],
+ "offices":
+  [{"description": null,
+    "address1": "156 University Avenue",
+    "address2": "",
+    "zip_code": "94301",
+    "city": "Palo Alto",
+    "state_code": "CA",
+    "country_code": "USA",
+    "latitude": 37.444173,
+    "longitude": -122.163294}],
+ "milestones":
+  [{"description": "Facebook adds comments to Mini-Feed",
+    "stoned_year": 2008,
+    "stoned_month": 6,
+    "stoned_day": 25,
+    "source_url": "http://venturebeat.com/2008/06/25/facebook-adds-comment-to-the-mini-feed-its-like-friendfeed-is-looking-in-the-mirror/",
+    "source_description": "Facebook adds comments to the Mini-Feed. It\u2019s like FriendFeed is looking in the mirror"}],
+ "ipo": null,
+ "video_embeds":
+  [{"embed_code": "\u003Cscript type=\"text/javascript\" src=\"http://www.podtech.net/player/popup.js\"\u003E\u003C/script\u003E\u003Cobject classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" codebase=\"http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0\" width=\"450\" height=\"299\" id=\"player73536e08d3f742de9d31b25a319af359\" align=\"middle\"\u003E\u003Cparam name=\"allowScriptAccess\" value=\"always\" /\u003E\u003Cparam name=\"FlashVars\" value=\"content=http://media1.podtech.net/media/2007/09/PID012533/PodtechRandiZuckerberg2.flv\u0026totalTime=2149000\u0026permalink=http://www.podtech.net/home/4118/the-first-sister-of-facebook\u0026breadcrumb=73536e08d3f742de9d31b25a319af359\" height=\"299\" width=\"450\" /\u003E\u003Cparam name=\"movie\" value=\"http://www.podtech.net/player/podtech-player.swf?bc=73536e08d3f742de9d31b25a319af359\" /\u003E\u003Cparam name=\"quality\" value=\"high\" /\u003E\u003Cparam name=\"scale\" value=\"noscale\" /\u003E\u003Cparam name=\"bgcolor\" value=\"#000000\" /\u003E\u003Cembed name=\"player73536e08d3f742de9d31b25a319af359\" type=\"application/x-shockwave-flash\" src=\"http://www.podtech.net/player/podtech-player.swf?bc=73536e08d3f742de9d31b25a319af359\" flashvars=\"content=http://media1.podtech.net/media/2007/09/PID012533/PodtechRandiZuckerberg2.flv\u0026totalTime=2149000\u0026permalink=http://www.podtech.net/home/4118/the-first-sister-of-facebook\u0026breadcrumb=73536e08d3f742de9d31b25a319af359\" height=\"299\" width=\"450\" allowScriptAccess=\"always\" /\u003E\u003C/object\u003E\u003Cnoscript\u003EYour browser does not support JavaScript. This media can be viewed at http://www.podtech.net/home/4118/the-first-sister-of-facebook\u003C/noscript\u003E",
+    "description": "\u003Cp\u003ERobert Scoble\u2019s video from www.podtech.net/scobleshow:\u003C/p\u003E"}],
+ "external_links":
+  [{"external_url": "http://www.marketwatch.com/news/story/story.aspx?guid={E4097AA2-9EA3-4773-9100-456E68EE1C9A}",
+    "title": "Hong Kong tycoon Li raises personal Facebook investment above $100 mln"}]}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/data/json/sparql-select-result.json	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,78 @@
+{
+	"head": {
+	   "link": [
+		   "http://www.w3.org/TR/rdf-sparql-XMLres/example.rq"
+		   ],
+	   "vars": [
+		   "x",
+		   "hpage",
+		   "name",
+		   "mbox",
+		   "age",
+		   "blurb",
+		   "friend"
+		   ]
+	   },
+   "results": {
+       "bindings": [
+               {
+                   "x" : {
+                     "type": "bnode",
+                     "value": "r1"
+                   },
+
+                   "hpage" : {
+                     "type": "uri",
+                     "value": "http://work.example.org/alice/"
+                   },
+
+                   "name" : {
+                     "type": "literal",
+                     "value": "Alice"
+                   },
+                   
+                   "mbox" : {
+                     "type": "literal",
+                     "value": ""
+                   },
+
+                   "blurb" : {
+                     "datatype": "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral",
+                     "type": "typed-literal",
+                     "value": "<p xmlns=\"http://www.w3.org/1999/xhtml\">My name is <b>alice</b></p>"
+                   },
+
+                   "friend" : {
+                     "type": "bnode",
+                     "value": "r2"
+                   }
+               },{
+                   "x" : {
+                     "type": "bnode",
+                     "value": "r2"
+                   },
+                   
+                   "hpage" : {
+                     "type": "uri",
+                     "value": "http://work.example.org/bob/"
+                   },
+                   
+                   "name" : {
+                     "type": "literal",
+                     "value": "Bob",
+                     "xml:lang": "en"
+                   },
+
+                   "mbox" : {
+                     "type": "uri",
+                     "value": "mailto:bob@work.example.org"
+                   },
+
+                   "friend" : {
+                     "type": "bnode",
+                     "value": "r1"
+                   }
+               }
+           ]
+       }
+   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/data/nt/test.nt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,78 @@
+#
+# Copyright World Wide Web Consortium, (Massachusetts Institute of
+# Technology, Institut National de Recherche en Informatique et en
+# Automatique, Keio University).
+#
+# All Rights Reserved.
+#
+# Please see the full Copyright clause at
+# <http://www.w3.org/Consortium/Legal/copyright-software.html>
+#
+# Test file with a variety of legal N-Triples
+#
+# Dave Beckett - http://purl.org/net/dajobe/
+# 
+# $Id: test.nt,v 1.7 2003/10/06 15:52:19 dbeckett2 Exp $
+# 
+#####################################################################
+
+# comment lines
+  	  	   # comment line after whitespace
+# empty blank line, then one with spaces and tabs
+
+         	
+<http://example.org/resource1> <http://example.org/property> <http://example.org/resource2> .
+_:anon <http://example.org/property> <http://example.org/resource2> .
+<http://example.org/resource2> <http://example.org/property> _:anon .
+# spaces and tabs throughout:
+ 	 <http://example.org/resource3> 	 <http://example.org/property>	 <http://example.org/resource2> 	.	 
+
+# line ending with CR NL (ASCII 13, ASCII 10)
+<http://example.org/resource4> <http://example.org/property> <http://example.org/resource2> .
+
+# 2 statement lines separated by single CR (ASCII 10)
+<http://example.org/resource5> <http://example.org/property> <http://example.org/resource2> .
<http://example.org/resource6> <http://example.org/property> <http://example.org/resource2> .
+
+
+# All literal escapes
+<http://example.org/resource7> <http://example.org/property> "simple literal" .
+<http://example.org/resource8> <http://example.org/property> "backslash:\\" .
+<http://example.org/resource9> <http://example.org/property> "dquote:\"" .
+<http://example.org/resource10> <http://example.org/property> "newline:\n" .
+<http://example.org/resource11> <http://example.org/property> "return\r" .
+<http://example.org/resource12> <http://example.org/property> "tab:\t" .
+
+# Space is optional before final .
+<http://example.org/resource13> <http://example.org/property> <http://example.org/resource2>.
+<http://example.org/resource14> <http://example.org/property> "x".
+<http://example.org/resource15> <http://example.org/property> _:anon.
+
+# \u and \U escapes
+# latin small letter e with acute symbol \u00E9 - 3 UTF-8 bytes #xC3 #A9
+<http://example.org/resource16> <http://example.org/property> "\u00E9" .
+# Euro symbol \u20ac  - 3 UTF-8 bytes #xE2 #x82 #xAC
+<http://example.org/resource17> <http://example.org/property> "\u20AC" .
+# resource18 test removed
+# resource19 test removed
+# resource20 test removed
+
+# XML Literals as Datatyped Literals
+<http://example.org/resource21> <http://example.org/property> ""^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource22> <http://example.org/property> " "^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource23> <http://example.org/property> "x"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource23> <http://example.org/property> "\""^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource24> <http://example.org/property> "<a></a>"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource25> <http://example.org/property> "a <b></b>"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource26> <http://example.org/property> "a <b></b> c"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource26> <http://example.org/property> "a\n<b></b>\nc"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+<http://example.org/resource27> <http://example.org/property> "chat"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .
+# resource28 test removed 2003-08-03
+# resource29 test removed 2003-08-03
+
+# Plain literals with languages
+<http://example.org/resource30> <http://example.org/property> "chat"@fr .
+<http://example.org/resource31> <http://example.org/property> "chat"@en .
+
+# Typed Literals
+<http://example.org/resource32> <http://example.org/property> "abc"^^<http://example.org/datatype1> .
+# resource33 test removed 2003-08-03
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/data/rdfxml/planetrdf-bloggers.rdf	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1439 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- this is a comment -->
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:rss="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:html="http://www.w3.org/1999/xhtml">
+
+<foaf:Agent rdf:nodeID="id2245565"> 
+<foaf:name>Planet RDF</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.planetrdf.com/"> 
+<dc:title>Planet RDF site blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.planetrdf.com/rss.xml"> 
+<foaf:maker rdf:nodeID="id2245565"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245590"> 
+<foaf:name>AKSW Group - University of Leipzig</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.aksw.org/"> 
+<dc:title>AKSW Group - University of Leipzig</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.aksw.org/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2245590"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245615"> 
+<foaf:name>Dean Allemang</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://dallemang.typepad.com/"> 
+<dc:title>S is for Semantics by Dean Allemang</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://dallemang.typepad.com/my_weblog/index.rdf"> 
+<foaf:maker rdf:nodeID="id2245615"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245641"> 
+<foaf:name>Zoltan Andrejkovics</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.andzol.com/"> 
+<dc:title>Zoltan Andrejkovics</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.andzol.com/?feed=rdf"> 
+<foaf:maker rdf:nodeID="id2245641"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245665"> 
+<foaf:name>Al Baker</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>AlBaker_Dev</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://linkedjava.blogspot.com/"> 
+<dc:title>Linked Java by Al Baker</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://linkedjava.blogspot.com/feeds/posts/default"> 
+<foaf:maker rdf:nodeID="id2245665"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245701"> 
+<foaf:name>Dave Beckett</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dajobe</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://journal.dajobe.org/journal/"> 
+<dc:title>Journalblog by Dave Beckett</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://journal.dajobe.org/journal/comments.rdf"> 
+<foaf:maker rdf:nodeID="id2245701"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245737"> 
+<foaf:name>Tim Berners-Lee</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>timberners_lee</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://dig.csail.mit.edu/breadcrumbs/blog/4"> 
+<dc:title>Tim Berners-Lee</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://dig.csail.mit.edu/breadcrumbs/blog/feed/4"> 
+<foaf:maker rdf:nodeID="id2245737"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245776"> 
+<foaf:name>Uldis Bojars</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>CaptSolo</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://captsolo.net/info/"> 
+<dc:title>Uldis Bojars (Captain Solo)</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://captsolo.net/info/xmlsrv/rdf.php?blog=2&amp;cat=3"> 
+<foaf:maker rdf:nodeID="id2245776"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245809"> 
+<foaf:name>John Breslin</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>johnbreslin</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.johnbreslin.com/blog/"> 
+<dc:title>Cloudlands by John Breslin</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.johnbreslin.com/blog/category/semantic-web/rdf"> 
+<foaf:maker rdf:nodeID="id2245809"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245844"> 
+<foaf:name>Dan Brickley</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>danbri</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://danbri.org/words/"> 
+<dc:title>danbri's foaf stories</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://danbri.org/words/category/technology/rdf"> 
+<foaf:maker rdf:nodeID="id2245844"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245877"> 
+<foaf:name>Jeen Broekstra</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>jeenbroekstra</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://rivuli-development.com/weblog/"> 
+<dc:title>Rivuli by Jeen Broekstra</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://rivuli-development.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2245877"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245911"> 
+<foaf:name>Dries Buytaert</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dries</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://buytaert.net/tag/semantic-web"> 
+<dc:title>Dries Buytaert - Semantic Web</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://buytaert.net/taxonomy/term/61/0/feed"> 
+<foaf:maker rdf:nodeID="id2245911"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245946"> 
+<foaf:name>Cambridge Semantics</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.cambridgesemantics.com/blog/"> 
+<dc:title>Cambridge Semantics</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/EnterpriseSemantics"> 
+<foaf:maker rdf:nodeID="id2245946"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2245972"> 
+<foaf:name>Clark and Parsia</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>candp</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://clarkparsia.com/weblog/"> 
+<dc:title>Tales of a Semantic Web Consultancy by Clark and Parsia</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://clarkparsia.com/weblog/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2245972"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257265"> 
+<foaf:name>Dan Connolly</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dckc</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.madmode.com/"> 
+<dc:title>Dan Connolly</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.madmode.com/feeds/posts/default"> 
+<foaf:maker rdf:nodeID="id2257265"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257300"> 
+<foaf:name>Richard Cyganiak</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>cygri</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://dowhatimean.net/"> 
+<dc:title>Richard Cyganiak</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://dowhatimean.net/category/semantic-web/rdf"> 
+<foaf:maker rdf:nodeID="id2257300"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257332"> 
+<foaf:name>Datagraph</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>datagraph</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.datagraph.org/"> 
+<dc:title>Datagraph</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/datagraph"> 
+<foaf:maker rdf:nodeID="id2257332"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257365"> 
+<foaf:name>Phil Dawes</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>phildawes</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.phildawes.net/blog/"> 
+<dc:title>Phil Dawes</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.phildawes.net/blog/category/semantic-web/rdf"> 
+<foaf:maker rdf:nodeID="id2257365"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257399"> 
+<foaf:name>Yves Raimond</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>moustaki</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.dbtune.org/"> 
+<dc:title>DBTune by Yves Raimond</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.dbtune.org/feed/rss2"> 
+<foaf:maker rdf:nodeID="id2257399"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257433"> 
+<foaf:name>DERI Galway</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.deri.ie/"> 
+<dc:title>DERI Galway</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.deri.ie/fileadmin/feed.rdf"> 
+<foaf:maker rdf:nodeID="id2257433"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257457"> 
+<foaf:name>DOAP Project</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://usefulinc.com/doap"> 
+<dc:title>DOAP Project</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://usefulinc.com/doap/news/rss"> 
+<foaf:maker rdf:nodeID="id2257457"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257481"> 
+<foaf:name>Leigh Dodds</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>ldodds</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://ldodds.com/blog/"> 
+<dc:title>Lost Boy by Leigh Dodds</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.ldodds.com/blog/index.rdf"> 
+<foaf:maker rdf:nodeID="id2257481"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257514"> 
+<foaf:name>Dublin Core Metadata Initiative</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>DublinCore</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.dublincore.org/"> 
+<dc:title>Dublin Core Metadata Initiative</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://dublincore.org/news.rss"> 
+<foaf:maker rdf:nodeID="id2257514"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257547"> 
+<foaf:name>Bob DuCharme</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>bobdc</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.snee.com/bobdc.blog/"> 
+<dc:title>bobdc.blog by Bob DuCharme</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.snee.com/bobdc.blog/bobdcblog.rdf"> 
+<foaf:maker rdf:nodeID="id2257547"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257581"> 
+<foaf:name>Edd Dumbill</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>edd</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://usefulinc.com/edd/blog"> 
+<dc:title>behind the times by Edd Dumbill</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://times.usefulinc.com/rss"> 
+<foaf:maker rdf:nodeID="id2257581"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257615"> 
+<foaf:name>Ebiquity research group UMBC</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://ebiquity.umbc.edu/blogger"> 
+<dc:title>Ebiquity research group UMBC</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://ebiquity.umbc.edu/blogger/category/semanticweb/rdf"> 
+<foaf:maker rdf:nodeID="id2257615"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257642"> 
+<foaf:name>Dydra</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dydradata</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.dydra.com/"> 
+<dc:title>Dydra</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/dydra"> 
+<foaf:maker rdf:nodeID="id2257642"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257675"> 
+<foaf:name>EnAKTing project</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blogs.ecs.soton.ac.uk/enakting/"> 
+<dc:title>EnAKTing project</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blogs.ecs.soton.ac.uk/enakting/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257675"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257701"> 
+<foaf:name>Orri Erling</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.openlinksw.com/weblogs/oerling/"> 
+<dc:title>Orri Erling by </dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.openlinksw.com/weblogs/oerling/gems/index.rdf"> 
+<foaf:maker rdf:nodeID="id2257701"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257726"> 
+<foaf:name>Lee Feigenbaum</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>LeeFeigenbaum</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.thefigtrees.net/lee/blog/semantic_web/"> 
+<dc:title>Lee Feigenbaum</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://thefigtrees.net/lee/blog/semantic_web/index.rdf"> 
+<foaf:maker rdf:nodeID="id2257726"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257760"> 
+<foaf:name>Sergio Fernández</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.wikier.org/blog/"> 
+<dc:title>Sergio Fernández</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/wikier-semantics"> 
+<foaf:maker rdf:nodeID="id2257760"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257787"> 
+<foaf:name>FOAF Project</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.foaf-project.org/"> 
+<dc:title>FOAF Project blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.foaf-project.org/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257787"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257813"> 
+<foaf:name>Morten Frederiksen</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>mortenf</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.wasab.dk/morten/blog/"> 
+<dc:title>Binary Relations by Morten Frederiksen</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.wasab.dk/morten/blog/archives/category/semweb/feed/"> 
+<foaf:maker rdf:nodeID="id2257813"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257847"> 
+<foaf:name>Frederick Giasson</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://fgiasson.com/blog/"> 
+<dc:title>Frederick Giasson</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://fgiasson.com/blog/index.php/category/fredblog/web/semantic-web/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257847"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257872"> 
+<foaf:name>John Goodwin</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>gothwin</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://johngoodwin225.wordpress.com/"> 
+<dc:title>John Goodwin</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://johngoodwin225.wordpress.com/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257872"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257906"> 
+<foaf:name>Richard Hancock</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.3kbo.com/"> 
+<dc:title>3kbo by Richard Hancock</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.3kbo.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2257906"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257931"> 
+<foaf:name>Michael Hausenblas</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>mhausenblas</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://webofdata.wordpress.com/"> 
+<dc:title>Web of Data by Michael Hausenblas</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://webofdata.wordpress.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2257931"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2257966"> 
+<foaf:name>Sandro Hawke</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>sandhawke</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://decentralyze.com/"> 
+<dc:title> Decentralyze – Programming the Data Cloud by Sandro Hawke</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://decentralyze.com/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2257966"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258003"> 
+<foaf:name>Tom Heath</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>tommyh</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://tomheath.com/blog/"> 
+<dc:title>Displacement Activities by Tom Heath</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://tomheath.com/blog/comments/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2258003"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258035"> 
+<foaf:name>Ivan Herman</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>ivan_herman</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://ivanherman.wordpress.com/tag/work-related/semantic-web/"> 
+<dc:title>Ivan Herman</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://ivan-herman.name/category/work-related/semantic-web/feed"> 
+<foaf:maker rdf:nodeID="id2258035"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258069"> 
+<foaf:name>Kingsley Idehen</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>Kidehen</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.openlinksw.com/blog/~kidehen/"> 
+<dc:title>Data Space by Kingsley Idehen</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.openlinksw.com/blog/~kidehen/gems/index.rdf"> 
+<foaf:maker rdf:nodeID="id2258069"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258104"> 
+<foaf:name>Learn Linked Data</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>learnlinkeddata</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://learnlinkeddata.com/"> 
+<dc:title>Learn Linked Data</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/learnlinkeddata"> 
+<foaf:maker rdf:nodeID="id2258104"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258138"> 
+<foaf:name>Talis</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>nodalities</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blogs.talis.com/nodalities/"> 
+<dc:title>Nodalities by Talis</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blogs.talis.com/nodalities/index.rdf"> 
+<foaf:maker rdf:nodeID="id2258138"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258172"> 
+<foaf:name>Seevl</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>seevl</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.seevl.net/category/technology/"> 
+<dc:title>Seevl technology</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.seevl.net/category/technology/feed/"> 
+<foaf:maker rdf:nodeID="id2258172"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258208"> 
+<foaf:name>Semantic Web Company (Austria)</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>semwebcompany</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.semantic-web.at/"> 
+<dc:title>Semantic Puzzle by Semantic Web Company (Austria)</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.semantic-web.at/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258208"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258266"> 
+<foaf:name>SchemaWeb</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.schemaweb.info/"> 
+<dc:title>SchemaWeb</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.schemaweb.info/blogrss.aspx?blogid=2"> 
+<foaf:maker rdf:nodeID="id2258266"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258290"> 
+<foaf:name>Ora Lassila</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.lassila.org/blog/"> 
+<dc:title>Wilbur-and-O by Ora Lassila</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.lassila.org/blog/index.rdf"> 
+<foaf:maker rdf:nodeID="id2258290"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258316"> 
+<foaf:name>Peter Mika</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://tripletalk.wordpress.com/"> 
+<dc:title>Tripletalk by Peter Mika</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://tripletalk.wordpress.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258316"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258342"> 
+<foaf:name>Andrew Matthews</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://aabs.wordpress.com/"> 
+<dc:title>The Wandering Glitch 2 by Andrew Matthews</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://aabs.wordpress.com/category/semanticweb/rdf"> 
+<foaf:maker rdf:nodeID="id2258342"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258368"> 
+<foaf:name>ZDNet Semantic Web by Paul Miller</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>PaulMiller</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blogs.zdnet.com/semantic-web/"> 
+<dc:title>ZDNet Semantic Web by Paul Miller</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.zdnet.com/blog/semantic-web/rss"> 
+<foaf:maker rdf:nodeID="id2258368"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258402"> 
+<foaf:name>Libby Miller</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>libbymiller</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://planb.nicecupoftea.org/"> 
+<dc:title>Plan B by Libby Miller</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://planb.nicecupoftea.org/feed/?feed=rdf"> 
+<foaf:maker rdf:nodeID="id2258402"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258436"> 
+<foaf:name>Benjamin Nowack</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>bengee</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.bnode.org/en-semweblog"> 
+<dc:title>bnode by Benjamin Nowack</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.bnode.org/rdfxml/page/en-semweblog"> 
+<foaf:maker rdf:nodeID="id2258436"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258470"> 
+<foaf:name>Open Sahara blog</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://opensahara.com/en/blog"> 
+<dc:title>Open Sahara blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds.feedburner.com/OpenSahara-Blog"> 
+<foaf:maker rdf:nodeID="id2258470"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258505"> 
+<foaf:name>Alexandre Passant</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>terraces</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://apassant.net/blog/"> 
+<dc:title>Alexandre Passant</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://apassant.net/taxonomy/term/3/feed"> 
+<foaf:maker rdf:nodeID="id2258505"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258537"> 
+<foaf:name>Davide Palmisano</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>dpalmisano</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://davidepalmisano.wordpress.com/"> 
+<dc:title>turn off the lights, please by Davide Palmisano</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://davidepalmisano.wordpress.com/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2258537"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258573"> 
+<foaf:name>POWDER WG blog</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.w3.org/blog/powder"> 
+<dc:title>POWDER WG blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.w3.org/blog/powder?tempskin=_rdf"> 
+<foaf:maker rdf:nodeID="id2258573"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258598"> 
+<foaf:name>RDFa</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://rdfa.info/"> 
+<dc:title>RDFa</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://rdfa.info/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258598"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258622"> 
+<foaf:name>Dave Raggett</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>draggett</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://people.w3.org/~dsr/blog/"> 
+<dc:title>Dave Raggett</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://people.w3.org/~dsr/blog/?feed=rdf"> 
+<foaf:maker rdf:nodeID="id2258622"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258655"> 
+<foaf:name>David Robillard</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>drobilla</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://drobilla.net/category/semweb/"> 
+<dc:title>David Robillard</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://drobilla.net/category/semweb/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2258655"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258688"> 
+<foaf:name>RDF Resource Guide</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://planetrdf.com/guide/"> 
+<dc:title>Dave Beckett's RDF Resource Guide</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://planetrdf.com/guide/rss.rdf"> 
+<foaf:maker rdf:nodeID="id2258688"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258714"> 
+<foaf:name>Peter Shaw</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://shawfactor.com/"> 
+<dc:title>Shawfactor by Peter Shaw</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://shawfactor.com/tag/semantic/feed/"> 
+<foaf:maker rdf:nodeID="id2258714"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258740"> 
+<foaf:name>schema.org</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blog.schema.org/"> 
+<dc:title>schema.org</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blog.schema.org/feeds/posts/default?alt=rss"> 
+<foaf:maker rdf:nodeID="id2258740"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258766"> 
+<foaf:name>Henry Story</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>bblfish</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://blogs.sun.com/bblfish/"> 
+<dc:title>BabelFish by Henry Story</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://blogs.sun.com/bblfish/page/rss10.xml"> 
+<foaf:maker rdf:nodeID="id2258766"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258801"> 
+<foaf:name>Jeni Tennison</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>JeniT</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.jenitennison.com/blog/"> 
+<dc:title>Jeni Tennison - Musings</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.jenitennison.com/blog/atom/feed"> 
+<foaf:maker rdf:nodeID="id2258801"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258835"> 
+<foaf:name>Tetherless World Constellation group RPI</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>jahendler</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://tw.rpi.edu/weblog/feed/rdf/"> 
+<dc:title>Tetherless World Constellation group RPI</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://tw.rpi.edu/weblog/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2258835"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258869"> 
+<foaf:name>Elias Torres</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://torrez.us/"> 
+<dc:title>Elias Torres</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://torrez.us/archives/category/semweb/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258869"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258903"> 
+<foaf:name>Sebastian Trueg</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://trueg.wordpress.com/"> 
+<dc:title>Semantic Desktop by Sebastian Trueg</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://trueg.wordpress.com/feed/rdf"> 
+<foaf:maker rdf:nodeID="id2258903"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258928"> 
+<foaf:name>W3C Semantic Web News</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.w3.org/2001/sw/"> 
+<dc:title>W3C Semantic Web News</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.w3.org/blog/xmlsrv/rdf.php?blog=13"> 
+<foaf:maker rdf:nodeID="id2258928"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258952"> 
+<foaf:name>W3C Read Write Web Community Group</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.w3.org/community/rww/"> 
+<dc:title>W3C Read Write Web Community Group Blog</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.w3.org/community/rww/feed/"> 
+<foaf:maker rdf:nodeID="id2258952"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2258979"> 
+<foaf:name>W3C Blog Semantic Web News</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.w3.org/QA/"> 
+<dc:title>W3C Blog Semantic Web News</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.ivan-herman.net/cgi-bin/toRss1.py?uri=http://www.w3.org/QA/atom.xml&amp;categories=[Semantic+Web]&amp;title=W3C+QA+Blog,+Semantic+Web&amp;link=http://www.w3.org/QA/atom.xml"> 
+<foaf:maker rdf:nodeID="id2258979"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259004"> 
+<foaf:name>Norm Walsh</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>ndw</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://norman.walsh.name/"> 
+<dc:title>Norm Walsh</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://norman.walsh.name/index.rss"> 
+<foaf:maker rdf:nodeID="id2259004"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259036"> 
+<foaf:name>Mark Watson</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>mark_l_watson</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://markwatson.com/blog/"> 
+<dc:title>Mark Watson</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://markwatson.com/blog/atom.xml"> 
+<foaf:maker rdf:nodeID="id2259036"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259070"> 
+<foaf:name>Danny Weitzner</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>djweitzner</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://people.w3.org/~djweitzner/blog/?cat=8"> 
+<dc:title>Open Internet Policy by Danny Weitzner</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://people.w3.org/~djweitzner/blog/?cat=8&amp;feed=rdf"> 
+<foaf:maker rdf:nodeID="id2259070"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259105"> 
+<foaf:name>Web of Data</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://webofdata.wordpress.com/"> 
+<dc:title>Web of Data</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://webofdata.wordpress.com/feed/rdf/"> 
+<foaf:maker rdf:nodeID="id2259105"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259130"> 
+<foaf:name>Bill Roberts</foaf:name> 
+<rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>billroberts</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.webofdatablog.com/"> 
+<dc:title>Web of Data by Bill Roberts</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://feeds2.feedburner.com/webofdatablog"> 
+<foaf:maker rdf:nodeID="id2259130"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259165"> 
+<foaf:name>Web Semántica Hoy</foaf:name> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://www.wshoy.sidar.org/index.php"> 
+<dc:title>Web Semántica Hoy</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://www.wshoy.sidar.org/rss.php"> 
+<foaf:maker rdf:nodeID="id2259165"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259199"> 
+<foaf:name>Gregory Williams</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>kasei</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://kasei.us/"> 
+<dc:title>Gregory Williams</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://kasei.us/archives/categories/technology/semantic_web/index.rdf"> 
+<foaf:maker rdf:nodeID="id2259199"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+<foaf:Agent rdf:nodeID="id2259232"> 
+<foaf:name>Egon Willighagen</foaf:name><foaf:holdsAccount><foaf:OnlineAccount><foaf:accountServiceHomepage rdf:resource="http://twitter.com/"/><foaf:accountName>egonwillighagen</foaf:accountName></foaf:OnlineAccount></foaf:holdsAccount> 
+<foaf:weblog> 
+<foaf:Document rdf:about="http://chem-bla-ics.blogspot.com/"> 
+<dc:title>chem-bla-ics by Egon Willighagen</dc:title> 
+<rdfs:seeAlso> 
+<rss:channel rdf:about="http://chem-bla-ics.blogspot.com/feeds/posts/default/-/RDF?alt=rss"> 
+<foaf:maker rdf:nodeID="id2259232"/> 
+<foaf:topic rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:topic rdf:resource="http://www.w3.org/RDF/"/> 
+</rss:channel> 
+</rdfs:seeAlso> 
+</foaf:Document> 
+</foaf:weblog> 
+<foaf:interest rdf:resource="http://www.w3.org/2001/sw/"/> 
+<foaf:interest rdf:resource="http://www.w3.org/RDF/"/> 
+</foaf:Agent> 
+
+</rdf:RDF> 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/data/turtle/manifest.ttl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,2190 @@
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+# Test named *subm* are (c) W3C and taken from the Turtle submission.
+
+@prefix rdf:    <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix rdfs:    <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> .
+@prefix qt:     <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> .
+
+@prefix rdft:   <http://www.w3.org/ns/rdftest#> .
+
+<>  rdf:type mf:Manifest ;
+    rdfs:comment "Turtle tests" ;
+    mf:entries
+    (
+
+    # atomic tests
+    <#IRI_subject>
+    <#IRI_with_four_digit_numeric_escape>
+    <#IRI_with_eight_digit_numeric_escape>
+    <#IRI_with_all_punctuation>
+    <#bareword_a_predicate>
+    <#old_style_prefix>
+    <#SPARQL_style_prefix>
+    <#prefixed_IRI_predicate>
+    <#prefixed_IRI_object>
+    <#prefix_only_IRI>
+    <#prefix_with_PN_CHARS_BASE_character_boundaries>
+    <#prefix_with_non_leading_extras>
+    <#default_namespace_IRI>
+    <#prefix_reassigned_and_used>
+    <#reserved_escaped_localName>
+    <#percent_escaped_localName>
+    <#HYPHEN_MINUS_in_localName>
+    <#underscore_in_localName>
+    <#localname_with_COLON>
+    <#localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries>
+    <#localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries>
+    <#localName_with_nfc_PN_CHARS_BASE_character_boundaries>
+    <#localName_with_PN_CHARS_BASE_character_boundaries>
+    <#localName_with_leading_underscore>
+    <#localName_with_leading_digit>
+    <#localName_with_non_leading_extras>
+    <#old_style_base>
+    <#SPARQL_style_base>
+    <#labeled_blank_node_subject>
+    <#labeled_blank_node_object>
+    <#labeled_blank_node_with_PN_CHARS_BASE_character_boundaries>
+    <#labeled_blank_node_with_leading_underscore>
+    <#labeled_blank_node_with_leading_digit>
+    <#labeled_blank_node_with_non_leading_extras>
+    <#anonymous_blank_node_subject>
+    <#anonymous_blank_node_object>
+    <#sole_blankNodePropertyList>
+    <#blankNodePropertyList_as_subject>
+    <#blankNodePropertyList_as_object>
+    <#blankNodePropertyList_with_multiple_triples>
+    <#nested_blankNodePropertyLists>
+    <#blankNodePropertyList_containing_collection>
+    <#collection_subject>
+    <#collection_object>
+    <#empty_collection>
+    <#nested_collection>
+    <#first>
+    <#last>
+    <#LITERAL1>
+    <#LITERAL1_ascii_boundaries>
+    <#LITERAL1_with_UTF8_boundaries>
+    <#LITERAL1_all_controls>
+    <#LITERAL1_all_punctuation>
+    <#LITERAL_LONG1>
+    <#LITERAL_LONG1_ascii_boundaries>
+    <#LITERAL_LONG1_with_UTF8_boundaries>
+    <#LITERAL_LONG1_with_1_squote>
+    <#LITERAL_LONG1_with_2_squotes>
+    <#LITERAL2>
+    <#LITERAL2_ascii_boundaries>
+    <#LITERAL2_with_UTF8_boundaries>
+    <#LITERAL_LONG2>
+    <#LITERAL_LONG2_ascii_boundaries>
+    <#LITERAL_LONG2_with_UTF8_boundaries>
+    <#LITERAL_LONG2_with_1_squote>
+    <#LITERAL_LONG2_with_2_squotes>
+    <#literal_with_CHARACTER_TABULATION>
+    <#literal_with_BACKSPACE>
+    <#literal_with_LINE_FEED>
+    <#literal_with_CARRIAGE_RETURN>
+    <#literal_with_FORM_FEED>
+    <#literal_with_REVERSE_SOLIDUS>
+    <#literal_with_escaped_CHARACTER_TABULATION>
+    <#literal_with_escaped_BACKSPACE>
+    <#literal_with_escaped_LINE_FEED>
+    <#literal_with_escaped_CARRIAGE_RETURN>
+    <#literal_with_escaped_FORM_FEED>
+    <#literal_with_numeric_escape4>
+    <#literal_with_numeric_escape8>
+    <#IRIREF_datatype>
+    <#prefixed_name_datatype>
+    <#bareword_integer>
+    <#bareword_decimal>
+    <#bareword_double>
+    <#double_lower_case_e>
+    <#negative_numeric>
+    <#positive_numeric>
+    <#numeric_with_leading_0>
+    <#literal_true>
+    <#literal_false>
+    <#langtagged_non_LONG>
+    <#langtagged_LONG>
+    <#lantag_with_subtag>
+    <#objectList_with_two_objects>
+    <#predicateObjectList_with_two_objectLists>
+    <#repeated_semis_at_end>
+    <#repeated_semis_not_at_end>
+
+    # original tests-ttl
+    <#turtle-syntax-file-01>
+    <#turtle-syntax-file-02>
+    <#turtle-syntax-file-03>
+    <#turtle-syntax-uri-01>
+    <#turtle-syntax-uri-02>
+    <#turtle-syntax-uri-03>
+    <#turtle-syntax-uri-04>
+    <#turtle-syntax-base-01>
+    <#turtle-syntax-base-02>
+    <#turtle-syntax-base-03>
+    <#turtle-syntax-base-04>
+    <#turtle-syntax-prefix-01>
+    <#turtle-syntax-prefix-02>
+    <#turtle-syntax-prefix-03>
+    <#turtle-syntax-prefix-04>
+    <#turtle-syntax-prefix-05>
+    <#turtle-syntax-prefix-06>
+    <#turtle-syntax-prefix-07>
+    <#turtle-syntax-prefix-08>
+    <#turtle-syntax-prefix-09>
+    <#turtle-syntax-string-01>
+    <#turtle-syntax-string-02>
+    <#turtle-syntax-string-03>
+    <#turtle-syntax-string-04>
+    <#turtle-syntax-string-05>
+    <#turtle-syntax-string-06>
+    <#turtle-syntax-string-07>
+    <#turtle-syntax-string-08>
+    <#turtle-syntax-string-09>
+    <#turtle-syntax-string-10>
+    <#turtle-syntax-string-11>
+    <#turtle-syntax-str-esc-01>
+    <#turtle-syntax-str-esc-02>
+    <#turtle-syntax-str-esc-03>
+    <#turtle-syntax-pname-esc-01>
+    <#turtle-syntax-pname-esc-02>
+    <#turtle-syntax-pname-esc-03>
+    <#turtle-syntax-bnode-01>
+    <#turtle-syntax-bnode-02>
+    <#turtle-syntax-bnode-03>
+    <#turtle-syntax-bnode-04>
+    <#turtle-syntax-bnode-05>
+    <#turtle-syntax-bnode-06>
+    <#turtle-syntax-bnode-07>
+    <#turtle-syntax-bnode-08>
+    <#turtle-syntax-bnode-09>
+    <#turtle-syntax-bnode-10>
+    <#turtle-syntax-number-01>
+    <#turtle-syntax-number-02>
+    <#turtle-syntax-number-03>
+    <#turtle-syntax-number-04>
+    <#turtle-syntax-number-05>
+    <#turtle-syntax-number-06>
+    <#turtle-syntax-number-07>
+    <#turtle-syntax-number-08>
+    <#turtle-syntax-number-09>
+    <#turtle-syntax-number-10>
+    <#turtle-syntax-number-11>
+    <#turtle-syntax-datatypes-01>
+    <#turtle-syntax-datatypes-02>
+    <#turtle-syntax-kw-01>
+    <#turtle-syntax-kw-02>
+    <#turtle-syntax-kw-03>
+    <#turtle-syntax-struct-01>
+    <#turtle-syntax-struct-02>
+    <#turtle-syntax-struct-03>
+    <#turtle-syntax-struct-04>
+    <#turtle-syntax-struct-05>
+    <#turtle-syntax-lists-01>
+    <#turtle-syntax-lists-02>
+    <#turtle-syntax-lists-03>
+    <#turtle-syntax-lists-04>
+    <#turtle-syntax-lists-05>
+    <#turtle-syntax-bad-uri-01>
+    <#turtle-syntax-bad-uri-02>
+    <#turtle-syntax-bad-uri-03>
+    <#turtle-syntax-bad-uri-04>
+    <#turtle-syntax-bad-uri-05>
+    <#turtle-syntax-bad-prefix-01>
+    <#turtle-syntax-bad-prefix-02>
+    <#turtle-syntax-bad-prefix-03>
+    <#turtle-syntax-bad-prefix-04>
+    <#turtle-syntax-bad-prefix-05>
+    <#turtle-syntax-bad-base-01>
+    <#turtle-syntax-bad-base-02>
+    <#turtle-syntax-bad-base-03>
+    <#turtle-syntax-bad-struct-01>
+    <#turtle-syntax-bad-struct-02>
+    <#turtle-syntax-bad-struct-03>
+    <#turtle-syntax-bad-struct-04>
+    <#turtle-syntax-bad-struct-05>
+    <#turtle-syntax-bad-struct-06>
+    <#turtle-syntax-bad-struct-07>
+    <#turtle-syntax-bad-kw-01>
+    <#turtle-syntax-bad-kw-02>
+    <#turtle-syntax-bad-kw-03>
+    <#turtle-syntax-bad-kw-04>
+    <#turtle-syntax-bad-kw-05>
+    <#turtle-syntax-bad-n3-extras-01>
+    <#turtle-syntax-bad-n3-extras-02>
+    <#turtle-syntax-bad-n3-extras-03>
+    <#turtle-syntax-bad-n3-extras-04>
+    <#turtle-syntax-bad-n3-extras-05>
+    <#turtle-syntax-bad-n3-extras-06>
+    <#turtle-syntax-bad-n3-extras-07>
+    <#turtle-syntax-bad-n3-extras-08>
+    <#turtle-syntax-bad-n3-extras-09>
+    <#turtle-syntax-bad-n3-extras-10>
+    <#turtle-syntax-bad-n3-extras-11>
+    <#turtle-syntax-bad-n3-extras-12>
+    <#turtle-syntax-bad-n3-extras-13>
+    <#turtle-syntax-bad-struct-08>
+    <#turtle-syntax-bad-struct-09>
+    <#turtle-syntax-bad-struct-10>
+    <#turtle-syntax-bad-struct-11>
+    <#turtle-syntax-bad-struct-12>
+    <#turtle-syntax-bad-struct-13>
+    <#turtle-syntax-bad-struct-14>
+    <#turtle-syntax-bad-struct-15>
+    <#turtle-syntax-bad-struct-16>
+    <#turtle-syntax-bad-struct-17>
+    <#turtle-syntax-bad-lang-01>
+    <#turtle-syntax-bad-esc-01>
+    <#turtle-syntax-bad-esc-02>
+    <#turtle-syntax-bad-esc-03>
+    <#turtle-syntax-bad-esc-04>
+    <#turtle-syntax-bad-pname-01>
+    <#turtle-syntax-bad-pname-02>
+    <#turtle-syntax-bad-pname-03>
+    <#turtle-syntax-bad-string-01>
+    <#turtle-syntax-bad-string-02>
+    <#turtle-syntax-bad-string-03>
+    <#turtle-syntax-bad-string-04>
+    <#turtle-syntax-bad-string-05>
+    <#turtle-syntax-bad-string-06>
+    <#turtle-syntax-bad-string-07>
+    <#turtle-syntax-bad-num-01>
+    <#turtle-syntax-bad-num-02>
+    <#turtle-syntax-bad-num-03>
+    <#turtle-syntax-bad-num-04>
+    <#turtle-syntax-bad-num-05>
+    <#turtle-eval-struct-01>
+    <#turtle-eval-struct-02>
+    <#turtle-subm-01>
+    <#turtle-subm-02>
+    <#turtle-subm-03>
+    <#turtle-subm-04>
+    <#turtle-subm-05>
+    <#turtle-subm-06>
+    <#turtle-subm-07>
+    <#turtle-subm-08>
+    <#turtle-subm-09>
+    <#turtle-subm-10>
+    <#turtle-subm-11>
+    <#turtle-subm-12>
+    <#turtle-subm-13>
+    <#turtle-subm-14>
+    <#turtle-subm-15>
+    <#turtle-subm-16>
+    <#turtle-subm-17>
+    <#turtle-subm-18>
+    <#turtle-subm-19>
+    <#turtle-subm-20>
+    <#turtle-subm-21>
+    <#turtle-subm-22>
+    <#turtle-subm-23>
+    <#turtle-subm-24>
+    <#turtle-subm-25>
+    <#turtle-subm-26>
+    <#turtle-subm-27>
+    <#turtle-eval-bad-01>
+    <#turtle-eval-bad-02>
+    <#turtle-eval-bad-03>
+    <#turtle-eval-bad-04>
+
+    # tests from Dave Beckett
+    # http://www.w3.org/2011/rdf-wg/wiki/Turtle_Candidate_Recommendation_Comments#c28
+    <#LITERAL_LONG2_with_REVERSE_SOLIDUS>
+    <#turtle-syntax-bad-LITERAL2_with_langtag_and_datatype>
+    <#two_LITERAL_LONG2s>
+    <#langtagged_LONG_with_subtag>
+
+    # tests from David Robillard
+    # http://www.w3.org/2011/rdf-wg/wiki/Turtle_Candidate_Recommendation_Comments#c21
+    <#turtle-syntax-bad-blank-label-dot-end>
+    <#turtle-syntax-bad-ln-dash-start>
+    <#turtle-syntax-bad-ln-escape-start>
+    <#turtle-syntax-bad-ln-escape>
+    <#turtle-syntax-bad-missing-ns-dot-end>
+    <#turtle-syntax-bad-missing-ns-dot-start>
+    <#turtle-syntax-bad-ns-dot-end>
+    <#turtle-syntax-bad-ns-dot-start>
+    <#turtle-syntax-bad-number-dot-in-anon>
+    <#turtle-syntax-blank-label>
+    <#turtle-syntax-ln-colons>
+    <#turtle-syntax-ln-dots>
+    <#turtle-syntax-ns-dots>
+    ) .
+
+# atomic tests
+<#IRI_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRI_subject" ;
+   rdfs:comment "IRI subject" ;
+   mf:action    <IRI_subject.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#IRI_with_four_digit_numeric_escape> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRI_with_four_digit_numeric_escape" ;
+   rdfs:comment "IRI with four digit numeric escape (\\u)" ;
+   mf:action    <IRI_with_four_digit_numeric_escape.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#IRI_with_eight_digit_numeric_escape> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRI_with_eight_digit_numeric_escape" ;
+   rdfs:comment "IRI with eight digit numeric escape (\\U)" ;
+   mf:action    <IRI_with_eight_digit_numeric_escape.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#IRI_with_all_punctuation> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRI_with_all_punctuation" ;
+   rdfs:comment "IRI with all punctuation" ;
+   mf:action    <IRI_with_all_punctuation.ttl> ;
+   mf:result    <IRI_with_all_punctuation.nt> ;
+   .
+
+<#bareword_a_predicate> rdf:type rdft:TestTurtleEval ;
+   mf:name      "bareword_a_predicate" ;
+   rdfs:comment "bareword a predicate" ;
+   mf:action    <bareword_a_predicate.ttl> ;
+   mf:result    <bareword_a_predicate.nt> ;
+   .
+
+<#old_style_prefix> rdf:type rdft:TestTurtleEval ;
+   mf:name      "old_style_prefix" ;
+   rdfs:comment "old-style prefix" ;
+   mf:action    <old_style_prefix.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#SPARQL_style_prefix> rdf:type rdft:TestTurtleEval ;
+   mf:name      "SPARQL_style_prefix" ;
+   rdfs:comment "SPARQL-style prefix" ;
+   mf:action    <SPARQL_style_prefix.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefixed_IRI_predicate> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefixed_IRI_predicate" ;
+   rdfs:comment "prefixed IRI predicate" ;
+   mf:action    <prefixed_IRI_predicate.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefixed_IRI_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefixed_IRI_object" ;
+   rdfs:comment "prefixed IRI object" ;
+   mf:action    <prefixed_IRI_object.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefix_only_IRI> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefix_only_IRI" ;
+   rdfs:comment "prefix-only IRI (p:)" ;
+   mf:action    <prefix_only_IRI.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefix_with_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefix_with_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "prefix with PN CHARS BASE character boundaries (prefix: AZazÀÖØöø...:)" ;
+   mf:action    <prefix_with_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefix_with_non_leading_extras> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefix_with_non_leading_extras" ;
+   rdfs:comment "prefix with_non_leading_extras (_:a·̀ͯ‿.â€)" ;
+   mf:action    <prefix_with_non_leading_extras.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "localName with assigned, NFC-normalized, basic-multilingual-plane PN CHARS BASE character boundaries (p:AZazÀÖØöø...)" ;
+   mf:action    <localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <localName_with_assigned_nfc_bmp_PN_CHARS_BASE_character_boundaries.nt> ;
+   .
+
+<#localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "localName with assigned, NFC-normalized PN CHARS BASE character boundaries (p:AZazÀÖØöø...)" ;
+   mf:action    <localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <localName_with_assigned_nfc_PN_CHARS_BASE_character_boundaries.nt> ;
+   .
+
+<#localName_with_nfc_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_nfc_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "localName with nfc-normalize PN CHARS BASE character boundaries (p:AZazÀÖØöø...)" ;
+   mf:action    <localName_with_nfc_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <localName_with_nfc_PN_CHARS_BASE_character_boundaries.nt> ;
+   .
+
+<#localName_with_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "localName with PN CHARS BASE character boundaries (p:AZazÀÖØöø...)" ;
+   mf:action    <localName_with_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <localName_with_PN_CHARS_BASE_character_boundaries.nt> ;
+   .
+
+<#default_namespace_IRI> rdf:type rdft:TestTurtleEval ;
+   mf:name      "default_namespace_IRI" ;
+   rdfs:comment "default namespace IRI (:ln)" ;
+   mf:action    <default_namespace_IRI.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#prefix_reassigned_and_used> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefix_reassigned_and_used" ;
+   rdfs:comment "prefix reassigned and used" ;
+   mf:action    <prefix_reassigned_and_used.ttl> ;
+   mf:result    <prefix_reassigned_and_used.nt> ;
+   .
+
+<#reserved_escaped_localName> rdf:type rdft:TestTurtleEval ;
+   mf:name      "reserved_escaped_localName" ;
+   rdfs:comment "reserved-escaped local name" ;
+   mf:action    <reserved_escaped_localName.ttl> ;
+   mf:result    <reserved_escaped_localName.nt> ;
+   .
+
+<#percent_escaped_localName> rdf:type rdft:TestTurtleEval ;
+   mf:name      "percent_escaped_localName" ;
+   rdfs:comment "percent-escaped local name" ;
+   mf:action    <percent_escaped_localName.ttl> ;
+   mf:result    <percent_escaped_localName.nt> ;
+   .
+
+<#HYPHEN_MINUS_in_localName> rdf:type rdft:TestTurtleEval ;
+   mf:name      "HYPHEN_MINUS_in_localName" ;
+   rdfs:comment "HYPHEN-MINUS in local name" ;
+   mf:action    <HYPHEN_MINUS_in_localName.ttl> ;
+   mf:result    <HYPHEN_MINUS_in_localName.nt> ;
+   .
+
+<#underscore_in_localName> rdf:type rdft:TestTurtleEval ;
+   mf:name      "underscore_in_localName" ;
+   rdfs:comment "underscore in local name" ;
+   mf:action    <underscore_in_localName.ttl> ;
+   mf:result    <underscore_in_localName.nt> ;
+   .
+
+<#localname_with_COLON> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localname_with_COLON" ;
+   rdfs:comment "localname with COLON" ;
+   mf:action    <localname_with_COLON.ttl> ;
+   mf:result    <localname_with_COLON.nt> ;
+   .
+
+<#localName_with_leading_underscore> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_leading_underscore" ;
+   rdfs:comment "localName with leading underscore (p:_)" ;
+   mf:action    <localName_with_leading_underscore.ttl> ;
+   mf:result    <localName_with_leading_underscore.nt> ;
+   .
+
+<#localName_with_leading_digit> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_leading_digit" ;
+   rdfs:comment "localName with leading digit (p:_)" ;
+   mf:action    <localName_with_leading_digit.ttl> ;
+   mf:result    <localName_with_leading_digit.nt> ;
+   .
+
+<#localName_with_non_leading_extras> rdf:type rdft:TestTurtleEval ;
+   mf:name      "localName_with_non_leading_extras" ;
+   rdfs:comment "localName with_non_leading_extras (_:a·̀ͯ‿.â€)" ;
+   mf:action    <localName_with_non_leading_extras.ttl> ;
+   mf:result    <localName_with_non_leading_extras.nt> ;
+   .
+
+<#old_style_base> rdf:type rdft:TestTurtleEval ;
+   mf:name      "old_style_base" ;
+   rdfs:comment "old-style base" ;
+   mf:action    <old_style_base.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#SPARQL_style_base> rdf:type rdft:TestTurtleEval ;
+   mf:name      "SPARQL_style_base" ;
+   rdfs:comment "SPARQL-style base" ;
+   mf:action    <SPARQL_style_base.ttl> ;
+   mf:result    <IRI_spo.nt> ;
+   .
+
+<#labeled_blank_node_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_subject" ;
+   rdfs:comment "labeled blank node subject" ;
+   mf:action    <labeled_blank_node_subject.ttl> ;
+   mf:result    <labeled_blank_node_subject.nt> ;
+   .
+
+<#labeled_blank_node_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_object" ;
+   rdfs:comment "labeled blank node object" ;
+   mf:action    <labeled_blank_node_object.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#labeled_blank_node_with_PN_CHARS_BASE_character_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_with_PN_CHARS_BASE_character_boundaries" ;
+   rdfs:comment "labeled blank node with PN_CHARS_BASE character boundaries (_:AZazÀÖØöø...)" ;
+   mf:action    <labeled_blank_node_with_PN_CHARS_BASE_character_boundaries.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#labeled_blank_node_with_leading_underscore> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_with_leading_underscore" ;
+   rdfs:comment "labeled blank node with_leading_underscore (_:_)" ;
+   mf:action    <labeled_blank_node_with_leading_underscore.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#labeled_blank_node_with_leading_digit> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_with_leading_digit" ;
+   rdfs:comment "labeled blank node with_leading_digit (_:0)" ;
+   mf:action    <labeled_blank_node_with_leading_digit.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#labeled_blank_node_with_non_leading_extras> rdf:type rdft:TestTurtleEval ;
+   mf:name      "labeled_blank_node_with_non_leading_extras" ;
+   rdfs:comment "labeled blank node with_non_leading_extras (_:a·̀ͯ‿.â€)" ;
+   mf:action    <labeled_blank_node_with_non_leading_extras.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#anonymous_blank_node_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "anonymous_blank_node_subject" ;
+   rdfs:comment "anonymous blank node subject" ;
+   mf:action    <anonymous_blank_node_subject.ttl> ;
+   mf:result    <labeled_blank_node_subject.nt> ;
+   .
+
+<#anonymous_blank_node_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "anonymous_blank_node_object" ;
+   rdfs:comment "anonymous blank node object" ;
+   mf:action    <anonymous_blank_node_object.ttl> ;
+   mf:result    <labeled_blank_node_object.nt> ;
+   .
+
+<#sole_blankNodePropertyList> rdf:type rdft:TestTurtleEval ;
+   mf:name      "sole_blankNodePropertyList" ;
+   rdfs:comment "sole blankNodePropertyList [ <p> <o> ] ." ;
+   mf:action    <sole_blankNodePropertyList.ttl> ;
+   mf:result    <labeled_blank_node_subject.nt> ;
+   .
+
+<#blankNodePropertyList_as_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "blankNodePropertyList_as_subject" ;
+   rdfs:comment "blankNodePropertyList as subject [ … ] <p> <o> ." ;
+   mf:action    <blankNodePropertyList_as_subject.ttl> ;
+   mf:result    <blankNodePropertyList_as_subject.nt> ;
+   .
+
+<#blankNodePropertyList_as_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "blankNodePropertyList_as_object" ;
+   rdfs:comment "blankNodePropertyList as object <s> <p> [ … ] ." ;
+   mf:action    <blankNodePropertyList_as_object.ttl> ;
+   mf:result    <blankNodePropertyList_as_object.nt> ;
+   .
+
+<#blankNodePropertyList_with_multiple_triples> rdf:type rdft:TestTurtleEval ;
+   mf:name      "blankNodePropertyList_with_multiple_triples" ;
+   rdfs:comment "blankNodePropertyList with multiple triples [ <s> <p> ; <s2> <p2> ]" ;
+   mf:action    <blankNodePropertyList_with_multiple_triples.ttl> ;
+   mf:result    <blankNodePropertyList_with_multiple_triples.nt> ;
+   .
+
+<#nested_blankNodePropertyLists> rdf:type rdft:TestTurtleEval ;
+   mf:name      "nested_blankNodePropertyLists" ;
+   rdfs:comment "nested blankNodePropertyLists [ <p1> [ <p2> <o2> ] ; <p3> <o3> ]" ;
+   mf:action    <nested_blankNodePropertyLists.ttl> ;
+   mf:result    <nested_blankNodePropertyLists.nt> ;
+   .
+
+<#blankNodePropertyList_containing_collection> rdf:type rdft:TestTurtleEval ;
+   mf:name      "blankNodePropertyList_containing_collection" ;
+   rdfs:comment "blankNodePropertyList containing collection [ <p1> ( … ) ]" ;
+   mf:action    <blankNodePropertyList_containing_collection.ttl> ;
+   mf:result    <blankNodePropertyList_containing_collection.nt> ;
+   .
+
+<#collection_subject> rdf:type rdft:TestTurtleEval ;
+   mf:name      "collection_subject" ;
+   rdfs:comment "collection subject" ;
+   mf:action    <collection_subject.ttl> ;
+   mf:result    <collection_subject.nt> ;
+   .
+
+<#collection_object> rdf:type rdft:TestTurtleEval ;
+   mf:name      "collection_object" ;
+   rdfs:comment "collection object" ;
+   mf:action    <collection_object.ttl> ;
+   mf:result    <collection_object.nt> ;
+   .
+
+<#empty_collection> rdf:type rdft:TestTurtleEval ;
+   mf:name      "empty_collection" ;
+   rdfs:comment "empty collection ()" ;
+   mf:action    <empty_collection.ttl> ;
+   mf:result    <empty_collection.nt> ;
+   .
+
+<#nested_collection> rdf:type rdft:TestTurtleEval ;
+   mf:name      "nested_collection" ;
+   rdfs:comment "nested collection (())" ;
+   mf:action    <nested_collection.ttl> ;
+   mf:result    <nested_collection.nt> ;
+   .
+
+<#first> rdf:type rdft:TestTurtleEval ;
+   mf:name      "first" ;
+   rdfs:comment "first, not last, non-empty nested collection" ;
+   mf:action    <first.ttl> ;
+   mf:result    <first.nt> ;
+   .
+
+<#last> rdf:type rdft:TestTurtleEval ;
+   mf:name      "last" ;
+   rdfs:comment "last, not first, non-empty nested collection" ;
+   mf:action    <last.ttl> ;
+   mf:result    <last.nt> ;
+   .
+
+<#LITERAL1> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1" ;
+   rdfs:comment "LITERAL1 'x'" ;
+   mf:action    <LITERAL1.ttl> ;
+   mf:result    <LITERAL1.nt> ;
+   .
+
+<#LITERAL1_ascii_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1_ascii_boundaries" ;
+   rdfs:comment "LITERAL1_ascii_boundaries '\\x00\\x09\\x0b\\x0c\\x0e\\x26\\x28...'" ;
+   mf:action    <LITERAL1_ascii_boundaries.ttl> ;
+   mf:result    <LITERAL1_ascii_boundaries.nt> ;
+   .
+
+<#LITERAL1_with_UTF8_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1_with_UTF8_boundaries" ;
+   rdfs:comment "LITERAL1_with_UTF8_boundaries '\\x80\\x7ff\\x800\\xfff...'" ;
+   mf:action    <LITERAL1_with_UTF8_boundaries.ttl> ;
+   mf:result    <LITERAL_with_UTF8_boundaries.nt> ;
+   .
+
+<#LITERAL1_all_controls> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1_all_controls" ;
+   rdfs:comment "LITERAL1_all_controls '\\x00\\x01\\x02\\x03\\x04...'" ;
+   mf:action    <LITERAL1_all_controls.ttl> ;
+   mf:result    <LITERAL1_all_controls.nt> ;
+   .
+
+<#LITERAL1_all_punctuation> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL1_all_punctuation" ;
+   rdfs:comment "LITERAL1_all_punctuation '!\"#$%&()...'" ;
+   mf:action    <LITERAL1_all_punctuation.ttl> ;
+   mf:result    <LITERAL1_all_punctuation.nt> ;
+   .
+
+<#LITERAL_LONG1> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1" ;
+   rdfs:comment "LITERAL_LONG1 '''x'''" ;
+   mf:action    <LITERAL_LONG1.ttl> ;
+   mf:result    <LITERAL1.nt> ;
+   .
+
+<#LITERAL_LONG1_ascii_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1_ascii_boundaries" ;
+   rdfs:comment "LITERAL_LONG1_ascii_boundaries '\\x00\\x26\\x28...'" ;
+   mf:action    <LITERAL_LONG1_ascii_boundaries.ttl> ;
+   mf:result    <LITERAL_LONG1_ascii_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG1_with_UTF8_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1_with_UTF8_boundaries" ;
+   rdfs:comment "LITERAL_LONG1_with_UTF8_boundaries '\\x80\\x7ff\\x800\\xfff...'" ;
+   mf:action    <LITERAL_LONG1_with_UTF8_boundaries.ttl> ;
+   mf:result    <LITERAL_with_UTF8_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG1_with_1_squote> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1_with_1_squote" ;
+   rdfs:comment "LITERAL_LONG1 with 1 squote '''a'b'''" ;
+   mf:action    <LITERAL_LONG1_with_1_squote.ttl> ;
+   mf:result    <LITERAL_LONG1_with_1_squote.nt> ;
+   .
+
+<#LITERAL_LONG1_with_2_squotes> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG1_with_2_squotes" ;
+   rdfs:comment "LITERAL_LONG1 with 2 squotes '''a''b'''" ;
+   mf:action    <LITERAL_LONG1_with_2_squotes.ttl> ;
+   mf:result    <LITERAL_LONG1_with_2_squotes.nt> ;
+   .
+
+<#LITERAL2> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL2" ;
+   rdfs:comment "LITERAL2 \"x\"" ;
+   mf:action    <LITERAL2.ttl> ;
+   mf:result    <LITERAL1.nt> ;
+   .
+
+<#LITERAL2_ascii_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL2_ascii_boundaries" ;
+   rdfs:comment "LITERAL2_ascii_boundaries '\\x00\\x09\\x0b\\x0c\\x0e\\x21\\x23...'" ;
+   mf:action    <LITERAL2_ascii_boundaries.ttl> ;
+   mf:result    <LITERAL2_ascii_boundaries.nt> ;
+   .
+
+<#LITERAL2_with_UTF8_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL2_with_UTF8_boundaries" ;
+   rdfs:comment "LITERAL2_with_UTF8_boundaries '\\x80\\x7ff\\x800\\xfff...'" ;
+   mf:action    <LITERAL2_with_UTF8_boundaries.ttl> ;
+   mf:result    <LITERAL_with_UTF8_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG2> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2" ;
+   rdfs:comment "LITERAL_LONG2 \"\"\"x\"\"\"" ;
+   mf:action    <LITERAL_LONG2.ttl> ;
+   mf:result    <LITERAL1.nt> ;
+   .
+
+<#LITERAL_LONG2_ascii_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2_ascii_boundaries" ;
+   rdfs:comment "LITERAL_LONG2_ascii_boundaries '\\x00\\x21\\x23...'" ;
+   mf:action    <LITERAL_LONG2_ascii_boundaries.ttl> ;
+   mf:result    <LITERAL_LONG2_ascii_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG2_with_UTF8_boundaries> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2_with_UTF8_boundaries" ;
+   rdfs:comment "LITERAL_LONG2_with_UTF8_boundaries '\\x80\\x7ff\\x800\\xfff...'" ;
+   mf:action    <LITERAL_LONG2_with_UTF8_boundaries.ttl> ;
+   mf:result    <LITERAL_with_UTF8_boundaries.nt> ;
+   .
+
+<#LITERAL_LONG2_with_1_squote> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2_with_1_squote" ;
+   rdfs:comment "LITERAL_LONG2 with 1 squote \"\"\"a\"b\"\"\"" ;
+   mf:action    <LITERAL_LONG2_with_1_squote.ttl> ;
+   mf:result    <LITERAL_LONG2_with_1_squote.nt> ;
+   .
+
+<#LITERAL_LONG2_with_2_squotes> rdf:type rdft:TestTurtleEval ;
+   mf:name      "LITERAL_LONG2_with_2_squotes" ;
+   rdfs:comment "LITERAL_LONG2 with 2 squotes \"\"\"a\"\"b\"\"\"" ;
+   mf:action    <LITERAL_LONG2_with_2_squotes.ttl> ;
+   mf:result    <LITERAL_LONG2_with_2_squotes.nt> ;
+   .
+
+<#literal_with_CHARACTER_TABULATION> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_CHARACTER_TABULATION" ;
+   rdfs:comment "literal with CHARACTER TABULATION" ;
+   mf:action    <literal_with_CHARACTER_TABULATION.ttl> ;
+   mf:result    <literal_with_CHARACTER_TABULATION.nt> ;
+   .
+
+<#literal_with_BACKSPACE> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_BACKSPACE" ;
+   rdfs:comment "literal with BACKSPACE" ;
+   mf:action    <literal_with_BACKSPACE.ttl> ;
+   mf:result    <literal_with_BACKSPACE.nt> ;
+   .
+
+<#literal_with_LINE_FEED> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_LINE_FEED" ;
+   rdfs:comment "literal with LINE FEED" ;
+   mf:action    <literal_with_LINE_FEED.ttl> ;
+   mf:result    <literal_with_LINE_FEED.nt> ;
+   .
+
+<#literal_with_CARRIAGE_RETURN> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_CARRIAGE_RETURN" ;
+   rdfs:comment "literal with CARRIAGE RETURN" ;
+   mf:action    <literal_with_CARRIAGE_RETURN.ttl> ;
+   mf:result    <literal_with_CARRIAGE_RETURN.nt> ;
+   .
+
+<#literal_with_FORM_FEED> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_FORM_FEED" ;
+   rdfs:comment "literal with FORM FEED" ;
+   mf:action    <literal_with_FORM_FEED.ttl> ;
+   mf:result    <literal_with_FORM_FEED.nt> ;
+   .
+
+<#literal_with_REVERSE_SOLIDUS> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_REVERSE_SOLIDUS" ;
+   rdfs:comment "literal with REVERSE SOLIDUS" ;
+   mf:action    <literal_with_REVERSE_SOLIDUS.ttl> ;
+   mf:result    <literal_with_REVERSE_SOLIDUS.nt> ;
+   .
+
+<#literal_with_escaped_CHARACTER_TABULATION> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_CHARACTER_TABULATION" ;
+   rdfs:comment "literal with escaped CHARACTER TABULATION" ;
+   mf:action    <literal_with_escaped_CHARACTER_TABULATION.ttl> ;
+   mf:result    <literal_with_CHARACTER_TABULATION.nt> ;
+   .
+
+<#literal_with_escaped_BACKSPACE> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_BACKSPACE" ;
+   rdfs:comment "literal with escaped BACKSPACE" ;
+   mf:action    <literal_with_escaped_BACKSPACE.ttl> ;
+   mf:result    <literal_with_BACKSPACE.nt> ;
+   .
+
+<#literal_with_escaped_LINE_FEED> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_LINE_FEED" ;
+   rdfs:comment "literal with escaped LINE FEED" ;
+   mf:action    <literal_with_escaped_LINE_FEED.ttl> ;
+   mf:result    <literal_with_LINE_FEED.nt> ;
+   .
+
+<#literal_with_escaped_CARRIAGE_RETURN> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_CARRIAGE_RETURN" ;
+   rdfs:comment "literal with escaped CARRIAGE RETURN" ;
+   mf:action    <literal_with_escaped_CARRIAGE_RETURN.ttl> ;
+   mf:result    <literal_with_CARRIAGE_RETURN.nt> ;
+   .
+
+<#literal_with_escaped_FORM_FEED> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_escaped_FORM_FEED" ;
+   rdfs:comment "literal with escaped FORM FEED" ;
+   mf:action    <literal_with_escaped_FORM_FEED.ttl> ;
+   mf:result    <literal_with_FORM_FEED.nt> ;
+   .
+
+<#literal_with_numeric_escape4> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_numeric_escape4" ;
+   rdfs:comment "literal with numeric escape4 \\u" ;
+   mf:action    <literal_with_numeric_escape4.ttl> ;
+   mf:result    <literal_with_numeric_escape4.nt> ;
+   .
+
+<#literal_with_numeric_escape8> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_with_numeric_escape8" ;
+   rdfs:comment "literal with numeric escape8 \\U" ;
+   mf:action    <literal_with_numeric_escape8.ttl> ;
+   mf:result    <literal_with_numeric_escape4.nt> ;
+   .
+
+<#IRIREF_datatype> rdf:type rdft:TestTurtleEval ;
+   mf:name      "IRIREF_datatype" ;
+   rdfs:comment "IRIREF datatype \"\"^^<t>" ;
+   mf:action    <IRIREF_datatype.ttl> ;
+   mf:result    <IRIREF_datatype.nt> ;
+   .
+
+<#prefixed_name_datatype> rdf:type rdft:TestTurtleEval ;
+   mf:name      "prefixed_name_datatype" ;
+   rdfs:comment "prefixed name datatype \"\"^^p:t" ;
+   mf:action    <prefixed_name_datatype.ttl> ;
+   mf:result    <IRIREF_datatype.nt> ;
+   .
+
+<#bareword_integer> rdf:type rdft:TestTurtleEval ;
+   mf:name      "bareword_integer" ;
+   rdfs:comment "bareword integer" ;
+   mf:action    <bareword_integer.ttl> ;
+   mf:result    <IRIREF_datatype.nt> ;
+   .
+
+<#bareword_decimal> rdf:type rdft:TestTurtleEval ;
+   mf:name      "bareword_decimal" ;
+   rdfs:comment "bareword decimal" ;
+   mf:action    <bareword_decimal.ttl> ;
+   mf:result    <bareword_decimal.nt> ;
+   .
+
+<#bareword_double> rdf:type rdft:TestTurtleEval ;
+   mf:name      "bareword_double" ;
+   rdfs:comment "bareword double" ;
+   mf:action    <bareword_double.ttl> ;
+   mf:result    <bareword_double.nt> ;
+   .
+
+<#double_lower_case_e> rdf:type rdft:TestTurtleEval ;
+   mf:name      "double_lower_case_e" ;
+   rdfs:comment "double lower case e" ;
+   mf:action    <double_lower_case_e.ttl> ;
+   mf:result    <double_lower_case_e.nt> ;
+   .
+
+<#negative_numeric> rdf:type rdft:TestTurtleEval ;
+   mf:name      "negative_numeric" ;
+   rdfs:comment "negative numeric" ;
+   mf:action    <negative_numeric.ttl> ;
+   mf:result    <negative_numeric.nt> ;
+   .
+
+<#positive_numeric> rdf:type rdft:TestTurtleEval ;
+   mf:name      "positive_numeric" ;
+   rdfs:comment "positive numeric" ;
+   mf:action    <positive_numeric.ttl> ;
+   mf:result    <positive_numeric.nt> ;
+   .
+
+<#numeric_with_leading_0> rdf:type rdft:TestTurtleEval ;
+   mf:name      "numeric_with_leading_0" ;
+   rdfs:comment "numeric with leading 0" ;
+   mf:action    <numeric_with_leading_0.ttl> ;
+   mf:result    <numeric_with_leading_0.nt> ;
+   .
+
+<#literal_true> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_true" ;
+   rdfs:comment "literal true" ;
+   mf:action    <literal_true.ttl> ;
+   mf:result    <literal_true.nt> ;
+   .
+
+<#literal_false> rdf:type rdft:TestTurtleEval ;
+   mf:name      "literal_false" ;
+   rdfs:comment "literal false" ;
+   mf:action    <literal_false.ttl> ;
+   mf:result    <literal_false.nt> ;
+   .
+
+<#langtagged_non_LONG> rdf:type rdft:TestTurtleEval ;
+   mf:name      "langtagged_non_LONG" ;
+   rdfs:comment "langtagged non-LONG \"x\"@en" ;
+   mf:action    <langtagged_non_LONG.ttl> ;
+   mf:result    <langtagged_non_LONG.nt> ;
+   .
+
+<#langtagged_LONG> rdf:type rdft:TestTurtleEval ;
+   mf:name      "langtagged_LONG" ;
+   rdfs:comment "langtagged LONG \"\"\"x\"\"\"@en" ;
+   mf:action    <langtagged_LONG.ttl> ;
+   mf:result    <langtagged_non_LONG.nt> ;
+   .
+
+<#lantag_with_subtag> rdf:type rdft:TestTurtleEval ;
+   mf:name      "lantag_with_subtag" ;
+   rdfs:comment "lantag with subtag \"x\"@en-us" ;
+   mf:action    <lantag_with_subtag.ttl> ;
+   mf:result    <lantag_with_subtag.nt> ;
+   .
+
+<#objectList_with_two_objects> rdf:type rdft:TestTurtleEval ;
+   mf:name      "objectList_with_two_objects" ;
+   rdfs:comment "objectList with two objects … <o1>,<o2>" ;
+   mf:action    <objectList_with_two_objects.ttl> ;
+   mf:result    <objectList_with_two_objects.nt> ;
+   .
+
+<#predicateObjectList_with_two_objectLists> rdf:type rdft:TestTurtleEval ;
+   mf:name      "predicateObjectList_with_two_objectLists" ;
+   rdfs:comment "predicateObjectList with two objectLists … <o1>,<o2>" ;
+   mf:action    <predicateObjectList_with_two_objectLists.ttl> ;
+   mf:result    <predicateObjectList_with_two_objectLists.nt> ;
+   .
+
+<#repeated_semis_at_end> rdf:type rdft:TestTurtleEval ;
+   mf:name      "repeated_semis_at_end" ;
+   rdfs:comment "repeated semis at end <s> <p> <o> ;; <p2> <o2> ." ;
+   mf:action    <repeated_semis_at_end.ttl> ;
+   mf:result    <predicateObjectList_with_two_objectLists.nt> ;
+   .
+
+<#repeated_semis_not_at_end> rdf:type rdft:TestTurtleEval ;
+   mf:name      "repeated_semis_not_at_end" ;
+   rdfs:comment "repeated semis not at end <s> <p> <o> ;;." ;
+   mf:action    <repeated_semis_not_at_end.ttl> ;
+   mf:result    <repeated_semis_not_at_end.nt> ;
+   .
+
+# original tests-ttl
+<#turtle-syntax-file-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-file-01" ;
+   rdfs:comment "Empty file" ;
+   mf:action    <turtle-syntax-file-01.ttl> ;
+   .
+
+<#turtle-syntax-file-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-file-02" ;
+   rdfs:comment "Only comment" ;
+   mf:action    <turtle-syntax-file-02.ttl> ;
+   .
+
+<#turtle-syntax-file-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-file-03" ;
+   rdfs:comment "One comment, one empty line" ;
+   mf:action    <turtle-syntax-file-03.ttl> ;
+   .
+
+<#turtle-syntax-uri-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-uri-01" ;
+   rdfs:comment "Only IRIs" ;
+   mf:action    <turtle-syntax-uri-01.ttl> ;
+   .
+
+<#turtle-syntax-uri-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-uri-02" ;
+   rdfs:comment "IRIs with Unicode escape" ;
+   mf:action    <turtle-syntax-uri-02.ttl> ;
+   .
+
+<#turtle-syntax-uri-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-uri-03" ;
+   rdfs:comment "IRIs with long Unicode escape" ;
+   mf:action    <turtle-syntax-uri-03.ttl> ;
+   .
+
+<#turtle-syntax-uri-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-uri-04" ;
+   rdfs:comment "Legal IRIs" ;
+   mf:action    <turtle-syntax-uri-04.ttl> ;
+   .
+
+<#turtle-syntax-base-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-base-01" ;
+   rdfs:comment "@base" ;
+   mf:action    <turtle-syntax-base-01.ttl> ;
+   .
+
+<#turtle-syntax-base-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-base-02" ;
+   rdfs:comment "BASE" ;
+   mf:action    <turtle-syntax-base-02.ttl> ;
+   .
+
+<#turtle-syntax-base-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-base-03" ;
+   rdfs:comment "@base with relative IRIs" ;
+   mf:action    <turtle-syntax-base-03.ttl> ;
+   .
+
+<#turtle-syntax-base-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-base-04" ;
+   rdfs:comment "base with relative IRIs" ;
+   mf:action    <turtle-syntax-base-04.ttl> ;
+   .
+
+<#turtle-syntax-prefix-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-01" ;
+   rdfs:comment "@prefix" ;
+   mf:action    <turtle-syntax-prefix-01.ttl> ;
+   .
+
+<#turtle-syntax-prefix-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-02" ;
+   rdfs:comment "PreFIX" ;
+   mf:action    <turtle-syntax-prefix-02.ttl> ;
+   .
+
+<#turtle-syntax-prefix-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-03" ;
+   rdfs:comment "Empty PREFIX" ;
+   mf:action    <turtle-syntax-prefix-03.ttl> ;
+   .
+
+<#turtle-syntax-prefix-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-04" ;
+   rdfs:comment "Empty @prefix with % escape" ;
+   mf:action    <turtle-syntax-prefix-04.ttl> ;
+   .
+
+<#turtle-syntax-prefix-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-05" ;
+   rdfs:comment "@prefix with no suffix" ;
+   mf:action    <turtle-syntax-prefix-05.ttl> ;
+   .
+
+<#turtle-syntax-prefix-06> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-06" ;
+   rdfs:comment "colon is a legal pname character" ;
+   mf:action    <turtle-syntax-prefix-06.ttl> ;
+   .
+
+<#turtle-syntax-prefix-07> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-07" ;
+   rdfs:comment "dash is a legal pname character" ;
+   mf:action    <turtle-syntax-prefix-07.ttl> ;
+   .
+
+<#turtle-syntax-prefix-08> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-08" ;
+   rdfs:comment "underscore is a legal pname character" ;
+   mf:action    <turtle-syntax-prefix-08.ttl> ;
+   .
+
+<#turtle-syntax-prefix-09> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-prefix-09" ;
+   rdfs:comment "percents in pnames" ;
+   mf:action    <turtle-syntax-prefix-09.ttl> ;
+   .
+
+<#turtle-syntax-string-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-01" ;
+   rdfs:comment "string literal" ;
+   mf:action    <turtle-syntax-string-01.ttl> ;
+   .
+
+<#turtle-syntax-string-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-02" ;
+   rdfs:comment "langString literal" ;
+   mf:action    <turtle-syntax-string-02.ttl> ;
+   .
+
+<#turtle-syntax-string-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-03" ;
+   rdfs:comment "langString literal with region" ;
+   mf:action    <turtle-syntax-string-03.ttl> ;
+   .
+
+<#turtle-syntax-string-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-04" ;
+   rdfs:comment "squote string literal" ;
+   mf:action    <turtle-syntax-string-04.ttl> ;
+   .
+
+<#turtle-syntax-string-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-05" ;
+   rdfs:comment "squote langString literal" ;
+   mf:action    <turtle-syntax-string-05.ttl> ;
+   .
+
+<#turtle-syntax-string-06> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-06" ;
+   rdfs:comment "squote langString literal with region" ;
+   mf:action    <turtle-syntax-string-06.ttl> ;
+   .
+
+<#turtle-syntax-string-07> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-07" ;
+   rdfs:comment "long string literal with embedded single- and double-quotes" ;
+   mf:action    <turtle-syntax-string-07.ttl> ;
+   .
+
+<#turtle-syntax-string-08> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-08" ;
+   rdfs:comment "long string literal with embedded newline" ;
+   mf:action    <turtle-syntax-string-08.ttl> ;
+   .
+
+<#turtle-syntax-string-09> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-09" ;
+   rdfs:comment "squote long string literal with embedded single- and double-quotes" ;
+   mf:action    <turtle-syntax-string-09.ttl> ;
+   .
+
+<#turtle-syntax-string-10> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-10" ;
+   rdfs:comment "long langString literal with embedded newline" ;
+   mf:action    <turtle-syntax-string-10.ttl> ;
+   .
+
+<#turtle-syntax-string-11> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-string-11" ;
+   rdfs:comment "squote long langString literal with embedded newline" ;
+   mf:action    <turtle-syntax-string-11.ttl> ;
+   .
+
+<#turtle-syntax-str-esc-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-str-esc-01" ;
+   rdfs:comment "string literal with escaped newline" ;
+   mf:action    <turtle-syntax-str-esc-01.ttl> ;
+   .
+
+<#turtle-syntax-str-esc-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-str-esc-02" ;
+   rdfs:comment "string literal with Unicode escape" ;
+   mf:action    <turtle-syntax-str-esc-02.ttl> ;
+   .
+
+<#turtle-syntax-str-esc-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-str-esc-03" ;
+   rdfs:comment "string literal with long Unicode escape" ;
+   mf:action    <turtle-syntax-str-esc-03.ttl> ;
+   .
+
+<#turtle-syntax-pname-esc-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-pname-esc-01" ;
+   rdfs:comment "pname with back-slash escapes" ;
+   mf:action    <turtle-syntax-pname-esc-01.ttl> ;
+   .
+
+<#turtle-syntax-pname-esc-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-pname-esc-02" ;
+   rdfs:comment "pname with back-slash escapes (2)" ;
+   mf:action    <turtle-syntax-pname-esc-02.ttl> ;
+   .
+
+<#turtle-syntax-pname-esc-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-pname-esc-03" ;
+   rdfs:comment "pname with back-slash escapes (3)" ;
+   mf:action    <turtle-syntax-pname-esc-03.ttl> ;
+   .
+
+<#turtle-syntax-bnode-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-01" ;
+   rdfs:comment "bnode subject" ;
+   mf:action    <turtle-syntax-bnode-01.ttl> ;
+   .
+
+<#turtle-syntax-bnode-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-02" ;
+   rdfs:comment "bnode object" ;
+   mf:action    <turtle-syntax-bnode-02.ttl> ;
+   .
+
+<#turtle-syntax-bnode-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-03" ;
+   rdfs:comment "bnode property list object" ;
+   mf:action    <turtle-syntax-bnode-03.ttl> ;
+   .
+
+<#turtle-syntax-bnode-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-04" ;
+   rdfs:comment "bnode property list object (2)" ;
+   mf:action    <turtle-syntax-bnode-04.ttl> ;
+   .
+
+<#turtle-syntax-bnode-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-05" ;
+   rdfs:comment "bnode property list subject" ;
+   mf:action    <turtle-syntax-bnode-05.ttl> ;
+   .
+
+<#turtle-syntax-bnode-06> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-06" ;
+   rdfs:comment "labeled bnode subject" ;
+   mf:action    <turtle-syntax-bnode-06.ttl> ;
+   .
+
+<#turtle-syntax-bnode-07> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-07" ;
+   rdfs:comment "labeled bnode subject and object" ;
+   mf:action    <turtle-syntax-bnode-07.ttl> ;
+   .
+
+<#turtle-syntax-bnode-08> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-08" ;
+   rdfs:comment "bare bnode property list" ;
+   mf:action    <turtle-syntax-bnode-08.ttl> ;
+   .
+
+<#turtle-syntax-bnode-09> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-09" ;
+   rdfs:comment "bnode property list" ;
+   mf:action    <turtle-syntax-bnode-09.ttl> ;
+   .
+
+<#turtle-syntax-bnode-10> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-bnode-10" ;
+   rdfs:comment "mixed bnode property list and triple" ;
+   mf:action    <turtle-syntax-bnode-10.ttl> ;
+   .
+
+<#turtle-syntax-number-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-01" ;
+   rdfs:comment "integer literal" ;
+   mf:action    <turtle-syntax-number-01.ttl> ;
+   .
+
+<#turtle-syntax-number-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-02" ;
+   rdfs:comment "negative integer literal" ;
+   mf:action    <turtle-syntax-number-02.ttl> ;
+   .
+
+<#turtle-syntax-number-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-03" ;
+   rdfs:comment "positive integer literal" ;
+   mf:action    <turtle-syntax-number-03.ttl> ;
+   .
+
+<#turtle-syntax-number-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-04" ;
+   rdfs:comment "decimal literal" ;
+   mf:action    <turtle-syntax-number-04.ttl> ;
+   .
+
+<#turtle-syntax-number-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-05" ;
+   rdfs:comment "decimal literal (no leading digits)" ;
+   mf:action    <turtle-syntax-number-05.ttl> ;
+   .
+
+<#turtle-syntax-number-06> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-06" ;
+   rdfs:comment "negative decimal literal" ;
+   mf:action    <turtle-syntax-number-06.ttl> ;
+   .
+
+<#turtle-syntax-number-07> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-07" ;
+   rdfs:comment "positive decimal literal" ;
+   mf:action    <turtle-syntax-number-07.ttl> ;
+   .
+
+<#turtle-syntax-number-08> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-08" ;
+   rdfs:comment "integer literal with decimal lexical confusion" ;
+   mf:action    <turtle-syntax-number-08.ttl> ;
+   .
+
+<#turtle-syntax-number-09> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-09" ;
+   rdfs:comment "double literal" ;
+   mf:action    <turtle-syntax-number-09.ttl> ;
+   .
+
+<#turtle-syntax-number-10> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-10" ;
+   rdfs:comment "negative double literal" ;
+   mf:action    <turtle-syntax-number-10.ttl> ;
+   .
+
+<#turtle-syntax-number-11> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-number-11" ;
+   rdfs:comment "double literal no fraction" ;
+   mf:action    <turtle-syntax-number-11.ttl> ;
+   .
+
+<#turtle-syntax-datatypes-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-datatypes-01" ;
+   rdfs:comment "xsd:byte literal" ;
+   mf:action    <turtle-syntax-datatypes-01.ttl> ;
+   .
+
+<#turtle-syntax-datatypes-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-datatypes-02" ;
+   rdfs:comment "integer as xsd:string" ;
+   mf:action    <turtle-syntax-datatypes-02.ttl> ;
+   .
+
+<#turtle-syntax-kw-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-kw-01" ;
+   rdfs:comment "boolean literal (true)" ;
+   mf:action    <turtle-syntax-kw-01.ttl> ;
+   .
+
+<#turtle-syntax-kw-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-kw-02" ;
+   rdfs:comment "boolean literal (false)" ;
+   mf:action    <turtle-syntax-kw-02.ttl> ;
+   .
+
+<#turtle-syntax-kw-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-kw-03" ;
+   rdfs:comment "'a' as keyword" ;
+   mf:action    <turtle-syntax-kw-03.ttl> ;
+   .
+
+<#turtle-syntax-struct-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-01" ;
+   rdfs:comment "object list" ;
+   mf:action    <turtle-syntax-struct-01.ttl> ;
+   .
+
+<#turtle-syntax-struct-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-02" ;
+   rdfs:comment "predicate list with object list" ;
+   mf:action    <turtle-syntax-struct-02.ttl> ;
+   .
+
+<#turtle-syntax-struct-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-03" ;
+   rdfs:comment "predicate list with object list and dangling ';'" ;
+   mf:action    <turtle-syntax-struct-03.ttl> ;
+   .
+
+<#turtle-syntax-struct-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-04" ;
+   rdfs:comment "predicate list with multiple ;;" ;
+   mf:action    <turtle-syntax-struct-04.ttl> ;
+   .
+
+<#turtle-syntax-struct-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-struct-05" ;
+   rdfs:comment "predicate list with multiple ;;" ;
+   mf:action    <turtle-syntax-struct-05.ttl> ;
+   .
+
+<#turtle-syntax-lists-01> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-01" ;
+   rdfs:comment "empty list" ;
+   mf:action    <turtle-syntax-lists-01.ttl> ;
+   .
+
+<#turtle-syntax-lists-02> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-02" ;
+   rdfs:comment "mixed list" ;
+   mf:action    <turtle-syntax-lists-02.ttl> ;
+   .
+
+<#turtle-syntax-lists-03> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-03" ;
+   rdfs:comment "isomorphic list as subject and object" ;
+   mf:action    <turtle-syntax-lists-03.ttl> ;
+   .
+
+<#turtle-syntax-lists-04> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-04" ;
+   rdfs:comment "lists of lists" ;
+   mf:action    <turtle-syntax-lists-04.ttl> ;
+   .
+
+<#turtle-syntax-lists-05> rdf:type rdft:TestTurtlePositiveSyntax ;
+   mf:name    "turtle-syntax-lists-05" ;
+   rdfs:comment "mixed lists with embedded lists" ;
+   mf:action    <turtle-syntax-lists-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-01" ;
+   rdfs:comment "Bad IRI : space (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-02" ;
+   rdfs:comment "Bad IRI : bad escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-03" ;
+   rdfs:comment "Bad IRI : bad long escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-04" ;
+   rdfs:comment "Bad IRI : character escapes not allowed (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-uri-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-uri-05" ;
+   rdfs:comment "Bad IRI : character escapes not allowed (2) (negative test)" ;
+   mf:action    <turtle-syntax-bad-uri-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-01" ;
+   rdfs:comment "No prefix (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-02" ;
+   rdfs:comment "No prefix (2) (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-03" ;
+   rdfs:comment "@prefix without URI (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-04" ;
+   rdfs:comment "@prefix without prefix name (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-prefix-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-prefix-05" ;
+   rdfs:comment "@prefix without ':' (negative test)" ;
+   mf:action    <turtle-syntax-bad-prefix-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-base-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-base-01" ;
+   rdfs:comment "@base without URI (negative test)" ;
+   mf:action    <turtle-syntax-bad-base-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-base-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-base-02" ;
+   rdfs:comment "@base in wrong case (negative test)" ;
+   mf:action    <turtle-syntax-bad-base-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-base-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-base-03" ;
+   rdfs:comment "BASE without URI (negative test)" ;
+   mf:action    <turtle-syntax-bad-base-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-01" ;
+   rdfs:comment "Turtle is not TriG (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-02" ;
+   rdfs:comment "Turtle is not N3 (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-03" ;
+   rdfs:comment "Turtle is not NQuads (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-04" ;
+   rdfs:comment "Turtle does not allow literals-as-subjects (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-05" ;
+   rdfs:comment "Turtle does not allow literals-as-predicates (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-06> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-06" ;
+   rdfs:comment "Turtle does not allow bnodes-as-predicates (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-06.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-07> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-07" ;
+   rdfs:comment "Turtle does not allow labeled bnodes-as-predicates (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-07.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-01" ;
+   rdfs:comment "'A' is not a keyword (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-02" ;
+   rdfs:comment "'a' cannot be used as subject (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-03" ;
+   rdfs:comment "'a' cannot be used as object (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-04" ;
+   rdfs:comment "'true' cannot be used as subject (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-kw-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-kw-05" ;
+   rdfs:comment "'true' cannot be used as object (negative test)" ;
+   mf:action    <turtle-syntax-bad-kw-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-01" ;
+   rdfs:comment "{} fomulae not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-02" ;
+   rdfs:comment "= is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-03" ;
+   rdfs:comment "N3 paths not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-04" ;
+   rdfs:comment "N3 paths not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-05" ;
+   rdfs:comment "N3 is...of not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-06> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-06" ;
+   rdfs:comment "N3 paths not in Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-06.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-07> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-07" ;
+   rdfs:comment "@keywords is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-07.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-08> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-08" ;
+   rdfs:comment "@keywords is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-08.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-09> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-09" ;
+   rdfs:comment "=> is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-09.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-10> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-10" ;
+   rdfs:comment "<= is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-10.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-11> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-11" ;
+   rdfs:comment "@forSome is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-11.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-12> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-12" ;
+   rdfs:comment "@forAll is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-12.ttl> ;
+   .
+
+<#turtle-syntax-bad-n3-extras-13> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-n3-extras-13" ;
+   rdfs:comment "@keywords is not Turtle (negative test)" ;
+   mf:action    <turtle-syntax-bad-n3-extras-13.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-08> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-08" ;
+   rdfs:comment "missing '.' (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-08.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-09> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-09" ;
+   rdfs:comment "extra '.' (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-09.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-10> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-10" ;
+   rdfs:comment "extra '.' (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-10.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-11> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-11" ;
+   rdfs:comment "trailing ';' no '.' (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-11.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-12> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-12" ;
+   rdfs:comment "subject, predicate, no object (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-12.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-13> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-13" ;
+   rdfs:comment "subject, predicate, no object (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-13.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-14> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-14" ;
+   rdfs:comment "literal as subject (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-14.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-15> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-15" ;
+   rdfs:comment "literal as predicate (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-15.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-16> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-16" ;
+   rdfs:comment "bnode as predicate (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-16.ttl> ;
+   .
+
+<#turtle-syntax-bad-struct-17> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-struct-17" ;
+   rdfs:comment "labeled bnode as predicate (negative test)" ;
+   mf:action    <turtle-syntax-bad-struct-17.ttl> ;
+   .
+
+<#turtle-syntax-bad-lang-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-lang-01" ;
+   rdfs:comment "langString with bad lang (negative test)" ;
+   mf:action    <turtle-syntax-bad-lang-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-esc-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-esc-01" ;
+   rdfs:comment "Bad string escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-esc-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-esc-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-esc-02" ;
+   rdfs:comment "Bad string escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-esc-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-esc-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-esc-03" ;
+   rdfs:comment "Bad string escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-esc-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-esc-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-esc-04" ;
+   rdfs:comment "Bad string escape (negative test)" ;
+   mf:action    <turtle-syntax-bad-esc-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-pname-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-pname-01" ;
+   rdfs:comment "'~' must be escaped in pname (negative test)" ;
+   mf:action    <turtle-syntax-bad-pname-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-pname-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-pname-02" ;
+   rdfs:comment "Bad %-sequence in pname (negative test)" ;
+   mf:action    <turtle-syntax-bad-pname-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-pname-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-pname-03" ;
+   rdfs:comment "Bad unicode escape in pname (negative test)" ;
+   mf:action    <turtle-syntax-bad-pname-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-01" ;
+   rdfs:comment "mismatching string literal open/close (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-02" ;
+   rdfs:comment "mismatching string literal open/close (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-03" ;
+   rdfs:comment "mismatching string literal long/short (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-04" ;
+   rdfs:comment "mismatching long string literal open/close (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-05" ;
+   rdfs:comment "Long literal with missing end (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-05.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-06> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-06" ;
+   rdfs:comment "Long literal with extra quote (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-06.ttl> ;
+   .
+
+<#turtle-syntax-bad-string-07> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-string-07" ;
+   rdfs:comment "Long literal with extra squote (negative test)" ;
+   mf:action    <turtle-syntax-bad-string-07.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-01> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-01" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-01.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-02> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-02" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-02.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-03> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-03" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-03.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-04> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-04" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-04.ttl> ;
+   .
+
+<#turtle-syntax-bad-num-05> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-05" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-num-05.ttl> ;
+   .
+
+<#turtle-eval-struct-01> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-eval-struct-01" ;
+   rdfs:comment "triple with IRIs" ;
+   mf:action    <turtle-eval-struct-01.ttl> ;
+   mf:result    <turtle-eval-struct-01.nt> ;
+   .
+
+<#turtle-eval-struct-02> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-eval-struct-02" ;
+   rdfs:comment "triple with IRIs and embedded whitespace" ;
+   mf:action    <turtle-eval-struct-02.ttl> ;
+   mf:result    <turtle-eval-struct-02.nt> ;
+   .
+
+<#turtle-subm-01> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-01" ;
+   rdfs:comment "Blank subject" ;
+   mf:action    <turtle-subm-01.ttl> ;
+   mf:result    <turtle-subm-01.nt> ;
+   .
+
+<#turtle-subm-02> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-02" ;
+   rdfs:comment "@prefix and qnames" ;
+   mf:action    <turtle-subm-02.ttl> ;
+   mf:result    <turtle-subm-02.nt> ;
+   .
+
+<#turtle-subm-03> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-03" ;
+   rdfs:comment ", operator" ;
+   mf:action    <turtle-subm-03.ttl> ;
+   mf:result    <turtle-subm-03.nt> ;
+   .
+
+<#turtle-subm-04> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-04" ;
+   rdfs:comment "; operator" ;
+   mf:action    <turtle-subm-04.ttl> ;
+   mf:result    <turtle-subm-04.nt> ;
+   .
+
+<#turtle-subm-05> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-05" ;
+   rdfs:comment "empty [] as subject and object" ;
+   mf:action    <turtle-subm-05.ttl> ;
+   mf:result    <turtle-subm-05.nt> ;
+   .
+
+<#turtle-subm-06> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-06" ;
+   rdfs:comment "non-empty [] as subject and object" ;
+   mf:action    <turtle-subm-06.ttl> ;
+   mf:result    <turtle-subm-06.nt> ;
+   .
+
+<#turtle-subm-07> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-07" ;
+   rdfs:comment "'a' as predicate" ;
+   mf:action    <turtle-subm-07.ttl> ;
+   mf:result    <turtle-subm-07.nt> ;
+   .
+
+<#turtle-subm-08> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-08" ;
+   rdfs:comment "simple collection" ;
+   mf:action    <turtle-subm-08.ttl> ;
+   mf:result    <turtle-subm-08.nt> ;
+   .
+
+<#turtle-subm-09> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-09" ;
+   rdfs:comment "empty collection" ;
+   mf:action    <turtle-subm-09.ttl> ;
+   mf:result    <turtle-subm-09.nt> ;
+   .
+
+<#turtle-subm-10> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-10" ;
+   rdfs:comment "integer datatyped literal" ;
+   mf:action    <turtle-subm-10.ttl> ;
+   mf:result    <turtle-subm-10.nt> ;
+   .
+
+<#turtle-subm-11> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-11" ;
+   rdfs:comment "decimal integer canonicalization" ;
+   mf:action    <turtle-subm-11.ttl> ;
+   mf:result    <turtle-subm-11.nt> ;
+   .
+
+<#turtle-subm-12> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-12" ;
+   rdfs:comment "- and _ in names and qnames" ;
+   mf:action    <turtle-subm-12.ttl> ;
+   mf:result    <turtle-subm-12.nt> ;
+   .
+
+<#turtle-subm-13> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-13" ;
+   rdfs:comment "tests for rdf:_<numbers> and other qnames starting with _" ;
+   mf:action    <turtle-subm-13.ttl> ;
+   mf:result    <turtle-subm-13.nt> ;
+   .
+
+<#turtle-subm-14> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-14" ;
+   rdfs:comment "bare : allowed" ;
+   mf:action    <turtle-subm-14.ttl> ;
+   mf:result    <turtle-subm-14.nt> ;
+   .
+
+<#turtle-subm-15> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-15" ;
+   rdfs:comment "simple long literal" ;
+   mf:action    <turtle-subm-15.ttl> ;
+   mf:result    <turtle-subm-15.nt> ;
+   .
+
+<#turtle-subm-16> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-16" ;
+   rdfs:comment "long literals with escapes" ;
+   mf:action    <turtle-subm-16.ttl> ;
+   mf:result    <turtle-subm-16.nt> ;
+   .
+
+<#turtle-subm-17> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-17" ;
+   rdfs:comment "floating point number" ;
+   mf:action    <turtle-subm-17.ttl> ;
+   mf:result    <turtle-subm-17.nt> ;
+   .
+
+<#turtle-subm-18> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-18" ;
+   rdfs:comment "empty literals, normal and long variant" ;
+   mf:action    <turtle-subm-18.ttl> ;
+   mf:result    <turtle-subm-18.nt> ;
+   .
+
+<#turtle-subm-19> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-19" ;
+   rdfs:comment "positive integer, decimal and doubles" ;
+   mf:action    <turtle-subm-19.ttl> ;
+   mf:result    <turtle-subm-19.nt> ;
+   .
+
+<#turtle-subm-20> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-20" ;
+   rdfs:comment "negative integer, decimal and doubles" ;
+   mf:action    <turtle-subm-20.ttl> ;
+   mf:result    <turtle-subm-20.nt> ;
+   .
+
+<#turtle-subm-21> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-21" ;
+   rdfs:comment "long literal ending in double quote" ;
+   mf:action    <turtle-subm-21.ttl> ;
+   mf:result    <turtle-subm-21.nt> ;
+   .
+
+<#turtle-subm-22> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-22" ;
+   rdfs:comment "boolean literals" ;
+   mf:action    <turtle-subm-22.ttl> ;
+   mf:result    <turtle-subm-22.nt> ;
+   .
+
+<#turtle-subm-23> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-23" ;
+   rdfs:comment "comments" ;
+   mf:action    <turtle-subm-23.ttl> ;
+   mf:result    <turtle-subm-23.nt> ;
+   .
+
+<#turtle-subm-24> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-24" ;
+   rdfs:comment "no final mewline" ;
+   mf:action    <turtle-subm-24.ttl> ;
+   mf:result    <turtle-subm-24.nt> ;
+   .
+
+<#turtle-subm-25> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-25" ;
+   rdfs:comment "repeating a @prefix changes pname definition" ;
+   mf:action    <turtle-subm-25.ttl> ;
+   mf:result    <turtle-subm-25.nt> ;
+   .
+
+<#turtle-subm-26> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-26" ;
+   rdfs:comment "Variations on decimal canonicalization" ;
+   mf:action    <turtle-subm-26.ttl> ;
+   mf:result    <turtle-subm-26.nt> ;
+   .
+
+<#turtle-subm-27> rdf:type rdft:TestTurtleEval ;
+   mf:name    "turtle-subm-27" ;
+   rdfs:comment "Repeating @base changes base for relative IRI lookup" ;
+   mf:action    <turtle-subm-27.ttl> ;
+   mf:result    <turtle-subm-27.nt> ;
+   .
+
+<#turtle-eval-bad-01> rdf:type rdft:TestTurtleNegativeEval ;
+   mf:name    "turtle-eval-bad-01" ;
+   rdfs:comment "Bad IRI : good escape, bad charcater (negative evaluation test)" ;
+   mf:action    <turtle-eval-bad-01.ttl> ;
+   .
+
+<#turtle-eval-bad-02> rdf:type rdft:TestTurtleNegativeEval ;
+   mf:name    "turtle-eval-bad-02" ;
+   rdfs:comment "Bad IRI : hex 3C is < (negative evaluation test)" ;
+   mf:action    <turtle-eval-bad-02.ttl> ;
+   .
+
+<#turtle-eval-bad-03> rdf:type rdft:TestTurtleNegativeEval ;
+   mf:name    "turtle-eval-bad-03" ;
+   rdfs:comment "Bad IRI : hex 3E is  (negative evaluation test)" ;
+   mf:action    <turtle-eval-bad-03.ttl> ;
+   .
+
+<#turtle-eval-bad-04> rdf:type rdft:TestTurtleNegativeEval ;
+   mf:name    "turtle-eval-bad-04" ;
+   rdfs:comment "Bad IRI : {abc} (negative evaluation test)" ;
+   mf:action    <turtle-eval-bad-04.ttl> ;
+   .
+
+# tests from Dave Beckett
+# http://www.w3.org/2011/rdf-wg/wiki/Turtle_Candidate_Recommendation_Comments#c28
+<#LITERAL_LONG2_with_REVERSE_SOLIDUS> rdf:type rdft:TestTurtleEval ;
+   mf:name    "LITERAL_LONG2_with_REVERSE_SOLIDUS" ;
+   rdfs:comment "REVERSE SOLIDUS at end of LITERAL_LONG2" ;
+   mf:action    <LITERAL_LONG2_with_REVERSE_SOLIDUS.ttl> ;
+   mf:result    <LITERAL_LONG2_with_REVERSE_SOLIDUS.nt> ;
+   .
+
+<#turtle-syntax-bad-LITERAL2_with_langtag_and_datatype> rdf:type rdft:TestTurtleNegativeSyntax ;
+   mf:name    "turtle-syntax-bad-num-05" ;
+   rdfs:comment "Bad number format (negative test)" ;
+   mf:action    <turtle-syntax-bad-LITERAL2_with_langtag_and_datatype.ttl> ;
+   .
+
+<#two_LITERAL_LONG2s> rdf:type rdft:TestTurtleEval ;
+   mf:name    "two_LITERAL_LONG2s" ;
+   rdfs:comment "two LITERAL_LONG2s testing quote delimiter overrun" ;
+   mf:action    <two_LITERAL_LONG2s.ttl> ;
+   mf:result    <two_LITERAL_LONG2s.nt> ;
+   .
+
+<#langtagged_LONG_with_subtag> rdf:type rdft:TestTurtleEval ;
+   mf:name      "langtagged_LONG_with_subtag" ;
+   rdfs:comment "langtagged LONG with subtag \"\"\"Cheers\"\"\"@en-UK" ;
+   mf:action    <langtagged_LONG_with_subtag.ttl> ;
+   mf:result    <langtagged_LONG_with_subtag.nt> ;
+   .
+
+# tests from David Robillard
+# http://www.w3.org/2011/rdf-wg/wiki/Turtle_Candidate_Recommendation_Comments#c21
+<#turtle-syntax-bad-blank-label-dot-end>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Blank node label must not end in dot" ;
+	mf:name "turtle-syntax-bad-blank-label-dot-end" ;
+	mf:action <turtle-syntax-bad-blank-label-dot-end.ttl> .
+
+<#turtle-syntax-bad-number-dot-in-anon>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Dot delimeter may not appear in anonymous nodes" ;
+	mf:name "turtle-syntax-bad-number-dot-in-anon" ;
+	mf:action <turtle-syntax-bad-number-dot-in-anon.ttl> .
+
+<#turtle-syntax-bad-ln-dash-start>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Local name must not begin with dash" ;
+	mf:name "turtle-syntax-bad-ln-dash-start" ;
+	mf:action <turtle-syntax-bad-ln-dash-start.ttl> .
+
+<#turtle-syntax-bad-ln-escape>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Bad hex escape in local name" ;
+	mf:name "turtle-syntax-bad-ln-escape" ;
+	mf:action <turtle-syntax-bad-ln-escape.ttl> .
+
+<#turtle-syntax-bad-ln-escape-start>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Bad hex escape at start of local name" ;
+	mf:name "turtle-syntax-bad-ln-escape-start" ;
+	mf:action <turtle-syntax-bad-ln-escape-start.ttl> .
+
+<#turtle-syntax-bad-ns-dot-end>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Prefix must not end in dot" ;
+	mf:name "turtle-syntax-bad-ns-dot-end" ;
+	mf:action <turtle-syntax-bad-ns-dot-end.ttl> .
+
+<#turtle-syntax-bad-ns-dot-start>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Prefix must not start with dot" ;
+	mf:name "turtle-syntax-bad-ns-dot-start" ;
+	mf:action <turtle-syntax-bad-ns-dot-start.ttl> .
+
+<#turtle-syntax-bad-missing-ns-dot-end>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Prefix must not end in dot (error in triple, not prefix directive like turtle-syntax-bad-ns-dot-end)" ;
+	mf:name "turtle-syntax-bad-missing-ns-dot-end" ;
+	mf:action <turtle-syntax-bad-missing-ns-dot-end.ttl> .
+
+<#turtle-syntax-bad-missing-ns-dot-start>
+	rdf:type rdft:TestTurtleNegativeSyntax ;
+	rdfs:comment "Prefix must not start with dot (error in triple, not prefix directive like turtle-syntax-bad-ns-dot-end)" ;
+	mf:name "turtle-syntax-bad-missing-ns-dot-start" ;
+	mf:action <turtle-syntax-bad-missing-ns-dot-start.ttl> .
+
+<#turtle-syntax-ln-dots>
+	rdf:type rdft:TestTurtlePositiveSyntax ;
+	rdfs:comment "Dots in pname local names" ;
+	mf:name "turtle-syntax-ln-dots" ;
+	mf:action <turtle-syntax-ln-dots.ttl> .
+
+<#turtle-syntax-ln-colons>
+	rdf:type rdft:TestTurtlePositiveSyntax ;
+	rdfs:comment "Colons in pname local names" ;
+	mf:name "turtle-syntax-ln-colons" ;
+	mf:action <turtle-syntax-ln-colons.ttl> .
+
+<#turtle-syntax-ns-dots>
+	rdf:type rdft:TestTurtlePositiveSyntax ;
+	rdfs:comment "Dots in namespace names" ;
+	mf:name "turtle-syntax-ns-dots" ;
+	mf:action <turtle-syntax-ns-dots.ttl> .
+
+<#turtle-syntax-blank-label>
+	rdf:type rdft:TestTurtlePositiveSyntax ;
+	rdfs:comment "Characters allowed in blank node labels" ;
+	mf:name "turtle-syntax-blank-label" ;
+	mf:action <turtle-syntax-blank-label.ttl> .
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/functional/ARC2_ReaderTest.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+<?php
+
+require_once '../ARC2_TestCase.php';
+
+class ARC2_ReaderTest extends ARC2_TestCase {
+
+
+	public function testActivate() {
+		
+		
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/unit/ARC2_ClassTest.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,68 @@
+<?php
+
+require_once '../ARC2_TestCase.php';
+require_once ARC2_DIR . '/ARC2_Class.php';
+
+class ARC2_ClassTest extends PHPUnit_Framework_TestCase {
+
+    public function setUp() {
+         $this->arc2 = new ARC2_Class(array(), new stdClass);
+    }
+
+    public function testCamelCase() {
+         $this->assertSame("Fish", $this->arc2->camelCase("fish"));
+         $this->assertSame("fish", $this->arc2->camelCase("fish", true));
+         $this->assertSame("fish", $this->arc2->camelCase("fish", true, true));
+
+         $this->assertSame("FishHeads", $this->arc2->camelCase("fish_heads"));
+         $this->assertSame("fishHeads", $this->arc2->camelCase("fish_heads", true));
+         $this->assertSame("fishHeads", $this->arc2->camelCase("fish_heads", true, true));
+
+         $this->assertSame("ALLCAPITALS", $this->arc2->camelCase("ALL_CAPITALS"));
+    }
+
+    public function testDeCamelCase() {
+         $this->assertSame("fish", $this->arc2->deCamelCase("fish"));
+         $this->assertSame("Fish", $this->arc2->deCamelCase("fish", true));
+
+         $this->assertSame("fish heads", $this->arc2->deCamelCase("fish_heads"));
+         $this->assertSame("Fish heads", $this->arc2->deCamelCase("fish_heads", true));
+
+         $this->assertSame("ALL CAPITALS", $this->arc2->deCamelCase("ALL_CAPITALS"));
+    }
+
+
+    public function testV() {
+        $this->assertSame(false, $this->arc2->v(null));
+        $this->assertSame(false, $this->arc2->v("cats", false, array()));
+        $this->assertSame(true, $this->arc2->v("cats", false, array("cats" => true)));
+
+        $o = new stdclass;
+        $o->cats = true;
+        $this->assertSame(true, $this->arc2->v("cats", false, $o));
+    }
+
+    public function testV1() {
+        $this->assertSame(false, $this->arc2->v1(null));
+        $this->assertSame(false, $this->arc2->v1("cats", false, array()));
+        $this->assertSame(true, $this->arc2->v1("cats", false, array("cats" => true)));
+        $this->assertSame("blackjack", $this->arc2->v1("cats", "blackjack", array("cats" => null)));
+
+        $o = new stdclass;
+        $o->cats = true;
+        $this->assertSame(true, $this->arc2->v1("cats", false, $o));
+
+        $o = new stdclass;
+        $o->cats = 0;
+        $this->assertSame("blackjack", $this->arc2->v1("cats", "blackjack", $o));
+    }
+
+    public function testExtractTermLabel() {
+        $this->assertSame("bar", $this->arc2->extractTermLabel('http://example.com/foo#bar'));
+        $this->assertSame("bar cats", $this->arc2->extractTermLabel('http://example.com/foo#bar?cats'));
+        $this->assertSame("bar", $this->arc2->extractTermLabel('#bar'));
+        $this->assertSame("bar", $this->arc2->extractTermLabel('http://example.com/bar'));
+        $this->assertSame("bar", $this->arc2->extractTermLabel('http://example.com/bar/'));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/unit/ARC2_GraphTest.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,208 @@
+<?php
+
+require_once '../ARC2_TestCase.php';
+
+class ARC2_GraphTest extends ARC2_TestCase {
+	
+	public function setUp() {
+		$this->obj = ARC2::getGraph();
+		$this->res1 = array(
+			'http://example.com/s1' => array(
+				'http://example.com/p1' => array(
+					array('value' => 'o1', 'type' => 'literal'),
+					array('value' => 'http://example.com/o1', 'type' => 'uri'),
+				),
+			),
+		);
+		$this->res2 = array(
+			'http://example.com/s2' => array(
+				'http://example.com/p2' => array(
+					array('value' => 'o2', 'type' => 'literal'),
+					array('value' => 'http://example.com/o2', 'type' => 'uri'),
+				),
+			),
+		);
+		$this->res3 = array(
+			'http://example.com/s1' => array(
+				'http://example.com/p3' => array(
+					array('value' => 'o3', 'type' => 'literal'),
+				),
+			),
+		);
+	}
+
+	public function testSetIndex() {
+		$actual = $this->obj->setIndex($this->res1);
+		$this->assertSame($this->obj, $actual);
+		
+		$actual = $this->obj->getIndex();
+		$this->assertEquals($this->res1, $actual);
+	}
+
+	public function testGetIndex() {
+		$actual = $this->obj->getIndex();
+		$this->assertTrue(is_array($actual), 'should return array');
+	}
+
+	public function testAddIndex() {
+		$actual = $this->obj->addIndex($this->res1);
+		$this->assertSame($this->obj, $actual);
+		
+		$actual = $this->obj->getIndex();
+		$this->assertEquals($this->res1, $actual);
+		
+		$this->obj->addIndex($this->res1);
+		$actual = $this->obj->getIndex();
+		$this->assertEquals($this->res1, $actual);
+		
+		$this->obj->addIndex($this->res2);
+		$actual = $this->obj->getIndex();
+		$this->assertEquals(array_merge($this->res1, $this->res2), $actual);
+		
+		$this->obj->addIndex($this->res3);
+		$actual = $this->obj->getIndex();
+		$this->assertEquals(2, count(array_keys($actual['http://example.com/s1'])));
+		$this->assertEquals(1, count(array_keys($actual['http://example.com/s2'])));
+	}
+	
+	public function testAddGraph() {
+		$this->obj->addIndex($this->res1);
+		$g2 = ARC2::getGraph()->addIndex($this->res2);
+		
+		$actual = $this->obj->addGraph($g2);
+		$this->assertSame($this->obj, $actual);
+		
+		$actual = $this->obj->getIndex();
+		$this->assertEquals(array_merge($this->res1, $this->res2), $actual);
+	}
+	
+	public function testAddGraphWithNamespaces() {
+		$g2 = ARC2::getGraph()->setPrefix('ex', 'http://example.com/');
+		
+		$actual = $this->obj->addGraph($g2);
+		$this->assertArrayHasKey('ex', $actual->ns);
+	}
+	
+	public function testAddRdf() {
+		$rdf = $this->obj->toTurtle($this->res1);
+		$this->obj->addRdf($rdf, 'turtle');
+		$actual = $this->obj->getIndex();
+		$this->assertEquals($this->res1, $actual);
+		
+		$rdf = json_encode($this->res2);
+		$this->obj->addRdf($rdf, 'json');
+		$actual = $this->obj->getIndex();
+		$this->assertEquals(array_merge($this->res1, $this->res2), $actual);
+	}
+	
+	public function testHasSubject() {
+		$actual = $this->obj->setIndex($this->res1);
+		$this->assertTrue($actual->hasSubject('http://example.com/s1'));
+		$this->assertFalse($actual->hasSubject('http://example.com/s2'));
+	}
+	
+	public function testHasTriple() {
+		$actual = $this->obj->setIndex($this->res1);
+		$this->assertTrue($actual->hasTriple('http://example.com/s1', 'http://example.com/p1', 'o1'));
+		$this->assertFalse($actual->hasTriple('http://example.com/s1', 'http://example.com/p1', 'o2'));
+		$this->assertTrue($actual->hasTriple('http://example.com/s1', 'http://example.com/p1', array('value' => 'o1', 'type' => 'literal')));
+		$this->assertFalse($actual->hasTriple('http://example.com/s1', 'http://example.com/p1', array('value' => 'o1', 'type' => 'uri')));
+	}
+	
+	public function testHasLiteralTriple() {
+		$actual = $this->obj->setIndex($this->res2);
+		$this->assertTrue($actual->hasLiteralTriple('http://example.com/s2', 'http://example.com/p2', 'o2'));
+		$this->assertFalse($actual->hasLiteralTriple('http://example.com/s1', 'http://example.com/p1', 'o2'));
+	}
+	
+	public function testHasLinkTriple() {
+		$actual = $this->obj->setIndex($this->res2);
+		$this->assertTrue($actual->hasLinkTriple('http://example.com/s2', 'http://example.com/p2', 'http://example.com/o2'));
+		$this->assertFalse($actual->hasLinkTriple('http://example.com/s2', 'http://example.com/p2', 'o2'));
+	}
+	
+	public function testAddTriple() {
+		$actual = $this->obj->addTriple('_:s1', '_:p1', 'o1');
+		$this->assertTrue($actual->hasLiteralTriple('_:s1', '_:p1', 'o1'));
+		
+		$actual = $this->obj->addTriple('_:s1', '_:p1', 'o1', 'bnode');
+		$this->assertTrue($actual->hasLinkTriple('_:s1', '_:p1', 'o1'));
+	}
+
+	public function testGetSubjects() {
+		$g = $this->obj->setIndex($this->res1);
+		
+		$actual = $g->getSubjects();
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+		
+		$actual = $g->getSubjects('p');
+		$this->assertEquals(array(), $actual);
+		
+		$actual = $g->getSubjects('http://example.com/p1');
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+		
+		$actual = $g->getSubjects(null, 'o');
+		$this->assertEquals(array(), $actual);
+		
+		$actual = $g->getSubjects(null, 'o1');
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+		
+		$actual = $g->getSubjects(null, array('value' => 'http://example.com/o1', 'type' => 'uri'));
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+		
+		$actual = $g->getSubjects('http://example.com/p1', 'o');
+		$this->assertEquals(array(), $actual);
+		
+		$actual = $g->getSubjects('http://example.com/p1', 'o1');
+		$this->assertEquals(array('http://example.com/s1'), $actual);
+		
+	}
+
+	public function testGetPredicates() {
+		$g = $this->obj->setIndex($this->res1)->addIndex($this->res2);
+		
+		$actual = $g->getPredicates();
+		$this->assertEquals(array('http://example.com/p1', 'http://example.com/p2'), $actual);
+		
+		$actual = $g->getPredicates('http://example.com/s2');
+		$this->assertEquals(array('http://example.com/p2'), $actual);
+	}
+
+	public function testGetObjects() {
+		$actual = $this->obj->setIndex($this->res1)->getObjects('http://example.com/s1', 'http://example.com/p1', true);
+		$this->assertEmpty(array_diff(array('http://example.com/o1', 'o1'), $actual));
+		$this->assertEmpty(array_diff($actual, array('http://example.com/o1', 'o1')));
+		
+		$actual = $this->obj->setIndex($this->res3)->getObjects('http://example.com/s1', 'http://example.com/p3');
+		$this->assertEquals(array(array('value' => 'o3', 'type' => 'literal')), $actual);
+	}
+
+	public function testGetObject() {
+		$actual = $this->obj->setIndex($this->res1)->getObject('http://example.com/s1', 'http://example.com/p1', true);
+		$this->assertEquals('o1', $actual);
+		
+		$actual = $this->obj->setIndex($this->res3)->getObject('http://example.com/s1', 'http://example.com/p3');
+		$this->assertEquals(array('value' => 'o3', 'type' => 'literal'), $actual);
+	}
+	
+	public function testGetNtriples() {
+		$actual = $this->obj->setIndex($this->res3)->getNTriples();
+		$this->assertContains('<http://example.com/s1> <http://example.com/p3> "o3"', $actual);
+	}
+
+	public function testGetTurtle() {
+		$actual = $this->obj->setIndex($this->res3)->setPrefix('ex', 'http://example.com/')->getTurtle();
+		$this->assertContains('<http://example.com/s1> ex:p3 "o3"', $actual);
+	}
+
+	public function testGetRDFXML() {
+		$actual = $this->obj->setIndex($this->res3)->getRDFXML();
+		$this->assertContains('<rdf:Description rdf:about="http://example.com/s1">', $actual);
+	}
+
+	public function testGetJSON() {
+		$actual = $this->obj->setIndex($this->res3)->getJSON();
+		$this->assertContains('{"http:\/\/example.com\/s1":', $actual);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/unit/ARC2_Test.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,124 @@
+<?php
+
+require_once '../ARC2_TestCase.php';
+
+class ARC2_Test extends ARC2_TestCase {
+
+	public function testGetVersion() {
+		$actual = ARC2::getVersion();
+		$this->assertRegExp('/^[0-9]{4}-[0-9]{2}-[0-9]{2}/', $actual, "should start with date");
+	}
+
+	public function testGetIncPath() {
+		$actual = ARC2::getIncPath('RDFParser');
+		$this->assertStringEndsWith('parsers/', $actual, 'should create correct path');
+		$this->assertTrue(is_dir($actual), 'should create correct pointer');
+	}
+	
+	public function testGetScriptURI() {
+		$tmp = $_SERVER;
+		unset($_SERVER);
+		$actual = ARC2::getScriptURI();
+		$this->assertEquals('http://localhost/unknown_path', $actual);
+		$_SERVER = $tmp;
+		
+		$_SERVER = array(
+			'SERVER_PROTOCOL' => 'http',
+			'SERVER_PORT' => 443,
+			'HTTP_HOST' => 'example.com',
+			'SCRIPT_NAME' => '/foo'
+		);
+		$actual = ARC2::getScriptURI();
+		$this->assertEquals('https://example.com/foo', $actual);
+		$_SERVER = $tmp;
+		
+		unset($_SERVER['HTTP_HOST']);
+		unset($_SERVER['SERVER_NAME']);
+		$_SERVER['SCRIPT_FILENAME'] = __FILE__;
+		$actual = ARC2::getScriptURI();
+		$this->assertEquals('file://' . __FILE__, $actual);
+		$_SERVER = $tmp;
+	}
+	
+	public function testGetRequestURI() {
+		$tmp = $_SERVER;
+		unset($_SERVER);
+		$actual = ARC2::getRequestURI();
+		$this->assertEquals(ARC2::getScriptURI(), $actual);
+		$_SERVER = $tmp;
+		
+		$_SERVER = array(
+			'SERVER_PROTOCOL' => 'http',
+			'SERVER_PORT' => 1234,
+			'HTTP_HOST' => 'example.com',
+			'REQUEST_URI' => '/foo'
+		);
+		$actual = ARC2::getRequestURI();
+		$this->assertEquals('http://example.com:1234/foo', $actual);
+		$_SERVER = $tmp;
+	}
+	
+	public function testInc() {
+		$actual = ARC2::inc('Class');
+		$this->assertNotEquals(0, $actual);
+		
+		$actual = ARC2::inc('RDFParser');
+		$this->assertNotEquals(0, $actual);
+		
+		$actual = ARC2::inc('ARC2_RDFParser');
+		$this->assertNotEquals(0, $actual);
+		
+		$actual = ARC2::inc('Foo');
+		$this->assertEquals(0, $actual);
+		
+		$actual = ARC2::inc('Vendor_Foo');
+		$this->assertEquals(0, $actual);
+	}
+	
+	public function testMtime() {
+		$actual = ARC2::mtime();
+		$this->assertTrue(is_float($actual));
+	}
+	
+	public function testX() {
+		$actual = ARC2::x('foo', '  foobar');
+		$this->assertEquals('bar', $actual[1]);
+	}
+	
+	public function testToUTF8() {
+		$actual = ARC2::toUTF8('foo');
+		$this->assertEquals('foo', $actual);
+		
+		$actual = ARC2::toUTF8(utf8_encode('Iñtërnâtiônàlizætiøn'));
+		$this->assertEquals('Iñtërnâtiônàlizætiøn', $actual);
+	}
+	
+	public function testSplitURI() {
+		$actual = ARC2::splitURI('http://www.w3.org/XML/1998/namespacefoo');
+		$this->assertEquals(array('http://www.w3.org/XML/1998/namespace', 'foo'), $actual);
+		
+		$actual = ARC2::splitURI('http://www.w3.org/2005/Atomfoo');
+		$this->assertEquals(array('http://www.w3.org/2005/Atom', 'foo'), $actual);
+		
+		$actual = ARC2::splitURI('http://www.w3.org/2005/Atom#foo');
+		$this->assertEquals(array('http://www.w3.org/2005/Atom#', 'foo'), $actual);
+		
+		$actual = ARC2::splitURI('http://www.w3.org/1999/xhtmlfoo');
+		$this->assertEquals(array('http://www.w3.org/1999/xhtml', 'foo'), $actual);
+		
+		$actual = ARC2::splitURI('http://www.w3.org/1999/02/22-rdf-syntax-ns#foo');
+		$this->assertEquals(array('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'foo'), $actual);
+		
+		$actual = ARC2::splitURI('http://example.com/foo');
+		$this->assertEquals(array('http://example.com/', 'foo'), $actual);
+		
+		$actual = ARC2::splitURI('http://example.com/foo/bar');
+		$this->assertEquals(array('http://example.com/foo/', 'bar'), $actual);
+		
+		$actual = ARC2::splitURI('http://example.com/foo#bar');
+		$this->assertEquals(array('http://example.com/foo#', 'bar'), $actual);
+		
+	}
+	
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/unit/ARC2_getFormatTest.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,73 @@
+<?php
+
+require_once '../ARC2_TestCase.php';
+
+class ARC2_getFormatTest extends ARC2_TestCase {
+
+	public function testGetFormatWithAtom() {
+		$data = file_get_contents('../data/atom/feed.atom');
+		
+		$actual = ARC2::getFormat($data, 'application/atom+xml');
+		$this->assertEquals('atom', $actual);
+		
+		$actual = ARC2::getFormat($data);
+		$this->assertEquals('atom', $actual);
+	}
+
+	public function testGetFormatWithRdfXml() {
+		$data = file_get_contents('../data/rdfxml/planetrdf-bloggers.rdf');
+		
+		$actual = ARC2::getFormat($data, 'application/rdf+xml');
+		$this->assertEquals('rdfxml', $actual);
+		
+		$actual = ARC2::getFormat($data);
+		$this->assertEquals('rdfxml', $actual);
+	}
+
+	public function testGetFormatWithTurtle() {
+		$data = file_get_contents('../data/turtle/manifest.ttl');
+		
+		$actual = ARC2::getFormat($data, 'text/turtle');
+		$this->assertEquals('turtle', $actual);
+		
+		$actual = ARC2::getFormat($data);
+		$this->assertEquals('turtle', $actual);
+	}
+
+	public function testGetFormatWithJson() {
+		$data = file_get_contents('../data/json/sparql-select-result.json');
+		
+		$actual = ARC2::getFormat($data, 'application/json');
+		$this->assertEquals('json', $actual);
+		
+		$actual = ARC2::getFormat($data);
+		$this->assertEquals('json', $actual);
+		
+		$data = file_get_contents('../data/json/crunchbase-facebook.js');
+		
+		$actual = ARC2::getFormat($data);
+		$this->assertEquals('cbjson', $actual);
+		
+	}
+
+	public function testGetFormatWithN3() {
+		$data = file_get_contents('../data/nt/test.nt');
+		
+		$actual = ARC2::getFormat($data, 'application/rdf+n3');
+		$this->assertEquals('n3', $actual);
+		
+		$actual = ARC2::getFormat($data, '', 'n3');
+		$this->assertEquals('n3', $actual);
+	}
+
+	public function testGetFormatWithNTriples() {
+		$data = file_get_contents('../data/nt/test.nt');
+		
+		$actual = ARC2::getFormat($data);
+		$this->assertEquals('ntriples', $actual);
+		
+		$actual = ARC2::getFormat($data, '', 'nt');
+		$this->assertEquals('ntriples', $actual);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/unit/ARC2_getPreferredFormatTest.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,24 @@
+<?php
+
+require_once '../ARC2_TestCase.php';
+
+class ARC2_getPreferredFormatTest extends ARC2_TestCase {
+
+	public function testGetPreferredFormat() {
+		$_SERVER['HTTP_ACCEPT'] = '';
+		$actual = ARC2::getPreferredFormat('xml');
+		$this->assertEquals('XML', $actual);
+		
+		$actual = ARC2::getPreferredFormat('foo');
+		$this->assertEquals(null, $actual);
+		
+		$_SERVER['HTTP_ACCEPT'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8';
+		$actual = ARC2::getPreferredFormat();
+		$this->assertEquals('HTML', $actual);
+		
+		$_SERVER['HTTP_ACCEPT'] = 'application/rdf+xml,text/html;q=0.9,*/*;q=0.8';
+		$actual = ARC2::getPreferredFormat();
+		$this->assertEquals('RDFXML', $actual);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/libraries/ARC2/arc/tests/unit/phpunit.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,16 @@
+<phpunit>
+
+    <php>
+        <ini name="memory_limit" value="512M"/>
+    </php>
+
+    <filter>
+	  <whitelist addUncoveredFilesFromWhitelist="true" processUncoveredFilesFromWhitelist="true">
+	    <directory suffix=".php">../..</directory>
+	    <exclude>
+	      <directory suffix=".php">../../tests</directory>
+	    </exclude>
+	  </whitelist>
+    </filter>
+
+</phpunit>
Binary file sites/all/modules/.DS_Store has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/CHANGELOG.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,366 @@
+
+Admin Menu 7.x-3.x, xxxx-xx-xx
+------------------------------
+#1177202 by das-peter, dereine, sun: Fixed copying and re-injection of child
+  router items breaks badly. Change them by reference instead.
+  Requires latest Views 3.x code.
+#1212064 by sun: Updated admin_views default views for VBO 3.x.
+#1196590 by sun: Fixed errors and notices for admin_views with Views 3.
+#1144768 by idlewilder, sun: Fixed devel modules to skip are not displayed.
+#1079374 by WillHall: Fixed JS Error: unrecognized expression: [href=/].
+#1114132 by joelstein, sun: Added Field UI to list of developer modules.
+#1008380 by bdragon, sun: Updated admin_views for D7.
+#1146644 by sun: Fixed PHP 5.3 compability in tests.
+#442560 by sun: Fixed 'defer' script attribute breaks Drupal.behaviors in FF3.6.
+#1022902 by matglas86, sun: Updated for changed core Toolbar styles.
+
+
+Admin Menu 7.x-3.0-RC1, 2010-01-07
+----------------------------------
+#990774 by sun: Updated for $closure renamed to $page_bottom.
+#991906 by johnv, sun: Added configure to .info file.
+#947198 by sun: Added hint about disabling Toolbar.
+by sun: Updated administrative settings form for D7 UX guidelines.
+by sun: Disabled "Rebuild system links" button on settings form.
+#420816 by sun, smk-ka: Improved on-demand loading of dynamic paths.
+#420816 by tim.plunkett: Fixed dynamic Field UI paths for vocabularies.
+#871774 by swentel: Fixed developer modules toggle still uses referer_uri().
+#671760 by sun: Updated for new preprocess defaults.
+#731462 by sun: Updated for system_rebuild_theme_data().
+by sun: Re-added a "Rebuild system links" button to settings form.
+#420816 by tim.plunkett: Updated taxonomy path map for machine names.
+#857688 by sun: Updated for reverted system_settings_form().
+#420816 by smk-ka, sun: Added merging of menu trees containing dynamic paths.
+by sun: Fixed tests and minor admin_menu_toolbar styling issues.
+by sun: Fixed various styling issues for admin_menu and admin_menu_toolbar.
+by sun: Updated for Schema API, DBTNG, coding standards.
+by sun: Updated for new admin/modules path.
+#701424 by hutch: Updated for new admin/people/people path.
+by sun: Removed orphan menu rewrite function.
+#667858 by sun: Don't remove the current user from the switch user list.
+#631550 by sun: Updated for fixed MENU_VISIBLE_IN_BREADCRUMB behavior.
+#658344 by dereine, sun: Updated for removed drupal_session_count().
+by sun: Added separate permission to flush cashes.
+by sun: Updated for changed Devel settings form.
+by sun: Updated for new {system}.info module data.
+#614730 by azriprajwala, sun: Updated for hook_theme() key changes.
+by sun: Updated for all theme functions should take a single argument.
+by sun: Reverted removal of registry cache flushing option.
+#578520 by sun: Fixed destination query parameter is processed wrongly.
+#578520 by sun: Updated for $query in url() should always be an array.
+by Dave Reid: Updated for PHP 5 date constants.
+by sun: Updated for new database API.
+by smk-ka: Removed remnants of the registry. Fixed flush admin menu cache
+  command.
+#567618 by smk-ka: Revised test cases. Abstracted out base web test class.
+by sun: Updated for removed registry, new admin paths.
+#326539 by sun: Updated for class attribute array.
+#519782 by sun: Updated for hook_footer() replaced by hook_page_alter().
+#525638 by Razorraser: Updated for admin/build renamed to admin/structure.
+by Dave Reid: Updated for hook_permission().
+#482314 by Dave Reid: Updated for node_type_get_types().
+#437506 by yched, Dave Reid: Updated for menu_router_build().
+#376816 by sun: Updated for compatibility for other JavaScript libraries.
+#337820 by Dave Reid: Updated for new user/logout path.
+#340546 by Dave Reid: Updated for drupal_add_js().
+#340531 by Dave Reid: Updated for module_list().
+#266358 by sun: Updated for drupal_add_css().
+#320526 by yettyn, sun: Updated to UNSTABLE-2 (DBTNG queries, permissions, etc).
+by sun: Changed admin_menu_wipe() to admin_menu_flush_caches().
+by sun: Updated content-type edit menu item locations.
+by sun: Fixed sess_count() changed to drupal_session_count().
+
+
+Admin Menu 6.x-3.x, xxxx-xx-xx
+------------------------------
+#588936 by fenstrat: Fixed Toolbar shortcuts not visible.
+#860390 by Kevin Rogers: Fixed .info file parsing error on uncertain platform.
+#551484 by sun: Fixed stale hook_admin_menu_output_alter() docs.
+
+
+Admin Menu 6.x-3.0-ALPHA4, 2010-03-11
+-------------------------------------
+#730156 by sun: Fixed Administration views.
+by sun: Fixed missing .element-hidden style in D6 for permissions tweak.
+#645526 by TravisCarden: Fixed stale local tasks markup after moving them.
+#366442 by sun: Added tweak to collapse modules on permissions page.
+#655926 by donquixote, sun: Improved performance of delayed mouseout.
+#557062 by sun: Fixed admin_menu_toolbar JS/CSS loaded before admin_menu's.
+#599462 by sun, koyama: Added background-color to avoid unintentional override.
+#601918 by BWPanda: Fixed admin_menu.css overrides admin_menu_toolbar.css.
+#586228 by Island Usurper: Fixed for PHP 5.3.
+#554124 by Dave Reid: Added missing toolbar.png.
+#557062 by Dave Reid: Fixed undefined Drupal.admin error when including
+  admin_menu_toolbar.js before admin_menu.js.
+#511744 by smk-ka, sun: Fixed /admin page links are broken.
+by smk-ka: Added missing variables to hook_uninstall().
+#571038 by smk-ka: Removed call to admin_menu_wipe() and cleaned install file.
+#552190 by Bartezz: Fixed missing t() for user logout link.
+
+
+Admin Menu 6.x-3.0-ALPHA3, 2009-08-16
+-------------------------------------
+#502500 by sun: Added "Create content" menu.
+#538714 by sun: Fixed wrong re-parenting in Drupal's menu system.
+#550132 by sun: Fixed (temporarily) admin_views menu items.
+by sun: Added Administration views sub-module, converting all administrative
+  listing pages in Drupal core into real, ajaxified, and alterable views.
+#547206 by sun: Fixed menu link descriptions lead to mouseover clashes.
+#540954 by Rob Loach: Added String Overrides to list of developer modules.
+#540762 by Deslack: Added Malay translation.
+
+
+Admin Menu 6.x-3.0-ALPHA2, 2009-08-02
+-------------------------------------
+#527908 by sun: Changed theme_admin_menu_links() to use $element['#children'].
+#527908 by markus_petrux, sun: Changed admin menu into a renderable array.
+#420812 by sun, smk-ka: Added support for hook_js().
+by sun: Fixed destination query string of current page not applied to links.
+by sun: Changed Drupal.admin.attachBehaviors() to accept local JS settings.
+#276751 by sun: Revamped rendering of menu additions/widgets.
+#500866 by sun: Updated for removed t() from getInfo() in tests.
+#402058 by sun: Added Administration menu toolbar module.
+by markus_petrux, sun: Added API documentation.
+#461264 by sun: Added site/domain as CSS class.
+#451270 by smk-ka, sun: Changed visual indication for uid1.
+by sun: Minor code clean-up.
+#490670 by sun: Fixed missing menu after installation/upgrade.
+#515718 by joelstein, sun: Added rules_admin module to developer modules list.
+#352065 by sun: Added setting to select developer modules to keep enabled.
+#511854 by psynaptic: Fixed logout link.
+#424960 by markus_petrux, sun: Fixed gzip compression for cached output.
+by sun: Fixed opacity of links in sub-menus.
+#479922 by sun: Fixed fieldsets not collapsed on admin/build/modules/list*.
+#495148 by sun: Fixed MENU_NORMAL_ITEMs do not appear in administration menu.
+by sun: Fixed tests for new content-type locations.
+#345984 by markus_petrux, sun: Fixed old menu links not removed on upgrade.
+#276751 by sun: Major rewrite. Fixed menu items cannot be moved, altered, or
+  added as well as various performance issues.
+by sun: Added variable to allow to disable caching (rewrite).
+
+
+Admin Menu 6.x-3.0-ALPHA1, 2009-06-10
+-------------------------------------
+#236657 by sun: Updated for corrected arguments of system_clear_cache_submit().
+#483870 by sun: Fixed compatibility with new Admin module.
+#483152 by sun: Fixed admin_menu caches not flushed when clean URLs are toggled.
+#479922 by danep: Fixed fieldsets not collapsed on admin/build/modules/list.
+#469716 by sun: Fixed wrong AJAX callback URL under various conditions.
+#471504 by wulff: Updated Danish translation.
+by sun: Fixed admin_menu_suppress() does not suppress margin-top.
+#451270 by sun: Added visual indication when working as uid 1.
+by Dave Reid: Updated for getInfo() in tests.
+#420828 by sun: Added dynamic replacements for cached administration menu.
+#420840 by sun: Fixed Drupal.behaviors.adminMenu must be only executed once.
+#345984 by markus_petrux, sun: Added client-side caching of administration menu.
+  Attention: A new era of Drupal user experience starts here.  This is the very
+  first issue of a series of improvements targeting plain awesomeness.
+#349169 by sun: Fixed Devel switch user links contain multiple path prefixes.
+#345984 by sun: Code clean-up in preparation for client-side caching.
+#415196 by psynaptic: Updated for CSS coding standards.
+#406672 by mr.j, sun: Fixed "Move local tasks" option leaves stale UL.
+by sun: Major code clean-up and sync across 3.x branches.
+#349505 by smk-ka, sun: Performance: Added caching of entire menu output.
+#315342 by wulff: Added "My account" link (by splitting the "Log out" item).
+#384100 by kepol, sun: Fixed content-type items displayed in wrong place.
+#373339 by sun: Fixed double-escaped 'Edit <content-type>' link titles.
+#373372 by sun: Turned procedural JavaScript into admin menu behaviors.
+by sun: Fixed admin menu tests (and updated to 6.x for SimpleTest 2.x).
+#359158 by nitrospectide, sun: Fixed Devel Themer breaks admin menu.
+#365335 by sun: Fixed not all variables removed after uninstall.
+
+
+Admin Menu 6.x-1.3, 2009-01-24
+------------------------------
+#362454 by sun: Fixed Drupal.settings.admin_menu is undefined JS error in some
+  browsers.
+
+
+Admin Menu 6.x-1.2, 2009-01-20
+------------------------------
+#358697 by sun: Added docs about admin_menu_suppress() to README.txt.
+#342684 by darumaki, sun: Added notice about Opera configuration to README.txt.
+#350932 by sun: Fixed "Run updates" link repeated per language/site.
+#342298 by gustz: Updated Spanish translation.
+#346106 by sun: Fixed XHTML-Strict validation for admin menu icon.
+#287448 by sun: Fixed unnecessary menu rebuild for users without permission to
+  use admin menu.
+#342002 by AltaVida: Fixed improper test for node/add paths.
+#272920 by keith.smith: Changed all text strings throughout the module.
+#322731 by sun: Fixed improper use of t() in module install file.
+#282030 by sun: Fixed "Run updates" item visible for unprivileged users.
+#322877 by sun: Added tweak to move page tabs into administration menu.
+#287468 by sun: Fixed module paths directly below "admin" get the wrong parent.
+#310423 by sun: Added optional position: fixed configuration setting.
+#292657 by smk-ka: Improved rendering performance.
+#234149 by yhager, sun: Fixed RTL support for IE.
+#323726 by danez1972: Added Spanish translation.
+#325057 by sun: Updated README.txt.
+#234149 by yhager, levavie, sun: Added RTL support.
+#325057 by sun: Added links to flush specific caches.
+#324334 by AltaVida: Fixed usernames with spaces not in Devel user switch links.
+#319382 by betz: Added Dutch translation.
+
+
+Admin Menu 6.x-1.1, 2008-09-12
+------------------------------
+#295476 by pwolanin, use <front> for icon path to fix front-page path-change
+  bug and pathauto conflict, add wipe button to admin form.
+#301370 by sun: Disabled module fieldset collapsing behavior by default.
+#288672 by sun: Fixed JS hover behavior not working in IE.
+#290803 by sun: Fixed missing devel_themer in devel modules; added some others.
+#286636 by sun: Fixed menus do not drop down in IE6.
+#249537 by pwolanin, sun: Added admin_menu_suppress() to allow other modules to
+  disable the display of admin_menu on certain pages (f.e. popups).
+#268211 by sun: Fixed invalid issue queue links for custom modules and
+  sub-modules of projects.
+#261461 by sun: Added FAQ entry for displaying other menus like admin_menu.
+#264067 by sun: Added FAQ entry for huge amount of anonymous users displayed.
+#280002 by pwolanin: Clean up .test setUp function.
+#242377 by sun: Fixed sub-level menu items exceed total document height.
+
+
+Admin Menu 6.x-1.0, 2008-06-26
+------------------------------
+#266308 by sun: Fixed jQuery 1.0.x incompatible selector for collapsing modules.
+#268373 by sun: Added hook_update to cleanup for alpha/beta testers.
+#268373 by sun: Added menu callback to disable/enable developer modules.
+#132524 by pwolanin: Fixed admin_menu links are re-inserted each time menu links
+  are rebuilt.
+by smk-ka: Performance: Use 'defer' attribute for JavaScript to delay execution.
+#266099 by sun: Fixed description of "Apply margin-top" configuration setting.
+#266308 by sun: Usability: Added Utility module features to collapse module
+  fieldsets on Modules page.
+#251341 by sun: Added docs about display drupal links permission.
+
+
+Admin Menu 6.x-1.0-BETA, 2008-06-08
+-----------------------------------
+#132524 by sun: Fixed support for sub-content-types below node/add.
+#132524 by pwolanin: Added support for localizable menu links.
+#132524 by pwolanin, sun: Fixed menu links adjustments.
+#132524 by pwolanin: Added simpletest.
+#132524 by pwolanin: Major rewrite to better use Drupal 6 menu system.
+#132524 by sun: Moved gettext translation files into translations.
+#132524 by sun: Committing pre-alpha code for D6 due to public demand.
+
+
+Admin Menu 5.x-2.x, xxxx-xx-xx
+------------------------------
+#246221 by sun: Fixed user counter displays different values than Who's online
+  block.
+#239022 by mikl: Added Danish translation.
+#234444 by smk-ka: Fixed admin_menu icon does not respect theme settings.
+#198240 by sun: Fixed admin_menu displayed in print output.
+
+
+Admin Menu 5.x-2.4, 2008-02-24
+------------------------------
+#214740 by sun: Regression: Fixed directly applied marginTop not supported by IE.
+#214725 by sun: Fixed wrong CSS id in admin_menu.js (missed in 5.x-2.3).
+
+
+Admin Menu 5.x-2.3, 2008-02-24
+------------------------------
+#214725 by sun: Fixed CSS id and classes should not contain underscores.
+#209390 by sun: Added note about interaction with user role permissions.
+#214740 by jjeff, sun: Added module settings to configure margin-top CSS.
+#200737 by sun: Changed admin_menu (fav)icon to use theme setting, if defined.
+#203116 by smk-ka: Improved performance of non-cached admin_menu by storing
+  already processed URLs in the cache.
+#224605 by sun: 'Add <content_type>' items do not appear without 'administer
+  nodes' permission.
+#210615 by robertgarrigos: Fixed Mozilla Mac: Collapsible fieldsets display
+  error.
+
+
+Admin Menu 5.x-2.2, 2007-01-08
+------------------------------
+#204884 by jjeff: Usability: Override theme font family declaration.
+#204935 by jjeff: Added mouseout delay for hovered menus (yay!).
+#193941 by downgang: Fixed margin in IE6 using Garland theme.
+#197306 by sun: Fixed 'Run updates' leads to wrong url with clean URLs disabled.
+Moved images into sub-folder.
+by smk-ka: Fixed icon title for user counter not displayed & coding style.
+Fixed user count not displayed without 'administer users' permission.
+
+
+Admin Menu 5.x-2.1, 2007-12-02
+------------------------------
+Fixed adding menu items with negative weight not always working.
+Fixed admin_menu_copy_items() is overwriting already existing items.
+Fixed display menu item ids in devel settings does not work.
+
+
+Admin Menu 5.x-2.0, 2007-12-02
+------------------------------
+Added devel_admin_menu() for fast access to clear-cache, variable editor and
+  switch_user.
+Added username to logout button.
+Added hook_admin_menu() to allow other modules to alter admin_menu.
+#194189 by sun: Added counter for current anonymous/authenticated users.
+Added Drupal.org project issue queue links for all enabled contrib modules.
+#189701 by sun: Changed admin_menu icon to be a menu.
+#193925 by sun: Removed obsolete menu slicing code.
+#193669 by smk-ka: Moved admin_menu builder functions into include file.
+
+
+Admin Menu 5.x-1.2, 2007-11-18
+------------------------------
+#176969 by smk-ka: Fixed performance issues with path(auto) module by
+  introducing a menu cache for admin_menu.
+#179648 by sun: Inject admin_menu into theme.
+  Fixes several CSS bugs in various themes and also activation of admin_menu
+  immediately after installation.
+#191213 by Standard: Fixed block info shouldn't contain the word "block".
+#187816 by sun: Fixed "Add" not translatable.
+#186218 by sun: Fixed admin menu icon too big in Safari.
+#182563 by sun: Fixed wrong datatype for array_search in _admin_menu_get_children().
+#183496 by sun: Fixed invalid argument supplied for foreach in admin_menu_copy_items().
+
+
+Admin Menu 5.x-1.1, 2007-10-10
+------------------------------
+#178876 by sun: Fixed 3rd-level submenus expand without hover over.
+#153455 by sun: Fixed add product node sub-elements are empty.
+Fixed path_to_theme() call breaking blocks page.
+#177582 by sun: Fixed bluebreeze theme compatibility.
+
+
+Admin Menu 5.x-1.0, 2007-09-06
+------------------------------
+#156952 by sun: Fixed admin menu inaccessible due to margins.
+#149229 by sun: Fixed admin menu not expanding in IE7.
+#172545 by sun: Use opacity instead of -moz-opacity.
+#132867 Fixed z-index too low.
+- Fixed admin menu block selectors to override any other theme styles.
+#155589 by sun: Added permission to access administration menu.
+- Fixed a PHP warning when there are no content types defined in the system, as
+  node/add then has no child menu items.
+#155312 by sun: Fixed menu item tooltip clashes.
+Added support for custom stylesheets per theme.
+Removed 4.7.x compatibility.
+
+
+Admin Menu 4.7-1.3, 2007-03-30
+------------------------------
+#126601 Fixed Users can see inaccessible items.
+#121027 Fixed Page not found entries for menu-collapsed.png.
+
+
+Admin Menu 4.7-1.2, 2007-03-04
+------------------------------
+- Fixed menu item adjustments
+- Fixed IE / Safari support
+- Fixed base_path for IE support
+- Added create content options to content management menu
+
+
+Admin Menu 4.7-1.1, 2007-01-24
+------------------------------
+First stable release, compatible to Drupal 4.7.x and 5.x.
+
+
+Admin Menu 4.7-1.0, 2007-01-16
+------------------------------
+Initial release of admin_menu module. Already supporting Drupal 5.0.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,188 @@
+
+-- SUMMARY --
+
+The Administration menu module displays the entire administrative menu tree (and
+most local tasks) in a drop-down menu, providing administrators one- or
+two-click access to most pages.  Other modules may also add menu links to the
+menu using hook_admin_menu_output_alter().
+
+For a full description of the module, visit the project page:
+  http://drupal.org/project/admin_menu
+
+To submit bug reports and feature suggestions, or to track changes:
+  http://drupal.org/project/issues/admin_menu
+
+
+-- REQUIREMENTS --
+
+None.
+
+
+-- INSTALLATION --
+
+* Install as usual, see http://drupal.org/node/70151 for further information.
+
+* You likely want to disable Toolbar module, since its output clashes with
+  Administration menu.
+
+
+-- CONFIGURATION --
+
+* Configure user permissions in Administration » People » Permissions:
+
+  - Use the administration pages and help (System module)
+
+    The top-level administration categories require this permission to be
+    accessible. The administration menu will be empty unless this permission is
+    granted.
+
+  - Access administration menu
+
+    Users in roles with the "Access administration menu" permission will see
+    the administration menu at the top of each page.
+
+  - Display Drupal links
+
+    Users in roles with the "Display drupal links" permission will receive
+    links to drupal.org issue queues for all enabled contributed modules. The
+    issue queue links appear under the administration menu icon.
+
+  Note that the menu items displayed in the administration menu depend on the
+  actual permissions of the viewing user. For example, the "People" menu item
+  is not displayed to a user who is not a member of a role with the "Administer
+  users" permission.
+
+* Customize the menu settings in Administration » Configuration and modules »
+  Administration » Administration menu.
+
+* To prevent administrative menu items from appearing twice, you may hide the
+  "Management" menu block.
+
+
+-- CUSTOMIZATION --
+
+* To override the default administration menu icon, you may:
+
+  1) Disable it via CSS in your theme:
+
+     body #admin-menu-icon { display: none; }
+
+  2) Alter the image by overriding the theme function:
+
+     Copy the entire theme_admin_menu_icon() function into your template.php,
+     rename it to phptemplate_admin_menu_icon() or THEMENAME_admin_menu_icon(),
+     and customize the output according to your needs.
+
+  Remember that the output of the administration menu is cached. To see changes
+  from your theme override function, you must clear your site cache (via
+  the "Flush all caches" link on the menu).
+
+* To override the font size, add the following line to your theme's stylesheet:
+
+  body #admin-menu { font-size: 10px; }
+
+
+-- TROUBLESHOOTING --
+
+* If the menu does not display, check the following:
+
+  - Are the "Access administration menu" and "Use the administration pages and help"
+    permissions enabled for the appropriate roles?
+
+  - Does html.tpl.php of your theme output the $page_bottom variable?
+
+* If the menu is rendered behind a Flash movie object, add this property to your
+  Flash object(s):
+
+  <param name="wmode" value="transparent" />
+
+  See http://drupal.org/node/195386 for further information.
+
+
+-- FAQ --
+
+Q: When the administration menu module is enabled, blank space is added to the
+   bottom of my theme. Why?
+
+A: This is caused by a long list of links to module issue queues at Drupal.org.
+   Use Administer >> User management >> Permissions to disable the "display
+   drupal links" permission for all appropriate roles. Note that since UID 1
+   automatically receives all permissions, the list of issue queue links cannot
+   be disabled for UID 1.
+
+
+Q: After upgrading to 6.x-1.x, the menu disappeared. Why?
+
+A: You may need to regenerate your menu. Visit
+   http://example.com/admin/build/modules to regenerate your menu (substitute
+   your site name for example.com).
+
+
+Q: Can I configure the administration menu module to display another menu (like
+   the Navigation menu, for instance)?
+
+A: No. As the name implies, administration menu module is for administrative
+   menu links only. However, you can copy and paste the contents of
+   admin_menu.css into your theme's stylesheet and replace #admin-menu with any
+   other menu block id (#block-menu-1, for example).
+
+
+Q: Sometimes, the user counter displays a lot of anonymous users, but no spike
+   of users or requests appear in Google Analytics or other tracking tools.
+
+A: If your site was concurrently spidered by search-engine robots, it may have
+   a significant number of anonymous users for a short time. Most web tracking
+   tools like Google Analytics automatically filter out these requests.
+
+
+Q: I enabled "Aggregate and compress CSS files", but admin_menu.css is still
+   there. Is this normal?
+
+A: Yes, this is the intended behavior. the administration menu module only loads
+   its stylesheet as needed (i.e., on page requests by logged-on, administrative
+   users).
+
+
+Q: Why are sub-menus not visible in Opera?
+
+A: In the Opera browser preferences under "web pages" there is an option to fit
+   to width. By disabling this option, sub-menus in the administration menu
+   should appear.
+
+
+Q: How can the administration menu be hidden on certain pages?
+
+A: You can suppress it by simply calling the following function in PHP:
+
+     module_invoke('admin_menu', 'suppress');
+
+   However, this needs to happen as early as possible in the page request, so
+   placing it in the theming layer (resp. a page template file) is too late.
+   Ideally, the function is called in hook_init() in a custom module.  If you do
+   not have a custom module, placing it into some conditional code at the top of
+   template.php may work out, too.
+
+
+-- CONTACT --
+
+Current maintainers:
+* Daniel F. Kudwien (sun) - http://drupal.org/user/54136
+* Peter Wolanin (pwolanin) - http://drupal.org/user/49851
+* Stefan M. Kudwien (smk-ka) - http://drupal.org/user/48898
+* Dave Reid (Dave Reid) - http://drupal.org/user/53892
+
+Major rewrite for Drupal 6 by Peter Wolanin (pwolanin).
+
+This project has been sponsored by:
+* UNLEASHED MIND
+  Specialized in consulting and planning of Drupal powered sites, UNLEASHED
+  MIND offers installation, development, theming, customization, and hosting
+  to get you started. Visit http://www.unleashedmind.com for more information.
+
+* Lullabot
+  Friendly Drupal experts providing professional consulting & education
+  services. Visit http://www.lullabot.com for more information.
+
+* Acquia
+  Commercially Supported Drupal. Visit http://acquia.com for more information.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_devel/admin_devel.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+name = Administration Development tools
+description = Administration and debugging functionality for developers and site builders.
+package = Administration
+core = 7.x
+scripts[] = admin_devel.js
+
+; Information added by drupal.org packaging script on 2013-01-31
+version = "7.x-3.0-rc4"
+core = "7.x"
+project = "admin_menu"
+datestamp = "1359651687"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_devel/admin_devel.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,40 @@
+(function($) {
+
+/**
+ * jQuery debugging helper.
+ *
+ * Invented for Dreditor.
+ *
+ * @usage
+ *   $.debug(var [, name]);
+ *   $variable.debug( [name] );
+ */
+jQuery.extend({
+  debug: function () {
+    // Setup debug storage in global window. We want to look into it.
+    window.debug = window.debug || [];
+
+    args = jQuery.makeArray(arguments);
+    // Determine data source; this is an object for $variable.debug().
+    // Also determine the identifier to store data with.
+    if (typeof this == 'object') {
+      var name = (args.length ? args[0] : window.debug.length);
+      var data = this;
+    }
+    else {
+      var name = (args.length > 1 ? args.pop() : window.debug.length);
+      var data = args[0];
+    }
+    // Store data.
+    window.debug[name] = data;
+    // Dump data into Firebug console.
+    if (typeof console != 'undefined') {
+      console.log(name, data);
+    }
+    return this;
+  }
+});
+// @todo Is this the right way?
+jQuery.fn.debug = jQuery.debug;
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_devel/admin_devel.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Administration and debugging functionality for developers and site builders.
+ */
+
+/**
+ * Implements hook_form_FORMID_alter().
+ */
+function admin_devel_form_admin_menu_theme_settings_alter(&$form, &$form_state) {
+  $form['actions']['wipe_rebuild'] = array(
+    '#type' => 'submit',
+    '#value' => t('Rebuild system links'),
+    '#submit' => array('admin_devel_form_admin_menu_theme_settings_alter_rebuild_submit'),
+    // @todo Not necessarily ready for mass-consumption yet.
+    '#access' => FALSE,
+  );
+}
+
+/**
+ * Form submit handler to wipe and rebuild all 'module' = 'system' menu links.
+ */
+function admin_devel_form_admin_menu_theme_settings_alter_rebuild_submit($form, &$form_state) {
+  // Delete all auto-generated menu links derived from menu router items.
+  db_delete('menu_links')
+    ->condition('module', 'system')
+    ->execute();
+  // Rebuild menu links from current menu router items.
+  menu_rebuild();
+
+  drupal_set_message(t('System links derived from menu router paths have been rebuilt.'));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu-rtl.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,64 @@
+
+#admin-menu {
+  text-align: right;
+}
+#admin-menu .dropdown .admin-menu-users a {
+  background-position: 10% center;
+  padding-left: 22px;
+  padding-right: 0;
+}
+#admin-menu .dropdown .admin-menu-action,
+#admin-menu .dropdown .admin-menu-search {
+  float: left;
+}
+#admin-menu .dropdown .admin-menu-action a {
+  border-left: none;
+  border-right: 1px solid #323232;
+}
+
+/* All lists */
+#admin-menu a {
+  text-align: right;
+}
+#admin-menu .dropdown a {
+  border-left: 1px solid #323232;
+  border-right: 0;
+}
+#admin-menu .dropdown .admin-menu-tab a {
+  border-left: 1px solid #52565E;
+  border-right: 0;
+}
+#admin-menu .dropdown li li a {
+  border-left: 0;
+}
+
+/* All list items */
+#admin-menu .dropdown li {
+  float: right;
+}
+#admin-menu .dropdown li li {
+}
+
+/* Second-level lists */
+#admin-menu .dropdown li ul {
+  left: auto;
+  right: -999em;
+}
+
+/* Third-and-above-level lists */
+#admin-menu .dropdown li li.expandable ul {
+  margin-left: 0;
+  margin-right: 160px;
+}
+
+/* Lists nested under hovered list items */
+#admin-menu .dropdown li.admin-menu-action:hover ul {
+  left: 0 !important;
+  right: auto;
+}
+
+/* Second-and-more-level hovering */
+#admin-menu .dropdown li li.expandable {
+  background-image: url(images/arrow-rtl.png);
+  background-position: 5px 6px;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.admin.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,62 @@
+(function($) {
+
+/**
+ * Live preview of Administration menu components.
+ */
+Drupal.behaviors.adminMenuLivePreview = {
+  attach: function (context, settings) {
+    $('input[name^="admin_menu_components"]', context).once('admin-menu-live-preview')
+      .change(function () {
+        var target = $(this).attr('rel');
+        $(target).toggle(this.checked);
+      })
+      .trigger('change');
+  }
+};
+
+/**
+ * Automatically enables required permissions on demand.
+ *
+ * Many users do not understand that two permissions are required for the
+ * administration menu to appear. Since Drupal core provides no facility for
+ * this, we implement a simple manual confirmation for automatically enabling
+ * the "other" permission.
+ */
+Drupal.behaviors.adminMenuPermissionsSetupHelp = {
+  attach: function (context, settings) {
+    $('#permissions', context).once('admin-menu-permissions-setup', function () {
+      // Retrieve matrix/mapping - these need to use the same indexes for the
+      // same permissions and roles.
+      var $roles = $(this).find('th:not(:first)');
+      var $admin = $(this).find('input[name$="[access administration pages]"]');
+      var $menu = $(this).find('input[name$="[access administration menu]"]');
+
+      // Retrieve the permission label - without description.
+      var adminPermission = $.trim($admin.eq(0).parents('td').prev().children().get(0).firstChild.textContent);
+      var menuPermission = $.trim($menu.eq(0).parents('td').prev().children().get(0).firstChild.textContent);
+
+      $admin.each(function (index) {
+        // Only proceed if both are not enabled already.
+        if (!(this.checked && $menu[index].checked)) {
+          // Stack both checkboxes and attach a click event handler to both.
+          $(this).add($menu[index]).click(function () {
+            // Do nothing when disabling a permission.
+            if (this.checked) {
+              // Figure out which is the other, check whether it still disabled,
+              // and if so, ask whether to auto-enable it.
+              var other = (this == $admin[index] ? $menu[index] : $admin[index]);
+              if (!other.checked && confirm(Drupal.t('Also allow !name role to !permission?', {
+                '!name': $roles[index].textContent,
+                '!permission': (this == $admin[index] ? menuPermission : adminPermission)
+              }))) {
+                other.checked = 'checked';
+              }
+            }
+          });
+        }
+      });
+    });
+  }
+};
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * @file
+ * API documentation for Administration menu.
+ */
+
+/**
+ * Provide expansion arguments for dynamic menu items.
+ *
+ * The map items must be keyed by the dynamic path to expand, i.e. a menu path
+ * containing one or more '%' placeholders. Each map item may have the following
+ * properties:
+ * - parent: The parent menu path to link the expanded items to.
+ * - arguments: An array of argument sets that will be used in the expansion.
+ *   Each set consists of an array of one or more placeholders, which again is
+ *   an array of possible expansion values. Upon expansion, each argument is
+ *   combined with every other argument from the set (technically, the cartesian
+ *   product of all arguments). The expansion values may be empty; that is, you
+ *   do not need to insert logic to skip map items for which no values exist,
+ *   since Administration menu will take care of that.
+ *
+ * @see admin_menu.map.inc
+ */
+function hook_admin_menu_map() {
+  // Expand content types below Structure > Content types.
+  // The key denotes the dynamic path to expand to multiple menu items.
+  $map['admin/structure/types/manage/%node_type'] = array(
+    // Link generated items directly to the "Content types" item.
+    'parent' => 'admin/structure/types',
+    // Create expansion arguments for the '%node_type' placeholder.
+    'arguments' => array(
+      array(
+        '%node_type' => array_keys(node_type_get_types()),
+      ),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Add to the administration menu content before it is rendered.
+ *
+ * Only use this hook to add new data to the menu structure. Use
+ * hook_admin_menu_output_alter() to *alter* existing data.
+ *
+ * @param array $content
+ *   A structured array suitable for drupal_render(), potentially containing:
+ *   - menu: The administrative menu of links below the path 'admin/*'.
+ *   - icon: The icon menu.
+ *   - account: The user account name and log out link.
+ *   - users: The user counter.
+ *   Additionally, these special properties:
+ *   - #components: The actual components contained in $content are configurable
+ *     and depend on the 'admin_menu_components' configuration value. #components
+ *     holds a copy of that for convenience.
+ *   - #complete: A Boolean indicating whether the complete menu should be built,
+ *     ignoring the current configuration in #components.
+ *   Passed by reference.
+ *
+ * @see hook_admin_menu_output_alter()
+ * @see admin_menu_links_menu()
+ * @see admin_menu_links_icon()
+ * @see admin_menu_links_user()
+ * @see theme_admin_menu_links()
+ */
+function hook_admin_menu_output_build(&$content) {
+  // In case your implementation provides a configurable component, check
+  // whether the component should be displayed:
+  if (empty($content['#components']['shortcut.links']) && !$content['#complete']) {
+    return;
+  }
+
+  // Add new top-level item to the menu.
+  if (isset($content['menu'])) {
+    $content['menu']['myitem'] = array(
+      '#title' => t('My item'),
+      // #attributes are used for list items (LI).
+      '#attributes' => array('class' => array('mymodule-myitem')),
+      '#href' => 'mymodule/path',
+      // #options are passed to l().
+      '#options' => array(
+        'query' => drupal_get_destination(),
+        // Apply a class on the link (anchor).
+        'attributes' => array('class' => array('myitem-link-anchor')),
+      ),
+      // #weight controls the order of links in the resulting item list.
+      '#weight' => 50,
+    );
+  }
+  // Add link to the icon menu to manually run cron.
+  if (isset($content['icon'])) {
+    $content['icon']['myitem']['cron'] = array(
+      '#title' => t('Run cron'),
+      '#access' => user_access('administer site configuration'),
+      '#href' => 'admin/reports/status/run-cron',
+    );
+  }
+}
+
+/**
+ * Change the administration menu content before it is rendered.
+ *
+ * Only use this hook to alter existing data in the menu structure. Use
+ * hook_admin_menu_output_build() to *add* new data.
+ *
+ * @param array $content
+ *   A structured array suitable for drupal_render(). Passed by reference.
+ *
+ * @see hook_admin_menu_output_build()
+ */
+function hook_admin_menu_output_alter(&$content) {
+}
+
+/**
+ * Return content to be replace via JS in the cached menu output.
+ *
+ * @param bool $complete
+ *   A Boolean indicating whether all available components of the menu will be
+ *   output and the cache will be skipped.
+ *
+ * @return array
+ *   An associative array whose keys are jQuery selectors and whose values are
+ *   strings containing the replacement content.
+ */
+function hook_admin_menu_replacements($complete) {
+  $items = array();
+  // If the complete menu is output, then it is uncached and will contain the
+  // current counts already.
+  if (!$complete) {
+    // Check whether the users count component is enabled.
+    $components = variable_get('admin_menu_components', array());
+    if (!empty($components['admin_menu.users']) && ($user_count = admin_menu_get_user_count())) {
+      // Replace the counters in the cached menu output with current counts.
+      $items['.admin-menu-users a'] = $user_count;
+    }
+  }
+  return $items;
+}
+
+/**
+ * Inform about additional module-specific caches that can be cleared.
+ *
+ * Administration menu uses this hook to gather information about available
+ * caches that can be flushed individually. Each returned item forms a separate
+ * menu link below the "Flush all caches" link in the icon menu.
+ *
+ * @return array
+ *   An associative array whose keys denote internal identifiers for a
+ *   particular caches (which can be freely defined, but should be in a module's
+ *   namespace) and whose values are associative arrays containing:
+ *   - title: The name of the cache, without "cache" suffix. This label is
+ *     output as link text, but also for the "!title cache cleared."
+ *     confirmation message after flushing the cache; make sure it works and
+ *     makes sense to users in both locations.
+ *   - callback: The name of a function to invoke to flush the individual cache.
+ */
+function hook_admin_menu_cache_info() {
+  $caches['update'] = array(
+    'title' => t('Update data'),
+    'callback' => '_update_cache_clear',
+  );
+  return $caches;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.color.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,46 @@
+
+/**
+ * @file
+ * Administration menu color override.
+ */
+
+#admin-menu {
+  background-color: #911;
+  background-image: url(images/bkg-red.png);
+}
+#admin-menu li.admin-menu-action a {
+  border-left-color: #a91f1f;
+}
+
+/* All lists */
+#admin-menu ul a {
+  border-right-color: #a91f1f;
+}
+#admin-menu ul li.admin-menu-tab a {
+  border-right-color: #52565E;
+}
+#admin-menu li li a {
+  border-top-color: #801f1f;
+}
+
+/* All list items */
+#admin-menu li li {
+  background-color: #991f1f;
+}
+
+/* Second-and-more-level hovering */
+#admin-menu li li.expandable {
+  background-color: #b93f3f;
+}
+#admin-menu li li:hover,
+#admin-menu li li.iehover {
+  background-color: #690f0f;
+}
+#admin-menu li li.expandable:hover a,
+#admin-menu li li.expandable:hover li.expandable:hover a {
+  border-color: #801f1f;
+}
+#admin-menu li li.expandable:hover li a,
+#admin-menu li li.expandable:hover li.expandable:hover li a {
+  border-color: #801f1f;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,250 @@
+
+/**
+ * @file
+ * Administration menu.
+ *
+ * Implementation of Sons of Suckerfish Dropdowns.
+ *
+ * @see www.htmldog.com/articles/suckerfish
+ */
+
+#admin-menu {
+  background: #101010 url(images/bkg.png) bottom left repeat-x;
+  font-size: 9px;
+  font-family: "lucida grande", tahoma, verdana, arial, sans-serif;
+  left: 0;
+  position: absolute;
+  text-align: left;
+  top: 0;
+  width: 100%;
+}
+#admin-menu-wrapper {
+  overflow: hidden;
+}
+#admin-menu .dropdown .admin-menu-icon a {
+  padding: 1px 8px 4px;
+}
+#admin-menu .dropdown .admin-menu-icon ul a {
+  padding: 4px 8px;
+}
+#admin-menu .dropdown .admin-menu-icon img {
+  vertical-align: bottom;
+}
+#admin-menu .dropdown .admin-menu-users a {
+  background: transparent url(images/icon_users.png) 90% center no-repeat;
+  padding-right: 22px;
+}
+#admin-menu .dropdown .admin-menu-action,
+#admin-menu .dropdown .admin-menu-search {
+  float: right;
+}
+#admin-menu .dropdown .admin-menu-action a {
+  border-left: 1px solid #323232;
+  border-right: none;
+}
+body.admin-menu {
+  margin-top: 20px !important;
+}
+
+/* All lists */
+#admin-menu,
+#admin-menu .dropdown {
+  line-height: 1.4em;
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  z-index: 999;
+}
+#admin-menu .dropdown {
+  position: static;
+}
+#admin-menu a,
+#admin-menu li > span {
+  background: transparent none;
+  border: none;
+  color: #EEE;
+  font-weight: normal;
+  text-align: left; /* LTR */
+  text-decoration: none;
+}
+#admin-menu .dropdown a,
+#admin-menu .dropdown li > span {
+  border-right: 1px solid #323232; /* LTR */
+  display: block;
+  padding: 4px 8px;
+}
+#admin-menu .dropdown .admin-menu-tab a {
+  border-right: 1px solid #52565E; /* LTR */
+}
+#admin-menu .dropdown li li a {
+  border-right: none; /* LTR */
+  border-top: 1px solid #323232;
+}
+
+/* All list items */
+#admin-menu .dropdown li {
+  background-image: none;
+  float: left; /* LTR */
+  height: 100%;
+  list-style-image: none;
+  list-style-type: none;
+  margin: 0 !important;
+  padding: 0;
+}
+#admin-menu .dropdown .admin-menu-tab {
+  background: url(images/bkg_tab.png) repeat-x left bottom;
+  padding-bottom: 1px;
+}
+#admin-menu .dropdown li li {
+  background: #202020;
+  filter: Alpha(opacity=88);
+  opacity: 0.88;
+  width: 160px; /* Required for Opera */
+}
+#admin-menu .dropdown li li li {
+  filter: Alpha(opacity=100);
+  opacity: 1;
+}
+
+/* Second-level lists */
+/* Note: We must hide sub-lists or scrollbars might appear (display: none is not read by screen readers). */
+#admin-menu .dropdown li ul {
+  background: none;
+  display: none;
+  left: -999em; /* LTR */
+  line-height: 1.2em;
+  margin: 0;
+  position: absolute;
+  width: 160px;
+}
+
+/* Third-and-above-level lists */
+#admin-menu .dropdown li li.expandable ul {
+  margin: -20px 0 0 160px; /* LTR */
+}
+
+#admin-menu .dropdown li:hover ul ul,
+#admin-menu .dropdown li:hover ul ul ul,
+#admin-menu .dropdown li:hover ul ul ul ul,
+#admin-menu .dropdown li:hover ul ul ul ul ul,
+#admin-menu .dropdown li.iehover ul ul,
+#admin-menu .dropdown li.iehover ul ul ul,
+#admin-menu .dropdown li.iehover ul ul ul ul,
+#admin-menu .dropdown li.iehover ul ul ul ul ul {
+  display: none;
+  left: -999em; /* LTR */
+}
+
+/* Lists nested under hovered list items */
+#admin-menu .dropdown li:hover ul,
+#admin-menu .dropdown li li:hover ul,
+#admin-menu .dropdown li li li:hover ul,
+#admin-menu .dropdown li li li li:hover ul,
+#admin-menu .dropdown li li li li li:hover ul,
+#admin-menu .dropdown li.iehover ul,
+#admin-menu .dropdown li li.iehover ul,
+#admin-menu .dropdown li li li.iehover ul,
+#admin-menu .dropdown li li li li.iehover ul,
+#admin-menu .dropdown li li li li li.iehover ul {
+  display: block;
+  left: auto; /* LTR */
+}
+#admin-menu .dropdown li.admin-menu-action:hover ul {
+  right: 0; /* LTR */
+}
+
+/* Second-and-more-level hovering */
+#admin-menu .dropdown li li.expandable {
+  background: #45454A url(images/arrow.png) no-repeat 145px 6px;
+}
+#admin-menu .dropdown li li:hover,
+#admin-menu .dropdown li li.iehover {
+  background-color: #111;
+}
+#admin-menu .dropdown li li:hover a,
+#admin-menu .dropdown li li:hover li:hover a,
+#admin-menu .dropdown li li:hover li:hover li:hover a {
+  color: #FFF;
+}
+#admin-menu .dropdown li li.expandable:hover a,
+#admin-menu .dropdown li li.expandable:hover li.expandable:hover a {
+  border-color: #444;
+  color: #EEE;
+}
+#admin-menu .dropdown li li.expandable:hover li a,
+#admin-menu .dropdown li li.expandable:hover li.expandable:hover li a {
+  border-color: #323232;
+}
+#admin-menu .dropdown li li:hover li a,
+#admin-menu .dropdown li li.iehover li a,
+#admin-menu .dropdown li li.iehover li.iehover li a {
+  color: #EEE;
+}
+#admin-menu .dropdown li li.iehover a,
+#admin-menu .dropdown li li.iehover li.iehover a,
+#admin-menu .dropdown li li.iehover li.iehover li.iehover a {
+  color: #FFF;
+  width: 90%; /* IE */
+}
+
+/* Search form */
+#admin-menu .admin-menu-search .form-item {
+  margin: 0;
+  padding: 0;
+}
+#admin-menu .admin-menu-search input {
+  background: #fff none center right no-repeat;
+  border: none;
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  border-radius: 5px;
+  font-size: 10px;
+  margin: 1px 0;
+  outline: none;
+  padding: 2px 22px 2px 4px;
+  width: 158px;
+}
+
+#admin-menu .dropdown .admin-menu-search-results {
+  display: block !important;
+  left: auto !important;
+  top: 100%;
+}
+#admin-menu .admin-menu-search-results,
+#admin-menu .admin-menu-search-results li {
+  width: 186px;
+}
+
+#admin-menu li.highlight {
+  background-color: #eee !important;
+}
+#admin-menu li.highlight > a {
+  border-color: #ccc !important;
+  color: #111 !important;
+}
+
+/* #210615: Mozilla on Mac fix */
+html.js fieldset.collapsible div.fieldset-wrapper {
+  overflow: visible;
+}
+
+/* Hide the menu on print output. */
+@media print {
+  #admin-menu {
+    display: none !important;
+  }
+  body.admin-menu {
+    margin-top: 0 !important;
+  }
+}
+
+/**
+ * Tweaks permissions, if enabled.
+ */
+tr.admin-menu-tweak-permissions-processed {
+  cursor: pointer;
+  cursor: hand;
+}
+tr.admin-menu-tweak-permissions-processed td.module {
+  border-top: 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1033 @@
+<?php
+
+/**
+ * @file
+ * Menu builder functions for Administration menu.
+ */
+
+/**
+ * Build the full administration menu tree from static and expanded dynamic items.
+ *
+ * @param $menu_name
+ *   The menu name to use as base for the tree.
+ */
+function admin_menu_tree($menu_name) {
+  // Get placeholder expansion arguments from hook_admin_menu_map()
+  // implementations.
+  module_load_include('inc', 'admin_menu', 'admin_menu.map');
+  $expand_map = module_invoke_all('admin_menu_map');
+  // Allow modules to alter the expansion map.
+  drupal_alter('admin_menu_map', $expand_map);
+
+  $new_map = array();
+  foreach ($expand_map as $path => $data) {
+    // Convert named placeholders to anonymous placeholders, since the menu
+    // system stores paths using anonymous placeholders.
+    $replacements = array_fill_keys(array_keys($data['arguments'][0]), '%');
+    $data['parent'] = strtr($data['parent'], $replacements);
+    $new_map[strtr($path, $replacements)] = $data;
+  }
+  $expand_map = $new_map;
+  unset($new_map);
+
+  // Retrieve dynamic menu link tree for the expansion mappings.
+  // @todo Skip entire processing if initial $expand_map is empty and directly
+  //   return $tree?
+  if (!empty($expand_map)) {
+    $tree_dynamic = admin_menu_tree_dynamic($expand_map);
+  }
+  else {
+    $tree_dynamic = array();
+  }
+
+  // Merge local tasks with static menu tree.
+  $tree = menu_tree_all_data($menu_name);
+  admin_menu_merge_tree($tree, $tree_dynamic, array());
+
+  return $tree;
+}
+
+/**
+ * Load menu link trees for router paths containing dynamic arguments.
+ *
+ * @param $expand_map
+ *   An array containing menu router path placeholder expansion argument
+ *   mappings.
+ *
+ * @return
+ *   An associative array whose keys are the parent paths of the menu router
+ *   paths given in $expand_map as well as the parent paths of any child link
+ *   deeper down the tree. The parent paths are used in admin_menu_merge_tree()
+ *   to check whether anything needs to be merged.
+ *
+ * @see hook_admin_menu_map()
+ */
+function admin_menu_tree_dynamic(array $expand_map) {
+  $p_columns = array();
+  for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
+    $p_columns[] = 'p' . $i;
+  }
+
+  // Fetch p* columns for all router paths to expand.
+  $router_paths = array_keys($expand_map);
+  $plids = db_select('menu_links', 'ml')
+    ->fields('ml', $p_columns)
+    ->condition('router_path', $router_paths)
+    ->execute()
+    ->fetchAll(PDO::FETCH_ASSOC);
+
+  // Unlikely, but possible.
+  if (empty($plids)) {
+    return array();
+  }
+
+  // Use queried plid columns to query sub-trees for the router paths.
+  $query = db_select('menu_links', 'ml');
+  $query->join('menu_router', 'm', 'ml.router_path = m.path');
+  $query
+    ->fields('ml')
+    ->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), drupal_schema_fields_sql('menu_links')));
+
+  // The retrieved menu link trees have to be ordered by depth, so parents
+  // always come before their children for the storage logic below.
+  foreach ($p_columns as $column) {
+    $query->orderBy($column, 'ASC');
+  }
+
+  $db_or = db_or();
+  foreach ($plids as $path_plids) {
+    $db_and = db_and();
+    // plids with value 0 may be ignored.
+    foreach (array_filter($path_plids) as $column => $plid) {
+      $db_and->condition($column, $plid);
+    }
+    $db_or->condition($db_and);
+  }
+  $query->condition($db_or);
+  $result = $query
+    ->execute()
+    ->fetchAllAssoc('mlid', PDO::FETCH_ASSOC);
+
+  // Store dynamic links grouped by parent path for later merging and assign
+  // placeholder expansion arguments.
+  $tree_dynamic = array();
+  foreach ($result as $mlid => $link) {
+    // If contained in $expand_map, then this is a (first) parent, and we need
+    // to store by the defined 'parent' path for later merging, as well as
+    // provide the expansion map arguments to apply to the dynamic tree.
+    if (isset($expand_map[$link['path']])) {
+      $parent_path = $expand_map[$link['path']]['parent'];
+      $link['expand_map'] = $expand_map[$link['path']]['arguments'];
+    }
+    // Otherwise, just store this link keyed by its parent path; the expand_map
+    // is automatically derived from parent paths.
+    else {
+      $parent_path = $result[$link['plid']]['path'];
+    }
+
+    $tree_dynamic[$parent_path][] = $link;
+  }
+
+  return $tree_dynamic;
+}
+
+/**
+ * Walk through the entire menu tree and merge in expanded dynamic menu links.
+ *
+ * @param &$tree
+ *   A menu tree structure as returned by menu_tree_all_data().
+ * @param $tree_dynamic
+ *   A dynamic menu tree structure as returned by admin_menu_tree_dynamic().
+ * @param $expand_map
+ *   An array containing menu router path placeholder expansion argument
+ *   mappings.
+ *
+ * @see hook_admin_menu_map()
+ * @see admin_menu_tree_dynamic()
+ * @see menu_tree_all_data()
+ */
+function admin_menu_merge_tree(array &$tree, array $tree_dynamic, array $expand_map) {
+  foreach ($tree as $key => $data) {
+    $path = $data['link']['router_path'];
+
+    // Recurse into regular menu tree.
+    if ($tree[$key]['below']) {
+      admin_menu_merge_tree($tree[$key]['below'], $tree_dynamic, $expand_map);
+    }
+    // Nothing to merge, if this parent path is not in our dynamic tree.
+    if (!isset($tree_dynamic[$path])) {
+      continue;
+    }
+
+    // Add expanded dynamic items.
+    foreach ($tree_dynamic[$path] as $link) {
+      // If the dynamic item has custom placeholder expansion parameters set,
+      // use them, otherwise keep current.
+      if (isset($link['expand_map'])) {
+        // If there are currently no expansion parameters, we may use the new
+        // set immediately.
+        if (empty($expand_map)) {
+          $current_expand_map = $link['expand_map'];
+        }
+        else {
+          // Otherwise we need to filter out elements that differ from the
+          // current set, i.e. that are not in the same path.
+          $current_expand_map = array();
+          foreach ($expand_map as $arguments) {
+            foreach ($arguments as $placeholder => $value) {
+              foreach ($link['expand_map'] as $new_arguments) {
+                // Skip the new argument if it doesn't contain the current
+                // replacement placeholders or if their values differ.
+                if (!isset($new_arguments[$placeholder]) || $new_arguments[$placeholder] != $value) {
+                  continue;
+                }
+                $current_expand_map[] = $new_arguments;
+              }
+            }
+          }
+        }
+      }
+      else {
+        $current_expand_map = $expand_map;
+      }
+
+      // Skip dynamic items without expansion parameters.
+      if (empty($current_expand_map)) {
+        continue;
+      }
+
+      // Expand anonymous to named placeholders.
+      // @see _menu_load_objects()
+      $path_args = explode('/', $link['path']);
+      $load_functions = unserialize($link['load_functions']);
+      if (is_array($load_functions)) {
+        foreach ($load_functions as $index => $function) {
+          if ($function) {
+            if (is_array($function)) {
+              list($function,) = each($function);
+            }
+            // Add the loader function name minus "_load".
+            $placeholder = '%' . substr($function, 0, -5);
+            $path_args[$index] = $placeholder;
+          }
+        }
+      }
+      $path_dynamic = implode('/', $path_args);
+
+      // Create new menu items using expansion arguments.
+      foreach ($current_expand_map as $arguments) {
+        // Create the cartesian product for all arguments and create new
+        // menu items for each generated combination thereof.
+        foreach (admin_menu_expand_args($arguments) as $replacements) {
+          $newpath = strtr($path_dynamic, $replacements);
+          // Skip this item, if any placeholder could not be replaced.
+          // Faster than trying to invoke _menu_translate().
+          if (strpos($newpath, '%') !== FALSE) {
+            continue;
+          }
+          $map = explode('/', $newpath);
+          $item = admin_menu_translate($link, $map);
+          // Skip this item, if the current user does not have access.
+          if (empty($item)) {
+            continue;
+          }
+          // Build subtree using current replacement arguments.
+          $new_expand_map = array();
+          foreach ($replacements as $placeholder => $value) {
+            $new_expand_map[$placeholder] = array($value);
+          }
+          admin_menu_merge_tree($item, $tree_dynamic, array($new_expand_map));
+          $tree[$key]['below'] += $item;
+        }
+      }
+    }
+    // Sort new subtree items.
+    ksort($tree[$key]['below']);
+  }
+}
+
+/**
+ * Translate an expanded router item into a menu link suitable for rendering.
+ *
+ * @param $router_item
+ *   A menu router item.
+ * @param $map
+ *   A path map with placeholders replaced.
+ */
+function admin_menu_translate($router_item, $map) {
+  _menu_translate($router_item, $map, TRUE);
+
+  // Run through hook_translated_menu_link_alter() to add devel information,
+  // if configured.
+  $router_item['menu_name'] = 'management';
+  // @todo Invoke as usual like _menu_link_translate().
+  admin_menu_translated_menu_link_alter($router_item, NULL);
+
+  if ($router_item['access']) {
+    // Override mlid to make this item unique; since these items are expanded
+    // from dynamic items, the mlid is always the same, so each item would
+    // replace any other.
+    // @todo Doing this instead leads to plenty of duplicate links below
+    //   admin/structure/menu; likely a hidden recursion problem.
+    // $router_item['mlid'] = $router_item['href'] . $router_item['mlid'];
+    $router_item['mlid'] = $router_item['href'];
+    // Turn menu callbacks into regular menu items to make them visible.
+    if ($router_item['type'] == MENU_CALLBACK) {
+      $router_item['type'] = MENU_NORMAL_ITEM;
+    }
+
+    // @see _menu_tree_check_access()
+    $key = (50000 + $router_item['weight']) . ' ' . $router_item['title'] . ' ' . $router_item['mlid'];
+    return array($key => array(
+      'link' => $router_item,
+      'below' => array(),
+    ));
+  }
+
+  return array();
+}
+
+/**
+ * Create the cartesian product of multiple varying sized argument arrays.
+ *
+ * @param $arguments
+ *   A two dimensional array of arguments.
+ *
+ * @see hook_admin_menu_map()
+ */
+function admin_menu_expand_args($arguments) {
+  $replacements = array();
+
+  // Initialize line cursors, move out array keys (placeholders) and assign
+  // numeric keys instead.
+  $i = 0;
+  $placeholders = array();
+  $new_arguments = array();
+  foreach ($arguments as $placeholder => $values) {
+    // Skip empty arguments.
+    if (empty($values)) {
+      continue;
+    }
+    $cursor[$i] = 0;
+    $placeholders[$i] = $placeholder;
+    $new_arguments[$i] = $values;
+    $i++;
+  }
+  $arguments = $new_arguments;
+  unset($new_arguments);
+
+  if ($rows = count($arguments)) {
+    do {
+      // Collect current argument from each row.
+      $row = array();
+      for ($i = 0; $i < $rows; ++$i) {
+        $row[$placeholders[$i]] = $arguments[$i][$cursor[$i]];
+      }
+      $replacements[] = $row;
+
+      // Increment cursor position.
+      $j = $rows - 1;
+      $cursor[$j]++;
+      while (!array_key_exists($cursor[$j], $arguments[$j])) {
+        // No more arguments left: reset cursor, go to next line and increment
+        // that cursor instead. Repeat until argument found or out of rows.
+        $cursor[$j] = 0;
+        if (--$j < 0) {
+          // We're done.
+          break 2;
+        }
+        $cursor[$j]++;
+      }
+    } while (1);
+  }
+
+  return $replacements;
+}
+
+/**
+ * Build the administration menu as renderable menu links.
+ *
+ * @param $tree
+ *   A data structure representing the administration menu tree as returned from
+ *   menu_tree_all_data().
+ *
+ * @return
+ *   The complete administration menu, suitable for theme_admin_menu_links().
+ *
+ * @see theme_admin_menu_links()
+ * @see admin_menu_menu_alter()
+ */
+function admin_menu_links_menu($tree) {
+  $links = array();
+  foreach ($tree as $data) {
+    // Skip items that are inaccessible, invisible, or link to their parent.
+    // (MENU_DEFAULT_LOCAL_TASK), and MENU_CALLBACK-alike items that should only
+    // appear in the breadcrumb.
+    if (!$data['link']['access'] || $data['link']['type'] & MENU_LINKS_TO_PARENT || $data['link']['type'] == MENU_VISIBLE_IN_BREADCRUMB || $data['link']['hidden'] == 1) {
+      continue;
+    }
+    // Hide 'Administer' and make child links appear on this level.
+    // @todo Make this configurable.
+    if ($data['link']['router_path'] == 'admin') {
+      if ($data['below']) {
+        $links = array_merge($links, admin_menu_links_menu($data['below']));
+      }
+      continue;
+    }
+    // Omit alias lookups.
+    $data['link']['localized_options']['alias'] = TRUE;
+    // Remove description to prevent mouseover tooltip clashes.
+    unset($data['link']['localized_options']['attributes']['title']);
+
+    // Make action links (typically "Add ...") appear first in dropdowns.
+    // They might appear first already, but only as long as there is no link
+    // that comes alphabetically first (e.g., a node type with label "Ad").
+    if ($data['link']['type'] & MENU_IS_LOCAL_ACTION) {
+      $data['link']['weight'] -= 1000;
+    }
+
+    $links[$data['link']['href']] = array(
+      '#title' => $data['link']['title'],
+      '#href' => $data['link']['href'],
+      '#options' => $data['link']['localized_options'],
+      '#weight' => $data['link']['weight'],
+    );
+
+    // Recurse to add any child links.
+    $children = array();
+    if ($data['below']) {
+      $children = admin_menu_links_menu($data['below']);
+      $links[$data['link']['href']] += $children;
+    }
+
+    // Handle links pointing to category/overview pages.
+    if ($data['link']['page_callback'] == 'system_admin_menu_block_page' || $data['link']['page_callback'] == 'system_admin_config_page') {
+      // Apply a marker for others to consume.
+      $links[$data['link']['href']]['#is_category'] = TRUE;
+      // Automatically hide empty categories.
+      // Check for empty children first for performance. Only when non-empty
+      // (typically 'admin/config'), check whether children are accessible.
+      if (empty($children) || !element_get_visible_children($children)) {
+        $links[$data['link']['href']]['#access'] = FALSE;
+      }
+    }
+  }
+  return $links;
+}
+
+/**
+ * Build icon menu links; mostly containing maintenance helpers.
+ *
+ * @see theme_admin_menu_links()
+ */
+function admin_menu_links_icon() {
+  $destination = drupal_get_destination();
+
+  $links = array(
+    '#theme' => 'admin_menu_links',
+    '#wrapper_attributes' => array('id' => 'admin-menu-icon'),
+    '#weight' => -100,
+  );
+  $links['icon'] = array(
+    '#title' => theme('admin_menu_icon'),
+    '#attributes' => array('class' => array('admin-menu-icon')),
+    '#href' => '<front>',
+    '#options' => array(
+      'html' => TRUE,
+    ),
+  );
+  // Add link to manually run cron.
+  $links['icon']['cron'] = array(
+    '#title' => t('Run cron'),
+    '#weight' => 50,
+    '#access' => user_access('administer site configuration'),
+    '#href' => 'admin/reports/status/run-cron',
+  );
+  // Add link to run update.php.
+  $links['icon']['update'] = array(
+    '#title' => t('Run updates'),
+    '#weight' => 50,
+    // @see update_access_allowed()
+    '#access' => $GLOBALS['user']->uid == 1 || !empty($GLOBALS['update_free_access']) || user_access('administer software updates'),
+    '#href' => base_path() . 'update.php',
+    '#options' => array(
+      'external' => TRUE,
+    ),
+  );
+  // Add link to drupal.org.
+  $links['icon']['drupal.org'] = array(
+    '#title' => 'Drupal.org',
+    '#weight' => 100,
+    '#access' => user_access('display drupal links'),
+    '#href' => 'http://drupal.org',
+  );
+  // Add links to project issue queues.
+  foreach (module_list(FALSE, TRUE) as $module) {
+    $info = drupal_parse_info_file(drupal_get_path('module', $module) . '/' . $module . '.info');
+    if (!isset($info['project']) || isset($links['icon']['drupal.org'][$info['project']])) {
+      continue;
+    }
+    $links['icon']['drupal.org'][$info['project']] = array(
+      '#title' => t('@project issue queue', array('@project' => $info['name'])),
+      '#weight' => ($info['project'] == 'drupal' ? -10 : 0),
+      '#href' => 'http://drupal.org/project/issues/' . $info['project'],
+      '#options' => array(
+        'query' => array('version' => (isset($info['core']) ? $info['core'] : 'All')),
+      ),
+    );
+  }
+  // Add items to flush caches.
+  $links['icon']['flush-cache'] = array(
+    '#title' => t('Flush all caches'),
+    '#weight' => 20,
+    '#access' => user_access('flush caches'),
+    '#href' => 'admin_menu/flush-cache',
+    '#options' => array(
+      'query' => $destination + array('token' => drupal_get_token('admin_menu/flush-cache')),
+    ),
+  );
+  $caches = module_invoke_all('admin_menu_cache_info');
+  foreach ($caches as $name => $cache) {
+    $links['icon']['flush-cache'][$name] = array(
+      '#title' => $cache['title'],
+      '#href' => 'admin_menu/flush-cache/' . $name,
+      '#options' => array(
+        'query' => $destination + array('token' => drupal_get_token('admin_menu/flush-cache/' . $name)),
+      ),
+    );
+  }
+
+  // Add link to toggle developer modules (performance).
+  $saved_state = variable_get('admin_menu_devel_modules_enabled', NULL);
+  $links['icon']['toggle-modules'] = array(
+    '#title' => isset($saved_state) ? t('Enable developer modules') : t('Disable developer modules'),
+    '#weight' => 88,
+    '#access' => user_access('administer modules'),
+    '#href' => 'admin_menu/toggle-modules',
+    '#options' => array(
+      'query' => $destination + array('token' => drupal_get_token('admin_menu/toggle-modules')),
+    ),
+  );
+
+  // Add Devel module menu links.
+  if (module_exists('devel')) {
+    $devel_tree = menu_build_tree('devel');
+    $devel_links = admin_menu_links_menu($devel_tree);
+    if (element_get_visible_children($devel_links)) {
+      $links['icon']['devel'] = array(
+        '#title' => t('Development'),
+        '#weight' => 30,
+      ) + $devel_links;
+    }
+  }
+
+  return $links;
+}
+
+/**
+ * Builds the account links.
+ *
+ * @see theme_admin_menu_links()
+ */
+function admin_menu_links_account() {
+  $links = array(
+    '#theme' => 'admin_menu_links',
+    '#wrapper_attributes' => array('id' => 'admin-menu-account'),
+    '#weight' => 100,
+  );
+  $links['account'] = array(
+    '#title' => format_username($GLOBALS['user']),
+    '#weight' => -99,
+    '#attributes' => array('class' => array('admin-menu-action', 'admin-menu-account')),
+    '#href' => 'user/' . $GLOBALS['user']->uid,
+  );
+  $links['logout'] = array(
+    '#title' => t('Log out'),
+    '#weight' => -100,
+    '#attributes' => array('class' => array('admin-menu-action')),
+    '#href' => 'user/logout',
+  );
+  // Add Devel module switch user links.
+  $switch_links = module_invoke('devel', 'switch_user_list');
+  if (!empty($switch_links) && count($switch_links) > 1) {
+    foreach ($switch_links as $uid => $link) {
+      $links['account'][$link['title']] = array(
+        '#title' => $link['title'],
+        '#description' => $link['attributes']['title'],
+        '#href' => $link['href'],
+        '#options' => array(
+          'query' => $link['query'],
+          'html' => !empty($link['html']),
+        ),
+      );
+    }
+  }
+  return $links;
+}
+
+/**
+ * Builds user counter.
+ *
+ * @see theme_admin_menu_links()
+ */
+function admin_menu_links_users() {
+  $links = array(
+    '#theme' => 'admin_menu_links',
+    '#wrapper_attributes' => array('id' => 'admin-menu-users'),
+    '#weight' => 150,
+  );
+  // Add link to show current authenticated/anonymous users.
+  $links['user-counter'] = array(
+    '#title' => admin_menu_get_user_count(),
+    '#description' => t('Current anonymous / authenticated users'),
+    '#weight' => -90,
+    '#attributes' => array('class' => array('admin-menu-action', 'admin-menu-users')),
+    '#href' => (user_access('administer users') ? 'admin/people/people' : 'user'),
+  );
+  return $links;
+}
+
+/**
+ * Build search widget.
+ *
+ * @see theme_admin_menu_links()
+ */
+function admin_menu_links_search() {
+  $links = array(
+    '#theme' => 'admin_menu_links',
+    '#wrapper_attributes' => array('id' => 'admin-menu-search'),
+    '#weight' => 180,
+  );
+  $links['search'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Search'),
+    '#title_display' => 'attribute',
+    '#attributes' => array(
+      'placeholder' => t('Search'),
+      'class' => array('admin-menu-search'),
+    ),
+  );
+  return $links;
+}
+
+/**
+ * Form builder function for module settings.
+ */
+function admin_menu_theme_settings() {
+  $form['admin_menu_margin_top'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Adjust top margin'),
+    '#default_value' => variable_get('admin_menu_margin_top', 1),
+    '#description' => t('Shifts the site output down by approximately 20 pixels from the top of the viewport. If disabled, absolute- or fixed-positioned page elements may be covered by the administration menu.'),
+  );
+  $form['admin_menu_position_fixed'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Keep menu at top of page'),
+    '#default_value' => variable_get('admin_menu_position_fixed', 1),
+    '#description' => t('Displays the administration menu always at the top of the browser viewport (even when scrolling the page).'),
+  );
+  // @todo Re-confirm this with latest browser versions.
+  $form['admin_menu_position_fixed']['#description'] .= '<br /><strong>' . t('In some browsers, this setting may result in a malformed page, an invisible cursor, non-selectable elements in forms, or other issues.') . '</strong>';
+
+  $form['advanced'] = array(
+    '#type' => 'vertical_tabs',
+    '#title' => t('Advanced settings'),
+  );
+
+  $form['plugins'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Plugins'),
+    '#group' => 'advanced',
+  );
+  $form['plugins']['admin_menu_components'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Enabled components'),
+    '#options' => array(
+      'admin_menu.icon' => t('Icon menu'),
+      'admin_menu.menu' => t('Administration menu'),
+      'admin_menu.search' => t('Search bar'),
+      'admin_menu.users' => t('User counts'),
+      'admin_menu.account' => t('Account links'),
+    ),
+  );
+  $form['plugins']['admin_menu_components']['#default_value'] = array_keys(array_filter(variable_get('admin_menu_components', $form['plugins']['admin_menu_components']['#options'])));
+
+  $process = element_info_property('checkboxes', '#process', array());
+  $form['plugins']['admin_menu_components']['#process'] = array_merge(array('admin_menu_settings_process_components'), $process);
+  $form['#attached']['js'][] = drupal_get_path('module', 'admin_menu') . '/admin_menu.admin.js';
+
+  $form['tweaks'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('System tweaks'),
+    '#group' => 'advanced',
+  );
+  $form['tweaks']['admin_menu_tweak_modules'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Collapse module groups on the <a href="!modules-url">%modules</a> page', array(
+      '%modules' => t('Modules'),
+      '!modules-url' => url('admin/modules'),
+    )),
+    '#default_value' => variable_get('admin_menu_tweak_modules', 0),
+  );
+  if (module_exists('util')) {
+    $form['tweaks']['admin_menu_tweak_modules']['#description'] .= '<br /><strong>' . t('If the Utility module was installed for this purpose, it can be safely disabled and uninstalled.') . '</strong>';
+  }
+  $form['tweaks']['admin_menu_tweak_permissions'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Collapse module groups on the <a href="@permissions-url">%permissions</a> page', array(
+      '%permissions' => t('Permissions'),
+      '@permissions-url' => url('admin/people/permissions'),
+    )),
+    '#default_value' => variable_get('admin_menu_tweak_permissions', 0),
+  );
+  $form['tweaks']['admin_menu_tweak_tabs'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Move local tasks into menu'),
+    '#default_value' => variable_get('admin_menu_tweak_tabs', 0),
+    '#description' => t('Moves the tabs on all pages into the administration menu. Only possible for themes using the CSS classes <code>tabs primary</code> and <code>tabs secondary</code>.'),
+  );
+
+  $form['performance'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Performance'),
+    '#group' => 'advanced',
+  );
+  $form['performance']['admin_menu_cache_client'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Cache menu in client-side browser'),
+    '#default_value' => variable_get('admin_menu_cache_client', 1),
+  );
+  // Fetch all available modules manually, since module_list() only returns
+  // currently enabled modules, which makes this setting pointless if developer
+  // modules are currently disabled.
+  $all_modules = array();
+  $result = db_query("SELECT name, filename, info FROM {system} WHERE type = 'module' ORDER BY name ASC");
+  foreach ($result as $module) {
+    if (file_exists($module->filename)) {
+      $info = unserialize($module->info);
+      $all_modules[$module->name] = $info['name'];
+    }
+  }
+  $devel_modules = variable_get('admin_menu_devel_modules', _admin_menu_developer_modules());
+  $devel_modules = array_intersect_key($all_modules, array_flip($devel_modules));
+  $form['performance']['admin_menu_devel_modules_skip'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Developer modules to keep enabled'),
+    '#default_value' => variable_get('admin_menu_devel_modules_skip', array()),
+    '#options' => $devel_modules,
+    '#access' => !empty($devel_modules),
+    '#description' => t('The selected modules will not be disabled when the link %disable-developer-modules below the icon in the menu is invoked.', array(
+      '%disable-developer-modules' => t('Disable developer modules'),
+    )),
+  );
+
+  return system_settings_form($form);
+}
+
+/**
+ * #process callback for component plugin form element in admin_menu_theme_settings().
+ */
+function admin_menu_settings_process_components($element) {
+  // Assign 'rel' attributes to all options to achieve a live preview.
+  // Unfortunately, #states relies on wrapping .form-wrapper classes, so it
+  // cannot be used here.
+  foreach ($element['#options'] as $key => $label) {
+    if (!isset($element[$key]['#attributes']['rel'])) {
+      $id = preg_replace('/[^a-z]/', '-', $key);
+      $element[$key]['#attributes']['rel'] = '#' . $id;
+    }
+  }
+  return $element;
+}
+
+/**
+ * Form validation handler for admin_menu_theme_settings().
+ */
+function admin_menu_theme_settings_validate(&$form, &$form_state) {
+  // Change the configured components to Boolean values.
+  foreach ($form_state['values']['admin_menu_components'] as $component => &$enabled) {
+    $enabled = (bool) $enabled;
+  }
+}
+
+/**
+ * Implementation of hook_form_FORM_ID_alter().
+ *
+ * Extends Devel module with Administration menu developer settings.
+ */
+function _admin_menu_form_devel_admin_settings_alter(&$form, $form_state) {
+  // Shift system_settings_form buttons.
+  $weight = isset($form['buttons']['#weight']) ? $form['buttons']['#weight'] : 0;
+  $form['buttons']['#weight'] = $weight + 1;
+
+  $form['admin_menu'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Administration menu settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  $display_options = array('mid', 'weight', 'pid');
+  $display_options = array(0 => t('None'), 'mlid' => t('Menu link ID'), 'weight' => t('Weight'), 'plid' => t('Parent link ID'));
+  $form['admin_menu']['admin_menu_display'] = array(
+    '#type' => 'radios',
+    '#title' => t('Display additional data for each menu item'),
+    '#default_value' => variable_get('admin_menu_display', 0),
+    '#options' => $display_options,
+    '#description' => t('Display the selected items next to each menu item link.'),
+  );
+  $form['admin_menu']['admin_menu_show_all'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Display all menu items'),
+    '#default_value' => variable_get('admin_menu_show_all', 0),
+    '#description' => t('If enabled, all menu items are displayed regardless of your site permissions. <em>Note: Do not enable on a production site.</em>'),
+  );
+}
+
+/**
+ * Menu callback; Enable/disable developer modules.
+ *
+ * This can save up to 150ms on each uncached page request.
+ */
+function admin_menu_toggle_modules() {
+  if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], current_path())) {
+    return MENU_ACCESS_DENIED;
+  }
+
+  $rebuild = FALSE;
+  $saved_state = variable_get('admin_menu_devel_modules_enabled', NULL);
+  if (isset($saved_state)) {
+    // Re-enable modules that were enabled before.
+    module_enable($saved_state);
+    variable_del('admin_menu_devel_modules_enabled');
+    drupal_set_message(t('Enabled these modules: !module-list.', array('!module-list' => implode(', ', $saved_state))));
+    $rebuild = TRUE;
+  }
+  else {
+    // Allow site admins to override this variable via settings.php.
+    $devel_modules = variable_get('admin_menu_devel_modules', _admin_menu_developer_modules());
+    // Store currently enabled modules in a variable.
+    $devel_modules = array_intersect(module_list(FALSE, FALSE), $devel_modules);
+    $devel_modules = array_diff($devel_modules, variable_get('admin_menu_devel_modules_skip', array()));
+    if (!empty($devel_modules)) {
+      variable_set('admin_menu_devel_modules_enabled', $devel_modules);
+      // Disable developer modules.
+      module_disable($devel_modules);
+      drupal_set_message(t('Disabled these modules: !module-list.', array('!module-list' => implode(', ', $devel_modules))));
+      $rebuild = TRUE;
+    }
+    else {
+      drupal_set_message(t('No developer modules are enabled.'));
+    }
+  }
+  if ($rebuild) {
+    // Make sure everything is rebuilt, basically a combination of the calls
+    // from system_modules() and system_modules_submit().
+    drupal_theme_rebuild();
+    menu_rebuild();
+    cache_clear_all('schema', 'cache');
+    cache_clear_all();
+    drupal_clear_css_cache();
+    drupal_clear_js_cache();
+    // Synchronize to catch any actions that were added or removed.
+    actions_synchronize();
+    // Finally, flush admin_menu's cache.
+    admin_menu_flush_caches();
+  }
+  drupal_goto();
+}
+
+/**
+ * Helper function to return a default list of developer modules.
+ */
+function _admin_menu_developer_modules() {
+  return array(
+    'admin_devel',
+    'cache_disable',
+    'coder',
+    'content_copy',
+    'context_ui',
+    'debug',
+    'delete_all',
+    'demo',
+    'devel',
+    'devel_node_access',
+    'devel_themer',
+    'field_ui',
+    'fontyourface_ui',
+    'form_controller',
+    'imagecache_ui',
+    'journal',
+    'l10n_client',
+    'l10n_update',
+    'macro',
+    'rules_admin',
+    'stringoverrides',
+    'trace',
+    'upgrade_status',
+    'user_display_ui',
+    'util',
+    'views_ui',
+    'views_theme_wizard',
+  );
+}
+
+/**
+ * Flush all caches or a specific one.
+ *
+ * @param $name
+ *   (optional) Name of cache to flush.
+ */
+function admin_menu_flush_cache($name = NULL) {
+  if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], current_path())) {
+    return MENU_ACCESS_DENIED;
+  }
+  if (isset($name)) {
+    $caches = module_invoke_all('admin_menu_cache_info');
+    if (!isset($caches[$name])) {
+      return MENU_NOT_FOUND;
+    }
+  }
+  else {
+    $caches[$name] = array(
+      'title' => t('Every'),
+      'callback' => 'drupal_flush_all_caches',
+    );
+  }
+  // Pass the cache to flush forward to the callback.
+  $function = $caches[$name]['callback'];
+  $function($name);
+
+  drupal_set_message(t('!title cache cleared.', array('!title' => $caches[$name]['title'])));
+
+  // The JavaScript injects a destination request parameter pointing to the
+  // originating page, so the user is redirected back to that page. Without
+  // destination parameter, the redirect ends on the front page.
+  drupal_goto();
+}
+
+/**
+ * Implements hook_admin_menu_cache_info().
+ */
+function admin_menu_admin_menu_cache_info() {
+  $caches['admin_menu'] = array(
+    'title' => t('Administration menu'),
+    'callback' => '_admin_menu_flush_cache',
+  );
+  return $caches;
+}
+
+/**
+ * Implements hook_admin_menu_cache_info() on behalf of System module.
+ */
+function system_admin_menu_cache_info() {
+  $caches = array(
+    'assets' => t('CSS and JavaScript'),
+    'cache' => t('Page and else'),
+    'menu' => t('Menu'),
+    'registry' => t('Class registry'),
+    'theme' => t('Theme registry'),
+  );
+  foreach ($caches as $name => $cache) {
+    $caches[$name] = array(
+      'title' => $cache,
+      'callback' => '_admin_menu_flush_cache',
+    );
+  }
+  return $caches;
+}
+
+/**
+ * Implements hook_admin_menu_cache_info() on behalf of Update module.
+ */
+function update_admin_menu_cache_info() {
+  $caches['update'] = array(
+    'title' => t('Update data'),
+    'callback' => '_update_cache_clear',
+  );
+  return $caches;
+}
+
+/**
+ * Flush all caches or a specific one.
+ *
+ * @param $name
+ *   (optional) Name of cache to flush.
+ *
+ * @see system_admin_menu_cache_info()
+ */
+function _admin_menu_flush_cache($name = NULL) {
+  switch ($name) {
+    case 'admin_menu':
+      admin_menu_flush_caches();
+      break;
+
+    case 'menu':
+      menu_rebuild();
+      break;
+
+    case 'registry':
+      registry_rebuild();
+      // Fall-through to clear cache tables, since registry information is
+      // usually the base for other data that is cached (e.g. SimpleTests).
+    case 'cache':
+      // Don't clear cache_form - in-progress form submissions may break.
+      // Ordered so clearing the page cache will always be the last action.
+      // @see drupal_flush_all_caches()
+      $core = array('cache', 'cache_bootstrap', 'cache_filter', 'cache_page');
+      $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
+      foreach ($cache_tables as $table) {
+        cache_clear_all('*', $table, TRUE);
+      }
+      break;
+
+    case 'assets':
+      // Change query-strings on css/js files to enforce reload for all users.
+      _drupal_flush_css_js();
+
+      drupal_clear_css_cache();
+      drupal_clear_js_cache();
+
+      // Clear the page cache, since cached HTML pages might link to old CSS and
+      // JS aggregates.
+      cache_clear_all('*', 'cache_page', TRUE);
+      break;
+
+    case 'theme':
+      system_rebuild_theme_data();
+      drupal_theme_rebuild();
+      break;
+  }
+}
+
+/**
+ * Preprocesses variables for theme_admin_menu_icon().
+ */
+function template_preprocess_admin_menu_icon(&$variables) {
+  // Image source might have been passed in as theme variable.
+  if (!isset($variables['src'])) {
+    if (theme_get_setting('toggle_favicon')) {
+      $variables['src'] = theme_get_setting('favicon');
+    }
+    else {
+      $variables['src'] = base_path() . 'misc/favicon.ico';
+    }
+  }
+  // Strip the protocol without delimiters for transient HTTP/HTTPS support.
+  // Since the menu is cached on the server-side and client-side, the cached
+  // version might contain a HTTP link, whereas the actual page is on HTTPS.
+  // Relative paths will work fine, but theme_get_setting() returns an
+  // absolute URI.
+  $variables['src'] = preg_replace('@^https?:@', '', $variables['src']);
+  $variables['src'] = check_plain($variables['src']);
+  $variables['alt'] = t('Home');
+}
+
+/**
+ * Renders an icon to display in the administration menu.
+ *
+ * @ingroup themeable
+ */
+function theme_admin_menu_icon($variables) {
+  return '<img class="admin-menu-icon" src="' . $variables['src'] . '" width="16" height="16" alt="' . $variables['alt'] . '" />';
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,16 @@
+name = Administration menu
+description = "Provides a dropdown menu to most administrative tasks and other common destinations (to users with the proper permissions)."
+package = Administration
+core = 7.x
+configure = admin/config/administration/admin_menu
+; Requires menu_build_tree() conditions; available after 7.10.
+; @see http://drupal.org/node/1025582
+dependencies[] = system (>7.10)
+files[] = tests/admin_menu.test
+
+; Information added by drupal.org packaging script on 2013-01-31
+version = "7.x-3.0-rc4"
+core = "7.x"
+project = "admin_menu"
+datestamp = "1359651687"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,122 @@
+<?php
+
+/**
+ * @file
+ * Install, update, and uninstall functions for the admin menu module.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function admin_menu_schema() {
+  $schema['cache_admin_menu'] = drupal_get_schema_unprocessed('system', 'cache');
+  $schema['cache_admin_menu']['description'] = 'Cache table for Administration menu to store client-side caching hashes.';
+  return $schema;
+}
+
+/**
+ * Implements hook_install().
+ */
+function admin_menu_install() {
+  // Increase the module weight, so admin_menu catches any alterations made by
+  // other modules in hook_menu_alter().
+  db_update('system')
+    ->fields(array('weight' => 100))
+    ->condition('type', 'module')
+    ->condition('name', 'admin_menu')
+    ->execute();
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function admin_menu_uninstall() {
+  // Delete variables.
+  variable_del('admin_menu_components');
+  variable_del('admin_menu_devel_modules');
+  variable_del('admin_menu_devel_modules_enabled');
+  variable_del('admin_menu_devel_modules_skip');
+  variable_del('admin_menu_margin_top');
+  variable_del('admin_menu_position_fixed');
+  variable_del('admin_menu_tweak_modules');
+  variable_del('admin_menu_tweak_tabs');
+  variable_del('admin_menu_show_all');
+  variable_del('admin_menu_display');
+  variable_del('admin_menu_cache_server');
+  variable_del('admin_menu_cache_client');
+}
+
+/**
+ * Ensure that admin_menu is rebuilt after upgrading to D6.
+ */
+function admin_menu_update_6000() {
+  // Drop the {admin_menu} table in admin_menu_update_6000() on sites that used
+  // one of the later patches in #132524.
+  if (db_table_exists('admin_menu')) {
+    db_drop_table('admin_menu');
+  }
+}
+
+/**
+ * Wipe and rebuild so we can switch the icon path to <front>.
+ */
+function admin_menu_update_6001() {
+  db_delete('menu_links')->condition('module', 'admin_menu')->execute();
+  menu_cache_clear('admin_menu');
+}
+
+/**
+ * Add {cache_admin_menu} table.
+ */
+function admin_menu_update_7300() {
+  if (!db_table_exists('cache_admin_menu')) {
+    $schema = drupal_get_schema_unprocessed('system', 'cache');
+    db_create_table('cache_admin_menu', $schema);
+  }
+}
+
+/**
+ * Increase the module weight.
+ *
+ * @see admin_menu_install()
+ */
+function admin_menu_update_7302() {
+  db_update('system')
+    ->fields(array('weight' => 100))
+    ->condition('type', 'module')
+    ->condition('name', 'admin_menu')
+    ->execute();
+}
+
+/**
+ * Remove local tasks from {menu_links} table.
+ */
+function admin_menu_update_7303() {
+  db_delete('menu_router')
+    ->condition('path', 'admin/%', 'LIKE')
+    ->condition('type', MENU_IS_LOCAL_TASK, '&')
+    ->execute();
+}
+
+/**
+ * Remove obsolete 'admin_menu' menu and all orphan links in it.
+ */
+function admin_menu_update_7304() {
+  // Remove the custom menu used by 6.x-1.x.
+  if (db_table_exists('menu_custom')) {
+    db_delete('menu_custom')->condition('menu_name', 'admin_menu')->execute();
+  }
+
+  // 6.x-1.x cloned the entire link structure below the path 'admin' into a
+  // separate 'menu_name' "admin_menu" with 'module' "admin_menu". 6.x-3.x and
+  // early alpha versions of 7.x-3.x still did something similar. All of these
+  // records are obsolete. Removal of the 'module' records (without different
+  // menu_name) is particularly important, since they would otherwise appear
+  // as duplicate links.
+  db_delete('menu_links')
+    ->condition(db_or()
+      ->condition('module', 'admin_menu')
+      ->condition('menu_name', 'admin_menu')
+    )
+    ->execute();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,397 @@
+(function($) {
+
+Drupal.admin = Drupal.admin || {};
+Drupal.admin.behaviors = Drupal.admin.behaviors || {};
+Drupal.admin.hashes = Drupal.admin.hashes || {};
+
+/**
+ * Core behavior for Administration menu.
+ *
+ * Test whether there is an administration menu is in the output and execute all
+ * registered behaviors.
+ */
+Drupal.behaviors.adminMenu = {
+  attach: function (context, settings) {
+    // Initialize settings.
+    settings.admin_menu = $.extend({
+      suppress: false,
+      margin_top: false,
+      position_fixed: false,
+      tweak_modules: false,
+      tweak_permissions: false,
+      tweak_tabs: false,
+      destination: '',
+      basePath: settings.basePath,
+      hash: 0,
+      replacements: {}
+    }, settings.admin_menu || {});
+    // Check whether administration menu should be suppressed.
+    if (settings.admin_menu.suppress) {
+      return;
+    }
+    var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
+    // Client-side caching; if administration menu is not in the output, it is
+    // fetched from the server and cached in the browser.
+    if (!$adminMenu.length && settings.admin_menu.hash) {
+      Drupal.admin.getCache(settings.admin_menu.hash, function (response) {
+          if (typeof response == 'string' && response.length > 0) {
+            $('body', context).append(response);
+          }
+          var $adminMenu = $('#admin-menu:not(.admin-menu-processed)', context);
+          // Apply our behaviors.
+          Drupal.admin.attachBehaviors(context, settings, $adminMenu);
+          // Allow resize event handlers to recalculate sizes/positions.
+          $(window).triggerHandler('resize');
+      });
+    }
+    // If the menu is in the output already, this means there is a new version.
+    else {
+      // Apply our behaviors.
+      Drupal.admin.attachBehaviors(context, settings, $adminMenu);
+    }
+  }
+};
+
+/**
+ * Collapse fieldsets on Modules page.
+ */
+Drupal.behaviors.adminMenuCollapseModules = {
+  attach: function (context, settings) {
+    if (settings.admin_menu.tweak_modules) {
+      $('#system-modules fieldset:not(.collapsed)', context).addClass('collapsed');
+    }
+  }
+};
+
+/**
+ * Collapse modules on Permissions page.
+ */
+Drupal.behaviors.adminMenuCollapsePermissions = {
+  attach: function (context, settings) {
+    if (settings.admin_menu.tweak_permissions) {
+      // Freeze width of first column to prevent jumping.
+      $('#permissions th:first', context).css({ width: $('#permissions th:first', context).width() });
+      // Attach click handler.
+      $modules = $('#permissions tr:has(td.module)', context).once('admin-menu-tweak-permissions', function () {
+        var $module = $(this);
+        $module.bind('click.admin-menu', function () {
+          // @todo Replace with .nextUntil() in jQuery 1.4.
+          $module.nextAll().each(function () {
+            var $row = $(this);
+            if ($row.is(':has(td.module)')) {
+              return false;
+            }
+            $row.toggleClass('element-hidden');
+          });
+        });
+      });
+      // Collapse all but the targeted permission rows set.
+      if (window.location.hash.length) {
+        $modules = $modules.not(':has(' + window.location.hash + ')');
+      }
+      $modules.trigger('click.admin-menu');
+    }
+  }
+};
+
+/**
+ * Apply margin to page.
+ *
+ * Note that directly applying marginTop does not work in IE. To prevent
+ * flickering/jumping page content with client-side caching, this is a regular
+ * Drupal behavior.
+ */
+Drupal.behaviors.adminMenuMarginTop = {
+  attach: function (context, settings) {
+    if (!settings.admin_menu.suppress && settings.admin_menu.margin_top) {
+      $('body:not(.admin-menu)', context).addClass('admin-menu');
+    }
+  }
+};
+
+/**
+ * Retrieve content from client-side cache.
+ *
+ * @param hash
+ *   The md5 hash of the content to retrieve.
+ * @param onSuccess
+ *   A callback function invoked when the cache request was successful.
+ */
+Drupal.admin.getCache = function (hash, onSuccess) {
+  if (Drupal.admin.hashes.hash !== undefined) {
+    return Drupal.admin.hashes.hash;
+  }
+  $.ajax({
+    cache: true,
+    type: 'GET',
+    dataType: 'text', // Prevent auto-evaluation of response.
+    global: false, // Do not trigger global AJAX events.
+    url: Drupal.settings.admin_menu.basePath.replace(/admin_menu/, 'js/admin_menu/cache/' + hash),
+    success: onSuccess,
+    complete: function (XMLHttpRequest, status) {
+      Drupal.admin.hashes.hash = status;
+    }
+  });
+};
+
+/**
+ * TableHeader callback to determine top viewport offset.
+ *
+ * @see toolbar.js
+ */
+Drupal.admin.height = function() {
+  var $adminMenu = $('#admin-menu');
+  var height = $adminMenu.outerHeight();
+  // In IE, Shadow filter adds some extra height, so we need to remove it from
+  // the returned height.
+  if ($adminMenu.css('filter') && $adminMenu.css('filter').match(/DXImageTransform\.Microsoft\.Shadow/)) {
+    height -= $adminMenu.get(0).filters.item("DXImageTransform.Microsoft.Shadow").strength;
+  }
+  return height;
+};
+
+/**
+ * @defgroup admin_behaviors Administration behaviors.
+ * @{
+ */
+
+/**
+ * Attach administrative behaviors.
+ */
+Drupal.admin.attachBehaviors = function (context, settings, $adminMenu) {
+  if ($adminMenu.length) {
+    $adminMenu.addClass('admin-menu-processed');
+    $.each(Drupal.admin.behaviors, function() {
+      this(context, settings, $adminMenu);
+    });
+  }
+};
+
+/**
+ * Apply 'position: fixed'.
+ */
+Drupal.admin.behaviors.positionFixed = function (context, settings, $adminMenu) {
+  if (settings.admin_menu.position_fixed) {
+    $adminMenu.addClass('admin-menu-position-fixed');
+    $adminMenu.css('position', 'fixed');
+  }
+};
+
+/**
+ * Move page tabs into administration menu.
+ */
+Drupal.admin.behaviors.pageTabs = function (context, settings, $adminMenu) {
+  if (settings.admin_menu.tweak_tabs) {
+    var $tabs = $(context).find('ul.tabs.primary');
+    $adminMenu.find('#admin-menu-wrapper > ul').eq(1)
+      .append($tabs.find('li').addClass('admin-menu-tab'));
+    $(context).find('ul.tabs.secondary')
+      .appendTo('#admin-menu-wrapper > ul > li.admin-menu-tab.active')
+      .removeClass('secondary');
+    $tabs.remove();
+  }
+};
+
+/**
+ * Perform dynamic replacements in cached menu.
+ */
+Drupal.admin.behaviors.replacements = function (context, settings, $adminMenu) {
+  for (var item in settings.admin_menu.replacements) {
+    $(item, $adminMenu).html(settings.admin_menu.replacements[item]);
+  }
+};
+
+/**
+ * Inject destination query strings for current page.
+ */
+Drupal.admin.behaviors.destination = function (context, settings, $adminMenu) {
+  if (settings.admin_menu.destination) {
+    $('a.admin-menu-destination', $adminMenu).each(function() {
+      this.search += (!this.search.length ? '?' : '&') + Drupal.settings.admin_menu.destination;
+    });
+  }
+};
+
+/**
+ * Apply JavaScript-based hovering behaviors.
+ *
+ * @todo This has to run last.  If another script registers additional behaviors
+ *   it will not run last.
+ */
+Drupal.admin.behaviors.hover = function (context, settings, $adminMenu) {
+  // Hover emulation for IE 6.
+  if ($.browser.msie && parseInt(jQuery.browser.version) == 6) {
+    $('li', $adminMenu).hover(
+      function () {
+        $(this).addClass('iehover');
+      },
+      function () {
+        $(this).removeClass('iehover');
+      }
+    );
+  }
+
+  // Delayed mouseout.
+  $('li.expandable', $adminMenu).hover(
+    function () {
+      // Stop the timer.
+      clearTimeout(this.sfTimer);
+      // Display child lists.
+      $('> ul', this)
+        .css({left: 'auto', display: 'block'})
+        // Immediately hide nephew lists.
+        .parent().siblings('li').children('ul').css({left: '-999em', display: 'none'});
+    },
+    function () {
+      // Start the timer.
+      var uls = $('> ul', this);
+      this.sfTimer = setTimeout(function () {
+        uls.css({left: '-999em', display: 'none'});
+      }, 400);
+    }
+  );
+};
+
+/**
+ * Apply the search bar functionality.
+ */
+Drupal.admin.behaviors.search = function (context, settings, $adminMenu) {
+  // @todo Add a HTML ID.
+  var $input = $('input.admin-menu-search', $adminMenu);
+  // Initialize the current search needle.
+  var needle = $input.val();
+  // Cache of all links that can be matched in the menu.
+  var links;
+  // Minimum search needle length.
+  var needleMinLength = 2;
+  // Append the results container.
+  var $results = $('<div />').insertAfter($input);
+
+  /**
+   * Executes the search upon user input.
+   */
+  function keyupHandler() {
+    var matches, $html, value = $(this).val();
+    // Only proceed if the search needle has changed.
+    if (value !== needle) {
+      needle = value;
+      // Initialize the cache of menu links upon first search.
+      if (!links && needle.length >= needleMinLength) {
+        // @todo Limit to links in dropdown menus; i.e., skip menu additions.
+        links = buildSearchIndex($adminMenu.find('li:not(.admin-menu-action, .admin-menu-action li) > a'));
+      }
+      // Empty results container when deleting search text.
+      if (needle.length < needleMinLength) {
+        $results.empty();
+      }
+      // Only search if the needle is long enough.
+      if (needle.length >= needleMinLength && links) {
+        matches = findMatches(needle, links);
+        // Build the list in a detached DOM node.
+        $html = buildResultsList(matches);
+        // Display results.
+        $results.empty().append($html);
+      }
+    }
+  }
+
+  /**
+   * Builds the search index.
+   */
+  function buildSearchIndex($links) {
+    return $links
+      .map(function () {
+        var text = (this.textContent || this.innerText);
+        // Skip menu entries that do not contain any text (e.g., the icon).
+        if (typeof text === 'undefined') {
+          return;
+        }
+        return {
+          text: text,
+          textMatch: text.toLowerCase(),
+          element: this
+        };
+      });
+  }
+
+  /**
+   * Searches the index for a given needle and returns matching entries.
+   */
+  function findMatches(needle, links) {
+    var needleMatch = needle.toLowerCase();
+    // Select matching links from the cache.
+    return $.grep(links, function (link) {
+      return link.textMatch.indexOf(needleMatch) !== -1;
+    });
+  }
+
+  /**
+   * Builds the search result list in a detached DOM node.
+   */
+  function buildResultsList(matches) {
+    var $html = $('<ul class="dropdown admin-menu-search-results" />');
+    $.each(matches, function () {
+      var result = this.text;
+      var $element = $(this.element);
+
+      // Check whether there is a top-level category that can be prepended.
+      var $category = $element.closest('#admin-menu-wrapper > ul > li');
+      var categoryText = $category.find('> a').text()
+      if ($category.length && categoryText) {
+        result = categoryText + ': ' + result;
+      }
+
+      var $result = $('<li><a href="' + $element.attr('href') + '">' + result + '</a></li>');
+      $result.data('original-link', $(this.element).parent());
+      $html.append($result);
+    });
+    return $html;
+  }
+
+  /**
+   * Highlights selected result.
+   */
+  function resultsHandler(e) {
+    var $this = $(this);
+    var show = e.type === 'mouseenter' || e.type === 'focusin';
+    $this.trigger(show ? 'showPath' : 'hidePath', [this]);
+  }
+
+  /**
+   * Closes the search results and clears the search input.
+   */
+  function resultsClickHandler(e, link) {
+    var $original = $(this).data('original-link');
+    $original.trigger('mouseleave');
+    $input.val('').trigger('keyup');
+  }
+
+  /**
+   * Shows the link in the menu that corresponds to a search result.
+   */
+  function highlightPathHandler(e, link) {
+    if (link) {
+      var $original = $(link).data('original-link');
+      var show = e.type === 'showPath';
+      // Toggle an additional CSS class to visually highlight the matching link.
+      // @todo Consider using same visual appearance as regular hover.
+      $original.toggleClass('highlight', show);
+      $original.trigger(show ? 'mouseenter' : 'mouseleave');
+    }
+  }
+
+  // Attach showPath/hidePath handler to search result entries.
+  $results.delegate('li', 'mouseenter mouseleave focus blur', resultsHandler);
+  // Hide the result list after a link has been clicked, useful for overlay.
+  $results.delegate('li', 'click', resultsClickHandler);
+  // Attach hover/active highlight behavior to search result entries.
+  $adminMenu.delegate('.admin-menu-search-results li', 'showPath hidePath', highlightPathHandler);
+  // Attach the search input event handler.
+  $input.bind('keyup search', keyupHandler);
+};
+
+/**
+ * @} End of "defgroup admin_behaviors".
+ */
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.map.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * @file
+ * Implements hook_admin_menu_map() on behalf of core modules.
+ *
+ * @todo Replace all/most of those API functions with direct DB queries;
+ *   we only need the menu arguments (keys), not fully loaded objects.
+ */
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Filter module.
+ */
+function filter_admin_menu_map() {
+  if (!user_access('administer filters')) {
+    return;
+  }
+  $map['admin/config/content/formats/%filter_format'] = array(
+    'parent' => 'admin/config/content/formats',
+    'arguments' => array(
+      array('%filter_format' => array_keys(filter_formats())),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Menu module.
+ */
+function menu_admin_menu_map() {
+  if (!user_access('administer menu')) {
+    return;
+  }
+  $map['admin/structure/menu/manage/%menu'] = array(
+    'parent' => 'admin/structure/menu',
+    'arguments' => array(
+      array('%menu' => array_keys(menu_get_menus())),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Node module.
+ */
+function node_admin_menu_map() {
+  if (!user_access('administer content types')) {
+    return;
+  }
+  $map['admin/structure/types/manage/%node_type'] = array(
+    'parent' => 'admin/structure/types',
+    'arguments' => array(
+      array('%node_type' => array_keys(node_type_get_types())),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Field UI module.
+ */
+function field_ui_admin_menu_map() {
+  $map = array();
+  foreach (entity_get_info() as $obj_type => $info) {
+    foreach ($info['bundles'] as $bundle_name => $bundle_info) {
+      if (isset($bundle_info['admin'])) {
+        $arguments = array();
+        switch ($obj_type) {
+          case 'comment':
+            $fields = array();
+            foreach (field_info_instances($obj_type, $bundle_name) as $field) {
+              $fields[] = $field['field_name'];
+            }
+            // @todo Make Comment module expose the original node type bundle,
+            //   pretty please.
+            if (drupal_substr($bundle_name, 0, 13) == 'comment_node_') {
+              $bundle_name = drupal_substr($bundle_name, 13);
+            }
+            // @todo Doesn't work yet. Why?
+            $arguments = array(
+              '%comment_node_type' => array($bundle_name),
+              '%field_ui_menu' => $fields,
+            );
+            break;
+
+          case 'node':
+            $fields = array();
+            foreach (field_info_instances($obj_type, $bundle_name) as $field) {
+              $fields[] = $field['field_name'];
+            }
+            $arguments = array(
+              '%node_type' => array($bundle_name),
+              '%field_ui_menu' => $fields,
+            );
+            break;
+
+          case 'taxonomy_term':
+            $fields = array();
+            foreach (field_info_instances($obj_type, $bundle_name) as $field) {
+              $fields[] = $field['field_name'];
+            }
+            // Map machine_name to vid.
+            $arguments = array(
+              '%taxonomy_vocabulary_machine_name' => array($bundle_name),
+              '%field_ui_menu' => $fields,
+            );
+            break;
+
+          case 'user':
+            $arguments = array(
+              '%field_ui_menu' => array_keys(field_info_fields('user')),
+            );
+            break;
+        }
+        if (!empty($arguments)) {
+          $path = $bundle_info['admin']['path'];
+          $map["$path/fields/%field_ui_menu"]['parent'] = "$path/fields";
+          $map["$path/fields/%field_ui_menu"]['arguments'][] = $arguments;
+        }
+      }
+    }
+  }
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Taxonomy module.
+ */
+function taxonomy_admin_menu_map() {
+  if (!user_access('administer taxonomy')) {
+    return;
+  }
+  $map['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name'] = array(
+    'parent' => 'admin/structure/taxonomy',
+    'arguments' => array(
+      array('%taxonomy_vocabulary_machine_name' => array_keys(taxonomy_vocabulary_get_names())),
+    ),
+  );
+  return $map;
+}
+
+/**
+ * Implements hook_admin_menu_map() on behalf of Views UI module.
+ */
+function views_ui_admin_menu_map() {
+  if (!user_access('administer views')) {
+    return;
+  }
+  $views = array();
+  foreach (views_get_enabled_views() as $name => $view) {
+    $views[] = $name;
+  }
+  if (empty($views)) {
+    return;
+  }
+  $map['admin/structure/views/view/%views_ui_cache'] = array(
+    'parent' => 'admin/structure/views',
+    'arguments' => array(
+      array('%views_ui_cache' => $views),
+    ),
+  );
+  return $map;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,858 @@
+<?php
+
+/**
+ * @file
+ * Render an administrative menu as a dropdown menu at the top of the window.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function admin_menu_help($path, $arg) {
+  switch ($path) {
+    case 'admin/config/administration/admin_menu':
+      return '<p>' . t('The administration menu module provides a dropdown menu arranged for one- or two-click access to most administrative tasks and other common destinations (to users with the proper permissions). Use the settings below to customize the appearance of the menu.') . '</p>';
+
+    case 'admin/help#admin_menu':
+      $output = '';
+      $output .= '<p>' . t('The administration menu module provides a dropdown menu arranged for one- or two-click access to most administrative tasks and other common destinations (to users with the proper permissions). Administration menu also displays the number of anonymous and authenticated users, and allows modules to add their own custom menu items. Integration with the menu varies from module to module; the contributed module <a href="@drupal">Devel</a>, for instance, makes strong use of the administration menu module to provide quick access to development tools.', array('@drupal' => 'http://drupal.org/project/devel')) . '</p>';
+      $output .= '<p>' . t('The administration menu <a href="@settings">settings page</a> allows you to modify some elements of the menu\'s behavior and appearance. Since the appearance of the menu is dependent on your site theme, substantial customizations require modifications to your site\'s theme and CSS files. See the advanced module README.txt file for more information on theme and CSS customizations.', array('@settings' => url('admin/config/administration/admin_menu'))) . '</p>';
+      $output .= '<p>' . t('The menu items displayed in the administration menu depend upon the actual permissions of the viewer. First, the administration menu is only displayed to users in roles with the <em>Access administration menu</em> (admin_menu module) permission. Second, a user must be a member of a role with the <em>Access administration pages</em> (system module) permission to view administrative links. And, third, only currently permitted links are displayed; for example, if a user is not a member of a role with the permissions <em>Administer permissions</em> (user module) and <em>Administer users</em> (user module), the <em>User management</em> menu item is not displayed.') . '</p>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_permission().
+ */
+function admin_menu_permission() {
+  return array(
+    'access administration menu' => array(
+      'title' => t('Access administration menu'),
+      'description' => t('Display the administration menu at the top of each page.'),
+    ),
+    'flush caches' => array(
+      'title' => t('Flush caches'),
+      'description' => t('Access links to flush caches in the administration menu.'),
+    ),
+    'display drupal links' => array(
+      'title' => t('Display Drupal links'),
+      'description' => t('Provide Drupal.org links in the administration menu.'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_theme().
+ */
+function admin_menu_theme() {
+  return array(
+    'admin_menu_links' => array(
+      'render element' => 'elements',
+    ),
+    'admin_menu_icon' => array(
+      'variables' => array('src' => NULL, 'alt' => NULL),
+      'file' => 'admin_menu.inc',
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function admin_menu_menu() {
+  // AJAX callback.
+  // @see http://drupal.org/project/js
+  $items['js/admin_menu/cache'] = array(
+    'page callback' => 'admin_menu_js_cache',
+    'delivery callback' => 'admin_menu_deliver',
+    'access arguments' => array('access administration menu'),
+    'type' => MENU_CALLBACK,
+  );
+  // Module settings.
+  $items['admin/config/administration'] = array(
+    'title' => 'Administration',
+    'description' => 'Administration tools.',
+    'page callback' => 'system_admin_menu_block_page',
+    'access arguments' => array('access administration pages'),
+    'file' => 'system.admin.inc',
+    'file path' => drupal_get_path('module', 'system'),
+  );
+  $items['admin/config/administration/admin_menu'] = array(
+    'title' => 'Administration menu',
+    'description' => 'Adjust administration menu settings.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('admin_menu_theme_settings'),
+    'access arguments' => array('administer site configuration'),
+    'file' => 'admin_menu.inc',
+  );
+  // Menu link callbacks.
+  $items['admin_menu/toggle-modules'] = array(
+    'page callback' => 'admin_menu_toggle_modules',
+    'access arguments' => array('administer modules'),
+    'type' => MENU_CALLBACK,
+    'file' => 'admin_menu.inc',
+  );
+  $items['admin_menu/flush-cache'] = array(
+    'page callback' => 'admin_menu_flush_cache',
+    'access arguments' => array('flush caches'),
+    'type' => MENU_CALLBACK,
+    'file' => 'admin_menu.inc',
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_menu_alter().
+ */
+function admin_menu_menu_alter(&$items) {
+  // Flush client-side caches whenever the menu is rebuilt.
+  admin_menu_flush_caches();
+}
+
+/**
+ * Implements hook_menu_link_insert().
+ */
+function admin_menu_menu_link_insert($link) {
+  // Flush all of our caches to pick up the link.
+  admin_menu_flush_caches();
+}
+
+/**
+ * Implements hook_menu_link_update().
+ */
+function admin_menu_menu_link_update($link) {
+  // Flush all of our caches to pick up the link.
+  admin_menu_flush_caches();
+}
+
+/**
+ * Implements hook_menu_link_delete().
+ */
+function admin_menu_menu_link_delete($link) {
+  // Flush all of our caches to pick up the link.
+  admin_menu_flush_caches();
+}
+
+/**
+ * Implements hook_system_info_alter().
+ *
+ * Indicate that the 'page_bottom' region (in which the administration menu
+ * is displayed) is an overlay supplemental region that should be refreshed
+ * whenever its content is updated.
+ *
+ * @see toolbar_system_info_alter()
+ */
+function admin_menu_system_info_alter(&$info, $file, $type) {
+  if ($type == 'theme') {
+    $info['overlay_supplemental_regions'][] = 'page_bottom';
+  }
+}
+
+/**
+ * Implements hook_page_build().
+ */
+function admin_menu_page_build(&$page) {
+  if (!user_access('access administration menu') || admin_menu_suppress(FALSE)) {
+    return;
+  }
+  // Performance: Skip this entirely for AJAX requests.
+  if (strpos($_GET['q'], 'js/') === 0) {
+    return;
+  }
+  global $user, $language;
+  $path = drupal_get_path('module', 'admin_menu');
+
+  $page['page_bottom']['admin_menu'] = array(
+    '#attached' => array(),
+  );
+  $attached = &$page['page_bottom']['admin_menu']['#attached'];
+  $options = array('every_page' => TRUE);
+
+  $attached['css'][$path . '/admin_menu.css'] = $options;
+  if ($user->uid == 1) {
+    $attached['css'][$path . '/admin_menu.uid1.css'] = $options;
+  }
+  // Previous versions used the 'defer' attribute to increase browser rendering
+  // performance. At least starting with Firefox 3.6, deferred .js files are
+  // loaded, but Drupal.behaviors are not contained in the DOM when drupal.js
+  // executes Drupal.attachBehaviors().
+  $attached['js'][$path . '/admin_menu.js'] = $options;
+
+  // Destination query strings are applied via JS.
+  $settings['destination'] = drupal_http_build_query(drupal_get_destination());
+
+  // Determine whether we need to show all components and disable all caches.
+  $complete = FALSE;
+  if (current_path() == 'admin/config/administration/admin_menu' && $_SERVER['REQUEST_METHOD'] == 'GET') {
+    $complete = TRUE;
+  }
+
+  // If the client supports JavaScript and we have a cached menu for the current
+  // user, only output the hash for the client-side HTTP cache callback URL.
+  $cid = 'admin_menu:' . $user->uid . ':' . session_id() . ':' . $language->language;
+  if (!$complete && !empty($_COOKIE['has_js']) && ($hash = admin_menu_cache_get($cid))) {
+    $settings['hash'] = $hash;
+    // The base path to use for cache requests depends on whether clean URLs
+    // are enabled, whether Drupal runs in a sub-directory, and on the language
+    // system configuration. url() already provides us the proper path and also
+    // invokes potentially existing custom_url_rewrite() functions, which may
+    // add further required components to the URL to provide context. Due to
+    // those components, and since url('') returns only base_path() when clean
+    // URLs are disabled, we need to use a replacement token as path.  Yuck.
+    $settings['basePath'] = url('admin_menu');
+  }
+  // Otherwise, add the full menu to the page.
+  else {
+    $page['page_bottom']['admin_menu']['#markup'] = admin_menu_output($complete);
+  }
+
+  $replacements = module_invoke_all('admin_menu_replacements', $complete);
+  if (!empty($replacements)) {
+    $settings['replacements'] = $replacements;
+  }
+
+  if ($setting = variable_get('admin_menu_margin_top', 1)) {
+    $settings['margin_top'] = $setting;
+    // @todo Drupal.behaviors.adminMenuMarginTop is obsolete, but
+    //   hook_page_build() does not allow to set a CSS class on the body yet.
+    // @see http://drupal.org/node/1473548, http://drupal.org/node/1194528
+    //$page['#attributes']['class'][] = 'admin-menu';
+  }
+  if ($setting = variable_get('admin_menu_position_fixed', 1)) {
+    $settings['position_fixed'] = $setting;
+
+    // In fixed positioning, supply a callback function for tableheader.js to
+    // allow it to determine the top viewport offset.
+    // @see admin_menu.js, toolbar.js
+    $attached['js'][] = array(
+      'data' => array('tableHeaderOffset' => 'Drupal.admin.height'),
+      'type' => 'setting',
+    );
+  }
+  if ($setting = variable_get('admin_menu_tweak_tabs', 0)) {
+    $settings['tweak_tabs'] = $setting;
+  }
+  if ($_GET['q'] == 'admin/modules' || strpos($_GET['q'], 'admin/modules/list') === 0) {
+    $settings['tweak_modules'] = variable_get('admin_menu_tweak_modules', 0);
+  }
+  if ($_GET['q'] == 'admin/people/permissions' || $_GET['q'] == 'admin/people/permissions/list') {
+    $settings['tweak_permissions'] = variable_get('admin_menu_tweak_permissions', 0);
+  }
+
+  $attached['js'][] = array(
+    'data' => array('admin_menu' => $settings),
+    'type' => 'setting',
+  );
+}
+
+/**
+ * Suppress display of administration menu.
+ *
+ * This function should be called from within another module's page callback
+ * (preferably using module_invoke()) when the menu should not be displayed.
+ * This is useful for modules that implement popup pages or other special
+ * pages where the menu would be distracting or break the layout.
+ *
+ * @param $set
+ *   Defaults to TRUE. If called before hook_footer(), the menu will not be
+ *   displayed. If FALSE is passed, the suppression state is returned.
+ */
+function admin_menu_suppress($set = TRUE) {
+  static $suppress = FALSE;
+  // drupal_add_js() must only be invoked once.
+  if (!empty($set) && $suppress === FALSE) {
+    $suppress = TRUE;
+    drupal_add_js(array('admin_menu' => array('suppress' => 1)), 'setting');
+  }
+  return $suppress;
+}
+
+/**
+ * Implements hook_js().
+ */
+function admin_menu_js() {
+  return array(
+    'cache' => array(
+      'callback' => 'admin_menu_js_cache',
+      'includes' => array('common', 'theme', 'unicode'),
+      'dependencies' => array('devel', 'filter', 'user'),
+    ),
+  );
+}
+
+/**
+ * Retrieve a client-side cache hash from cache.
+ *
+ * The hash cache is consulted more than once per request; we therefore cache
+ * the results statically to avoid multiple database requests.
+ *
+ * This should only be used for client-side cache hashes. Use cache_menu for
+ * administration menu content.
+ *
+ * @param $cid
+ *   The cache ID of the data to retrieve.
+ */
+function admin_menu_cache_get($cid) {
+  $cache = &drupal_static(__FUNCTION__, array());
+
+  if (!variable_get('admin_menu_cache_client', TRUE)) {
+    return FALSE;
+  }
+  if (!array_key_exists($cid, $cache)) {
+    $cache[$cid] = cache_get($cid, 'cache_admin_menu');
+    if ($cache[$cid] && isset($cache[$cid]->data)) {
+      $cache[$cid] = $cache[$cid]->data;
+    }
+  }
+
+  return $cache[$cid];
+}
+
+/**
+ * Store a client-side cache hash in persistent cache.
+ *
+ * This should only be used for client-side cache hashes. Use cache_menu for
+ * administration menu content.
+ *
+ * @param $cid
+ *   The cache ID of the data to retrieve.
+ */
+function admin_menu_cache_set($cid, $data) {
+  if (variable_get('admin_menu_cache_client', TRUE)) {
+    cache_set($cid, $data, 'cache_admin_menu');
+  }
+}
+
+/**
+ * Menu callback; Output administration menu for HTTP caching via AJAX request.
+ *
+ * @see admin_menu_deliver()
+ */
+function admin_menu_js_cache() {
+  global $conf;
+
+  // Suppress Devel module.
+  $GLOBALS['devel_shutdown'] = FALSE;
+
+  // Enforce page caching.
+  $conf['cache'] = 1;
+  drupal_page_is_cacheable(TRUE);
+
+  // If we have a cache, serve it.
+  // @see _drupal_bootstrap_page_cache()
+  $cache = drupal_page_get_cache();
+  if (is_object($cache)) {
+    header('X-Drupal-Cache: HIT');
+    // Restore the metadata cached with the page.
+    $_GET['q'] = $cache->data['path'];
+    date_default_timezone_set(drupal_get_user_timezone());
+
+    drupal_serve_page_from_cache($cache);
+
+    // We are done.
+    exit;
+  }
+
+  // Otherwise, create a new page response (that will be cached).
+  header('X-Drupal-Cache: MISS');
+
+  // The Expires HTTP header is the heart of the client-side HTTP caching. The
+  // additional server-side page cache only takes effect when the client
+  // accesses the callback URL again (e.g., after clearing the browser cache or
+  // when force-reloading a Drupal page).
+  $max_age = 3600 * 24 * 365;
+  drupal_add_http_header('Expires', gmdate(DATE_RFC1123, REQUEST_TIME + $max_age));
+  drupal_add_http_header('Cache-Control', 'private, max-age=' . $max_age);
+
+  // Retrieve and return the rendered menu.
+  return admin_menu_output();
+}
+
+/**
+ * Delivery callback for client-side HTTP caching.
+ *
+ * @see admin_menu_js_cache()
+ */
+function admin_menu_deliver($page_callback_result) {
+  drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
+
+  // Send appropriate language header for browsers.
+  global $language;
+  drupal_add_http_header('Content-Language', $language->language);
+
+  // The page callback is always admin_menu_js_cache(), which always returns a
+  // string, and is only accessed when the user actually has access to it.
+  // Therefore, we do not care for the other possible page callback results.
+  print $page_callback_result;
+
+  // Perform end-of-request tasks. The page cache is created here.
+  drupal_page_footer();
+}
+
+/**
+ * Implements hook_admin_menu_replacements().
+ */
+function admin_menu_admin_menu_replacements($complete) {
+  $items = array();
+  // If the complete menu is output, then it is uncached and will contain the
+  // current counts already.
+  if (!$complete) {
+    // Check whether the users count component is enabled.
+    $components = variable_get('admin_menu_components', array());
+    if (!empty($components['admin_menu.users']) && ($user_count = admin_menu_get_user_count())) {
+      // Replace the counters in the cached menu output with current counts.
+      $items['.admin-menu-users a'] = $user_count;
+    }
+  }
+  return $items;
+}
+
+/**
+ * Return count of online anonymous/authenticated users.
+ *
+ * @see user_block(), user.module
+ */
+function admin_menu_get_user_count() {
+  $interval   = REQUEST_TIME - variable_get('user_block_seconds_online', 900);
+  $count_anon = admin_menu_session_count($interval, TRUE);
+  $count_auth = admin_menu_session_count($interval, FALSE);
+
+  return t('@count-anon / @count-auth', array('@count-anon' => $count_anon, '@count-auth' => $count_auth));
+}
+
+/**
+ * Counts how many users are active on the site.
+ *
+ * Counts how many users have sessions which have been active since the
+ * specified time. Can count either anonymous sessions or authenticated
+ * sessions.
+ *
+ * @param $timestamp
+ *   A Unix timestamp. Users who have been active since this time will be
+ *   counted. The default is 0, which counts all existing sessions.
+ * @param $anonymous
+ *   TRUE counts only anonymous users. FALSE counts only authenticated users.
+ *
+ * @return
+ *   The number of users with sessions.
+ *
+ * @todo There are mostly no anonymous sessions anymore. Split this into a
+ *   separate module providing proper user statistics.
+ */
+function admin_menu_session_count($timestamp = 0, $anonymous = TRUE) {
+  $query = db_select('sessions');
+  $query->addExpression('COUNT(sid)', 'count');
+  $query->condition('timestamp', $timestamp, '>=');
+  $query->condition('uid', 0, $anonymous ? '=' : '>');
+  return $query->execute()->fetchField();
+}
+
+/**
+ * Build the administration menu output.
+ *
+ * @param bool $complete
+ *   (optional) Whether to build to the complete menu including all components
+ *   and ignore the cache. Defaults to FALSE. Internally used for the settings
+ *   page.
+ */
+function admin_menu_output($complete = FALSE) {
+  global $user, $language;
+
+  $cache_server_enabled = !$complete && variable_get('admin_menu_cache_server', TRUE);
+  $cid = 'admin_menu:' . $user->uid . ':' . session_id() . ':' . $language->language;
+
+  // Try to load and output administration menu from server-side cache.
+  // @todo Duplicates the page cache? Page cache ID contains the hash that is
+  //   generated at the bottom of this function, which is based on $content,
+  //   but logically identical to the $cid. Investigate whether not only the
+  //   cache_menu but also the cache_admin_menu could be dropped; the
+  //   client-side HTTP cache hash check could be based on a cid lookup in
+  //   cache_page instead? (i.e., one cache to rule them all) However,
+  //   cache_page is cleared very often.
+  if ($cache_server_enabled) {
+    $cache = cache_get($cid, 'cache_menu');
+    if ($cache && isset($cache->data)) {
+      $content = $cache->data;
+    }
+  }
+
+  // Rebuild the output.
+  if (!isset($content)) {
+    // Retrieve enabled components to display and make them available for others.
+    $components = variable_get('admin_menu_components', array());
+    $components += array(
+      'admin_menu.menu' => TRUE,
+      'admin_menu.icon' => TRUE,
+      'admin_menu.account' => TRUE,
+    );
+    $content['#components'] = $components;
+    $content['#complete'] = $complete;
+
+    // Add site name as CSS class for development/staging theming purposes. We
+    // leverage the cookie domain instead of HTTP_HOST to account for many (but
+    // not all) multi-domain setups (e.g. language-based sub-domains).
+    $classes = 'admin-menu-site' . drupal_strtolower(preg_replace('/[^a-zA-Z0-9-]/', '-', $GLOBALS['cookie_domain']));
+    // Displace overlay.
+    // @see Drupal.overlay.create
+    // @see toolbar_preprocess_toolbar()
+    if (module_exists('overlay')) {
+      $classes .= ' overlay-displace-top';
+    }
+    // @todo Always output container to harden JS-less support.
+    $content['#prefix'] = '<div id="admin-menu" class="' . $classes . '"><div id="admin-menu-wrapper">';
+    $content['#suffix'] = '</div></div>';
+
+    // Load menu builder functions.
+    module_load_include('inc', 'admin_menu');
+
+    // @todo Move the below callbacks into hook_admin_menu_build()
+    //   implementations (and $module.admin_menu.inc).
+
+    // Add administration menu.
+    if (!empty($components['admin_menu.menu']) || $complete) {
+      $content['menu'] = admin_menu_links_menu(admin_menu_tree('management'));
+      $content['menu']['#theme'] = 'admin_menu_links';
+      $content['menu']['#wrapper_attributes']['id'] = 'admin-menu-menu';
+      // Ensure the menu tree is rendered between the icon and user links.
+      $content['menu']['#weight'] = 0;
+    }
+
+    // Add menu additions.
+    if (!empty($components['admin_menu.icon']) || $complete) {
+      $content['icon'] = admin_menu_links_icon();
+    }
+    if (!empty($components['admin_menu.account']) || $complete) {
+      $content['account'] = admin_menu_links_account();
+    }
+    if (!empty($components['admin_menu.users']) || $complete) {
+      $content['users'] = admin_menu_links_users();
+    }
+    if (!empty($components['admin_menu.search']) || $complete) {
+      $content['search'] = admin_menu_links_search();
+    }
+
+    // Allow modules to enhance the menu.
+    // Uses '_output' suffix for consistency with the alter hook (see below).
+    foreach (module_implements('admin_menu_output_build') as $module) {
+      $function = $module . '_admin_menu_output_build';
+      $function($content);
+    }
+
+    // Allow modules to alter the output.
+    // The '_output' suffix is required to prevent hook implementation function
+    // name clashes with the contributed Admin module.
+    drupal_alter('admin_menu_output', $content);
+
+    $content = drupal_render($content);
+
+    // Cache the menu for this user.
+    if ($cache_server_enabled) {
+      cache_set($cid, $content, 'cache_menu');
+    }
+  }
+
+  // Store the new hash for this user.
+  if (!empty($_COOKIE['has_js']) && !$complete) {
+    admin_menu_cache_set($cid, md5($content));
+  }
+
+  return $content;
+}
+
+/**
+ * Implements hook_admin_menu_output_build().
+ */
+function admin_menu_admin_menu_output_build(&$content) {
+  if (!isset($content['menu'])) {
+    return;
+  }
+
+  // Unassign weights for categories below Configuration.
+  // An alphabetical order is more natural for a dropdown menu.
+  if (isset($content['menu']['admin/config'])) {
+    foreach (element_children($content['menu']['admin/config']) as $key) {
+      $content['menu']['admin/config'][$key]['#weight_original'] = $content['menu']['admin/config'][$key]['#weight'];
+      unset($content['menu']['admin/config'][$key]['#weight']);
+    }
+  }
+
+  // Retrieve the "Add content" link tree.
+  $link = db_query("SELECT * FROM {menu_links} WHERE router_path = 'node/add' AND module = 'system'")->fetchAssoc();
+  $conditions = array();
+  for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
+    if (!empty($link["p$i"])) {
+      $conditions["p$i"] = $link["p$i"];
+    }
+  }
+  $tree = menu_build_tree($link['menu_name'], array(
+    'conditions' => $conditions,
+    'min_depth' => $link['depth'],
+  ));
+  $links = admin_menu_links_menu($tree);
+  if (!empty($links)) {
+    // If the user has access to the top-level "Content" category, insert the
+    // "Add content" link tree there.
+    if (isset($content['menu']['admin/content'])) {
+      $content['menu']['admin/content'] += $links;
+    }
+    // Otherwise make insert "Add content" as top-level category.
+    else {
+      $key = key($links);
+      $links[$key]['#weight'] = -100;
+      $content['menu'] += $links;
+    }
+  }
+}
+
+/**
+ * Implements hook_admin_menu_output_alter().
+ */
+function admin_menu_admin_menu_output_alter(&$content) {
+  foreach ($content['menu'] as $key => $link) {
+    // Move local tasks on 'admin' into icon menu.
+    if ($key == 'admin/tasks' || $key == 'admin/index') {
+      $content['icon']['icon'][$key] = $link;
+      unset($content['menu'][$key]);
+    }
+  }
+}
+
+/**
+ * Render a themed list of links.
+ *
+ * @param $variables
+ *   - elements: A renderable array of links using the following keys:
+ *     - #attributes: Optional array of attributes for the list item, processed
+ *       via drupal_attributes().
+ *     - #title: Title of the link, passed to l().
+ *     - #href: Optional path of the link, passed to l(). When omitted, the
+ *       element's '#title' is rendered without link.
+ *     - #description: Optional alternative text for the link, passed to l().
+ *     - #options: Optional alternative text for the link, passed to l().
+ *     The array key of each child element itself is passed as path for l().
+ */
+function theme_admin_menu_links($variables) {
+  $destination = &drupal_static('admin_menu_destination');
+  $elements = $variables['elements'];
+
+  if (!isset($destination)) {
+    $destination = drupal_get_destination();
+    $destination = $destination['destination'];
+  }
+
+  // The majority of items in the menu are sorted already, but since modules
+  // may add or change arbitrary items anywhere, there is no way around sorting
+  // everything again. element_sort() is not sufficient here, as it
+  // intentionally retains the order of elements having the same #weight,
+  // whereas menu links are supposed to be ordered by #weight and #title.
+  uasort($elements, 'admin_menu_element_sort');
+  $elements['#sorted'] = TRUE;
+
+  $output = '';
+  foreach (element_children($elements) as $path) {
+    // Early-return nothing if user does not have access.
+    if (isset($elements[$path]['#access']) && !$elements[$path]['#access']) {
+      continue;
+    }
+    $elements[$path] += array(
+      '#attributes' => array(),
+      '#options' => array(),
+    );
+    // Render children to determine whether this link is expandable.
+    if (isset($elements[$path]['#type']) || isset($elements[$path]['#theme']) || isset($elements[$path]['#pre_render'])) {
+      $elements[$path]['#children'] = drupal_render($elements[$path]);
+    }
+    else {
+      $elements[$path]['#children'] = theme('admin_menu_links', array('elements' => $elements[$path]));
+      if (!empty($elements[$path]['#children'])) {
+        $elements[$path]['#attributes']['class'][] = 'expandable';
+      }
+      if (isset($elements[$path]['#attributes']['class'])) {
+        $elements[$path]['#attributes']['class'] = $elements[$path]['#attributes']['class'];
+      }
+    }
+
+    $link = '';
+    // Handle menu links.
+    if (isset($elements[$path]['#href'])) {
+      // Strip destination query string from href attribute and apply a CSS class
+      // for our JavaScript behavior instead.
+      if (isset($elements[$path]['#options']['query']['destination']) && $elements[$path]['#options']['query']['destination'] == $destination) {
+        unset($elements[$path]['#options']['query']['destination']);
+        $elements[$path]['#options']['attributes']['class'][] = 'admin-menu-destination';
+      }
+
+      $link = l($elements[$path]['#title'], $elements[$path]['#href'], $elements[$path]['#options']);
+    }
+    // Handle plain text items, but do not interfere with menu additions.
+    elseif (!isset($elements[$path]['#type']) && isset($elements[$path]['#title'])) {
+      if (!empty($elements[$path]['#options']['html'])) {
+        $title = $elements[$path]['#title'];
+      }
+      else {
+        $title = check_plain($elements[$path]['#title']);
+      }
+      $attributes = '';
+      if (isset($elements[$path]['#options']['attributes'])) {
+        $attributes = drupal_attributes($elements[$path]['#options']['attributes']);
+      }
+      $link = '<span' . $attributes . '>' . $title . '</span>';
+    }
+
+    $output .= '<li' . drupal_attributes($elements[$path]['#attributes']) . '>';
+    $output .= $link . $elements[$path]['#children'];
+    $output .= '</li>';
+  }
+  // @todo #attributes probably required for UL, but already used for LI.
+  // @todo Use $element['#children'] here instead.
+  if ($output) {
+    $elements['#wrapper_attributes']['class'][] = 'dropdown';
+    $attributes = drupal_attributes($elements['#wrapper_attributes']);
+    $output = "\n" . '<ul' . $attributes . '>' . $output . '</ul>';
+  }
+  return $output;
+}
+
+/**
+ * Function used by uasort to sort structured arrays by #weight AND #title.
+ */
+function admin_menu_element_sort($a, $b) {
+  // @see element_sort()
+  $a_weight = isset($a['#weight']) ? $a['#weight'] : 0;
+  $b_weight = isset($b['#weight']) ? $b['#weight'] : 0;
+  if ($a_weight == $b_weight) {
+    // @see element_sort_by_title()
+    $a_title = isset($a['#title']) ? $a['#title'] : '';
+    $b_title = isset($b['#title']) ? $b['#title'] : '';
+    return strnatcasecmp($a_title, $b_title);
+  }
+  return ($a_weight < $b_weight) ? -1 : 1;
+}
+
+/**
+ * Implements hook_translated_menu_link_alter().
+ *
+ * Here is where we make changes to links that need dynamic information such
+ * as the current page path or the number of users.
+ */
+function admin_menu_translated_menu_link_alter(&$item, $map) {
+  global $user, $base_url;
+  static $access_all;
+
+  if ($item['menu_name'] != 'admin_menu') {
+    return;
+  }
+
+  // Check whether additional development output is enabled.
+  if (!isset($access_all)) {
+    $access_all = variable_get('admin_menu_show_all', 0) && module_exists('devel');
+  }
+  // Prepare links that would not be displayed normally.
+  if ($access_all && !$item['access']) {
+    $item['access'] = TRUE;
+    // Prepare for http://drupal.org/node/266596
+    if (!isset($item['localized_options'])) {
+      _menu_item_localize($item, $map, TRUE);
+    }
+  }
+
+  // Don't waste cycles altering items that are not visible
+  if (!$item['access']) {
+    return;
+  }
+
+  // Add developer information to all links, if enabled.
+  if ($extra = variable_get('admin_menu_display', 0)) {
+    $item['title'] .= ' ' . $extra[0] . ': ' . $item[$extra];
+  }
+}
+
+/**
+ * Implements hook_flush_caches().
+ *
+ * Flushes client-side caches.
+ *
+ * @param int $uid
+ *   (optional) A user ID to limit the cache flush to.
+ */
+function admin_menu_flush_caches($uid = NULL) {
+  // A call to menu_rebuild() will trigger potentially thousands of calls into
+  // menu_link_save(), for which admin_menu has to implement the corresponding
+  // CRUD hooks, in order to take up any menu link changes, since any menu link
+  // change could affect the admin menu (which essentially is an aggregate) and
+  // since there is no other way to get notified about stale caches. The cache
+  // only needs to be flushed once though, so we prevent a ton of needless
+  // subsequent calls with this static.
+  // @see http://drupal.org/node/918538
+  $was_flushed = &drupal_static(__FUNCTION__, array());
+  // $uid can be NULL. PHP automatically converts that into '' (empty string),
+  // which is different to uid 0 (zero).
+  if (isset($was_flushed[$uid])) {
+    return;
+  }
+  $was_flushed[$uid] = TRUE;
+
+  $cid = 'admin_menu:';
+  if (isset($uid)) {
+    $cid .= $uid . ':';
+  }
+  // Flush cached output of admin_menu.
+  cache_clear_all($cid, 'cache_menu', TRUE);
+  // Flush client-side cache hashes.
+  drupal_static_reset('admin_menu_cache_get');
+  // db_table_exists() required for SimpleTest.
+  if (db_table_exists('cache_admin_menu')) {
+    cache_clear_all(isset($uid) ? $cid : '*', 'cache_admin_menu', TRUE);
+  }
+}
+
+/**
+ * Implements hook_form_alter().
+ */
+function admin_menu_form_alter(&$form, &$form_state, $form_id) {
+  $global_flush_ids = array(
+    'admin_menu_theme_settings' => 1,
+    // Update links for clean/non-clean URLs.
+    'system_clean_url_settings' => 1,
+    // Incorporate changed user permissions.
+    'user_admin_permissions' => 1,
+    // Removing a role potentially means less permissions.
+    'user_admin_role_delete_confirm' => 1,
+    // User name and roles may be changed on the user account form.
+    'user_profile_form' => 1,
+  );
+  if (isset($global_flush_ids[$form_id])) {
+    $form['#submit'][] = 'admin_menu_form_alter_flush_cache_submit';
+
+    // Optionally limit the cache flush to a certain user ID.
+    $form_state['admin_menu_uid'] = NULL;
+    if ($form_id == 'user_profile_form') {
+      $form_state['admin_menu_uid'] = $form_state['user']->uid;
+    }
+  }
+
+  // UX: Add a confirmation to the permissions form to ask the user whether to
+  // auto-enable the 'access administration menu' permission along with
+  // 'access administration pages'.
+  if ($form_id == 'user_admin_permissions') {
+    $form['#attached']['js'][] = drupal_get_path('module', 'admin_menu') . '/admin_menu.admin.js';
+  }
+}
+
+/**
+ * Form submission handler to flush Administration menu caches.
+ */
+function admin_menu_form_alter_flush_cache_submit($form, &$form_state) {
+  admin_menu_flush_caches($form_state['admin_menu_uid']);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ *
+ * Extends Devel module with Administration menu developer settings.
+ */
+function admin_menu_form_devel_admin_settings_alter(&$form, &$form_state) {
+  form_load_include($form_state, 'inc', 'admin_menu');
+  _admin_menu_form_devel_admin_settings_alter($form, $form_state);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu.uid1.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,9 @@
+
+/**
+ * @file
+ * Administration menu color override for uid1.
+ */
+
+#admin-menu li.admin-menu-account > a {
+  background: #911 url(images/bkg-red.png) bottom left repeat-x;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,145 @@
+
+/**
+ * @file
+ * Toolbar style for Administration menu.
+ *
+ * Important: We cannot re-use toolbar.png from Toolbar module, since we cannot
+ * reliably determine the path to it.
+ *
+ * @todo Separate shortcut functionality into own module/widget.
+ */
+
+/* Adjust margin/height */
+html body.admin-menu {
+  margin-top: 29px !important;
+}
+html body.admin-menu-with-shortcuts {
+  margin-top: 65px !important;
+}
+/* Displace the core Toolbar, if concurrently output. */
+body div#toolbar.toolbar {
+  top: 30px;
+}
+
+/**
+ * Base styles.
+ *
+ * We use a keyword for the toolbar font size to make it display consistently
+ * across different themes, while still allowing browsers to resize the text.
+ */
+#admin-menu {
+  font: normal small "Lucida Grande", Verdana, sans-serif;
+  -moz-box-shadow: 0 -10px 20px 13px #000;
+  -webkit-box-shadow: 0 -10px 20px 13px #000;
+  box-shadow: 0 -10px 20px 13px #000;
+  right: 0;
+  width: auto;
+}
+#admin-menu-wrapper {
+  font-size: .846em;
+  padding: 5px 10px 0;
+}
+
+#admin-menu .dropdown a {
+  color: #fafafa;
+}
+
+/* Remove border from all lists and actions */
+#admin-menu .dropdown .admin-menu-action a {
+  border-left: 0;
+}
+#admin-menu .dropdown .admin-menu-icon > a {
+  padding: 2px 10px 3px;
+}
+
+/**
+ * Administration menu.
+ */
+#admin-menu .dropdown .admin-menu-icon > a span {
+  vertical-align: text-bottom;
+  width: 11px;
+  height: 14px;
+  display: block;
+  background: url(toolbar.png) no-repeat 0 -45px;
+  text-indent: -9999px;
+}
+#admin-menu > div > .dropdown > li > a {
+  border-right: 0;
+  margin-bottom: 4px;
+  padding: 2px 10px 3px;
+}
+#admin-menu .dropdown .admin-menu-toolbar-category > a,
+#admin-menu .dropdown .admin-menu-action > a {
+  border-radius: 10px;
+  -moz-border-radius: 10px;
+  -webkit-border-radius: 10px;
+}
+#admin-menu .dropdown .admin-menu-toolbar-category > a.active-trail {
+  text-shadow: #333 0 1px 0;
+  background: url(toolbar.png) 0 0 repeat-x;
+}
+#admin-menu .dropdown .admin-menu-toolbar-category > a:hover {
+  background-color: #444;
+}
+#admin-menu .dropdown .admin-menu-tab a {
+  border-right: 0;
+}
+#admin-menu .dropdown li li.expandable ul {
+  margin: -22px 0 0 160px;
+}
+
+/**
+ * Shortcuts toggle.
+ */
+#admin-menu .shortcut-toggle {
+  cursor: pointer;
+  background: url(toolbar.png) 0 -20px no-repeat;
+  display: block;
+  float: right;
+  margin: 0 0 0 1.3em;
+  text-indent: -9999px;
+  overflow: hidden;
+  width: 25px;
+  height: 25px;
+}
+#admin-menu .shortcut-toggle:focus,
+#admin-menu .shortcut-toggle:hover {
+  background-position: -50px -20px;
+}
+#admin-menu .shortcut-toggle.active {
+  background-position: -25px -20px;
+}
+#admin-menu .shortcut-toggle.active:focus,
+#admin-menu .shortcut-toggle.active:hover {
+  background-position: -75px -20px;
+}
+
+/**
+ * Shortcuts widget.
+ */
+#admin-menu .shortcut-toolbar {
+  background-color: #666;
+  clear: both;
+  display: none;
+  margin: 0 -10px;
+  overflow: hidden;
+  /* Align with icon; @see shortcut.css */
+  padding-left: 5px;
+}
+#admin-menu .shortcut-toolbar.active {
+  display: block;
+}
+/* Override theme list style; @see shortcut.css */
+#admin-menu .shortcut-toolbar ul {
+  margin: 0;
+}
+/* @see toolbar.css */
+#admin-menu .shortcut-toolbar li {
+  float: left;
+  list-style-image: none;
+  list-style-type: none;
+}
+#admin-menu .shortcut-toolbar a {
+  display: block;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+name = Administration menu Toolbar style
+description = A better Toolbar.
+package = Administration
+core = 7.x
+dependencies[] = admin_menu
+
+; Information added by drupal.org packaging script on 2013-01-31
+version = "7.x-3.0-rc4"
+core = "7.x"
+project = "admin_menu"
+datestamp = "1359651687"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Installation functionality for Administration menu toolbar module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function admin_menu_toolbar_install() {
+  // Required to load JS/CSS in hook_init() after admin_menu.
+  db_update('system')
+    ->fields(array('weight' => 101))
+    ->condition('type', 'module')
+    ->condition('name', 'admin_menu_toolbar')
+    ->execute();
+}
+
+/**
+ * Set module weight to a value higher than admin_menu.
+ *
+ * At this point, admin_menu should have a weight of 100. To account for
+ * customized weights, we increase the weight relatively.
+ *
+ * @see admin_menu_toolbar_install()
+ */
+function admin_menu_toolbar_update_6300() {
+  $weight = db_query("SELECT weight FROM {system} WHERE type = 'module' AND name = 'admin_menu'")->fetchField();
+  $weight++;
+  db_update('system')
+    ->fields(array('weight' => $weight))
+    ->condition('type', 'module')
+    ->condition('name', 'admin_menu_toolbar')
+    ->execute();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,56 @@
+(function($) {
+
+Drupal.admin = Drupal.admin || {};
+Drupal.admin.behaviors = Drupal.admin.behaviors || {};
+
+/**
+ * @ingroup admin_behaviors
+ * @{
+ */
+
+/**
+ * Apply active trail highlighting based on current path.
+ *
+ * @todo Not limited to toolbar; move into core?
+ */
+Drupal.admin.behaviors.toolbarActiveTrail = function (context, settings, $adminMenu) {
+  if (settings.admin_menu.toolbar && settings.admin_menu.toolbar.activeTrail) {
+    $adminMenu.find('> div > ul > li > a[href="' + settings.admin_menu.toolbar.activeTrail + '"]').addClass('active-trail');
+  }
+};
+
+/**
+ * Toggles the shortcuts bar.
+ */
+Drupal.admin.behaviors.shortcutToggle = function (context, settings, $adminMenu) {
+  var $shortcuts = $adminMenu.find('.shortcut-toolbar');
+  if (!$shortcuts.length) {
+    return;
+  }
+  var storage = window.localStorage || false;
+  var storageKey = 'Drupal.admin_menu.shortcut';
+  var $body = $(context).find('body');
+  var $toggle = $adminMenu.find('.shortcut-toggle');
+  $toggle.click(function () {
+    var enable = !$shortcuts.hasClass('active');
+    $shortcuts.toggleClass('active', enable);
+    $toggle.toggleClass('active', enable);
+    if (settings.admin_menu.margin_top) {
+      $body.toggleClass('admin-menu-with-shortcuts', enable);
+    }
+    // Persist toggle state across requests.
+    storage && enable ? storage.setItem(storageKey, 1) : storage.removeItem(storageKey);
+    this.blur();
+    return false;
+  });
+
+  if (!storage || storage.getItem(storageKey)) {
+    $toggle.trigger('click');
+  }
+};
+
+/**
+ * @} End of "ingroup admin_behaviors".
+ */
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/admin_menu_toolbar/admin_menu_toolbar.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Renders Administration menu like Toolbar (core) module.
+ *
+ * @todo Separate shortcut functionality into own module/widget.
+ */
+
+/**
+ * Implements hook_form_FORMID_alter().
+ */
+function admin_menu_toolbar_form_admin_menu_theme_settings_alter(&$form) {
+  // Add the shortcut links as component on behalf of Shortcut module.
+  $form['plugins']['admin_menu_components']['#options']['shortcut.links'] = t('Shortcuts');
+  // The shortcut bar consists of two elements, so we target their class names
+  // instead of cluttering the markup with additional IDs.
+  $form['plugins']['admin_menu_components']['shortcut.links']['#attributes']['rel'] = '.shortcut-toggle, .shortcut-toolbar';
+}
+
+/**
+ * Implementation of hook_page_build().
+ */
+function admin_menu_toolbar_page_build(&$page) {
+  if (!isset($page['page_bottom']['admin_menu'])) {
+    return;
+  }
+  $path = drupal_get_path('module', 'admin_menu_toolbar');
+  $attached = &$page['page_bottom']['admin_menu']['#attached'];
+  $options = array('every_page' => TRUE);
+
+  $attached['css'][$path . '/admin_menu_toolbar.css'] = $options;
+  $attached['js'][$path . '/admin_menu_toolbar.js'] = $options;
+
+  // @todo Stop-gap fix until cached rendering is resolved.
+  // @see http://drupal.org/node/1567622
+  if (module_exists('shortcut')) {
+    $attached['css'][drupal_get_path('module', 'shortcut') . '/shortcut.css'] = $options;
+  }
+
+  $settings = array();
+  // Add current path to support menu item highlighting.
+  // @todo Compile real active trail here?
+  $args = explode('/', $_GET['q']);
+  if ($args[0] == 'admin' && !empty($args[1])) {
+    $settings['activeTrail'] = url($args[0] . '/' . $args[1]);
+  }
+  elseif (drupal_is_front_page()) {
+    $settings['activeTrail'] = url('<front>');
+  }
+
+  $attached['js'][] = array(
+    'data' => array('admin_menu' => array('toolbar' => $settings)),
+    'type' => 'setting',
+  );
+}
+
+/**
+ * Implements hook_admin_menu_output_build().
+ */
+function admin_menu_toolbar_admin_menu_output_build(&$content) {
+  if (empty($content['#components']['shortcut.links']) && !$content['#complete']) {
+    return;
+  }
+  // Add shortcuts toggle.
+  $content['shortcut-toggle'] = array(
+    '#access' => module_exists('shortcut'),
+    '#weight' => -200,
+    '#type' => 'link',
+    '#title' => t('Show shortcuts'),
+    '#href' => '',
+    '#options' => array(
+      'attributes' => array('class' => 'shortcut-toggle'),
+    ),
+  );
+
+  // Add shortcuts bar.
+  $content['shortcut'] = array(
+    '#access' => module_exists('shortcut'),
+    '#weight' => 200,
+    '#prefix' => '<div class="shortcut-toolbar">',
+    '#suffix' => '</div>',
+  );
+  $content['shortcut']['shortcuts'] = array(
+    // Shortcut module's CSS relies on Toolbar module's markup.
+    // @see http://drupal.org/node/1217038
+    '#prefix' => '<div id="toolbar">',
+    '#suffix' => '</div>',
+    // @todo Links may contain .active-trail classes.
+    '#pre_render' => array('shortcut_toolbar_pre_render'),
+  );
+}
+
+/**
+ * Implements hook_admin_menu_output_alter().
+ */
+function admin_menu_toolbar_admin_menu_output_alter(&$content) {
+  // Add a class to top-level items for styling.
+  if (isset($content['menu'])) {
+    foreach (element_children($content['menu']) as $link) {
+      $content['menu'][$link]['#attributes']['class'][] = 'admin-menu-toolbar-category';
+    }
+  }
+
+  // Alter icon.
+  if (isset($content['icon'])) {
+    unset($content['icon']['icon']['#theme']);
+    $content['icon']['icon']['#title'] = '<span>' . t('Home') . '</span>';
+    $content['icon']['icon']['#attributes']['class'][] = 'admin-menu-toolbar-category';
+  }
+
+  // Alter user account link.
+  if (isset($content['account'])) {
+    $content['account']['account']['#title'] = t('Hello <strong>@username</strong>', array('@username' => $content['account']['account']['#title']));
+    $content['account']['account']['#options']['html'] = TRUE;
+  }
+}
+
Binary file sites/all/modules/admin_menu/admin_menu_toolbar/toolbar.png has changed
Binary file sites/all/modules/admin_menu/images/arrow-rtl.png has changed
Binary file sites/all/modules/admin_menu/images/arrow.png has changed
Binary file sites/all/modules/admin_menu/images/bkg-red.png has changed
Binary file sites/all/modules/admin_menu/images/bkg.png has changed
Binary file sites/all/modules/admin_menu/images/bkg_tab.png has changed
Binary file sites/all/modules/admin_menu/images/icon_users.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/admin_menu/tests/admin_menu.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,520 @@
+<?php
+
+/**
+ * @file
+ * Tests for the Administration menu module.
+ */
+
+/**
+ * Base class for all administration menu web test cases.
+ */
+class AdminMenuWebTestCase extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  protected $basePermissions = array(
+    'system' => 'access administration pages',
+    'admin_menu' => 'access administration menu',
+  );
+
+  function setUp() {
+    // Enable admin menu module and any other modules.
+    $modules = func_get_args();
+    $modules = isset($modules[0]) ? $modules[0] : $modules;
+    $modules[] = 'admin_menu';
+    parent::setUp($modules);
+
+    // Disable client-side caching.
+    variable_set('admin_menu_cache_client', FALSE);
+    // Disable Clean URLs to ensure drupal.org testbot compatibility.
+    variable_set('clean_url', 0);
+  }
+
+  /**
+   * Check that an element exists in HTML markup.
+   *
+   * @param $xpath
+   *   An XPath expression.
+   * @param array $arguments
+   *   (optional) An associative array of XPath replacement tokens to pass to
+   *   DrupalWebTestCase::buildXPathQuery().
+   * @param $message
+   *   The message to display along with the assertion.
+   * @param $group
+   *   The type of assertion - examples are "Browser", "PHP".
+   *
+   * @return
+   *   TRUE if the assertion succeeded, FALSE otherwise.
+   */
+  protected function assertElementByXPath($xpath, array $arguments = array(), $message, $group = 'Other') {
+    $elements = $this->xpath($xpath, $arguments);
+    return $this->assertTrue(!empty($elements[0]), $message, $group);
+  }
+
+  /**
+   * Check that an element does not exist in HTML markup.
+   *
+   * @param $xpath
+   *   An XPath expression.
+   * @param array $arguments
+   *   (optional) An associative array of XPath replacement tokens to pass to
+   *   DrupalWebTestCase::buildXPathQuery().
+   * @param $message
+   *   The message to display along with the assertion.
+   * @param $group
+   *   The type of assertion - examples are "Browser", "PHP".
+   *
+   * @return
+   *   TRUE if the assertion succeeded, FALSE otherwise.
+   */
+  protected function assertNoElementByXPath($xpath, array $arguments = array(), $message, $group = 'Other') {
+    $elements = $this->xpath($xpath, $arguments);
+    return $this->assertTrue(empty($elements), $message, $group);
+  }
+
+  /**
+   * Asserts that links appear in the menu in a specified trail.
+   *
+   * @param array $trail
+   *   A list of menu link titles to assert in the menu.
+   */
+  protected function assertLinkTrailByTitle(array $trail) {
+    $xpath = array();
+    $args = array();
+    $message = '';
+    foreach ($trail as $i => $title) {
+      $xpath[] = '/li/a[text()=:title' . $i . ']';
+      $args[':title' . $i] = $title;
+      $message .= ($i ? ' » ' : '') . check_plain($title);
+    }
+    $xpath = '//div[@id="admin-menu"]/div/ul' . implode('/parent::li/ul', $xpath);
+    $this->assertElementByXPath($xpath, $args, $message . ' link found.');
+  }
+
+  /**
+   * Asserts that no link appears in the menu for a specified trail.
+   *
+   * @param array $trail
+   *   A list of menu link titles to assert in the menu.
+   */
+  protected function assertNoLinkTrailByTitle(array $trail) {
+    $xpath = array();
+    $args = array();
+    $message = '';
+    foreach ($trail as $i => $title) {
+      $xpath[] = '/li/a[text()=:title' . $i . ']';
+      $args[':title' . $i] = $title;
+      $message .= ($i ? ' » ' : '') . check_plain($title);
+    }
+    $xpath = '//div[@id="admin-menu"]/div/ul' . implode('/parent::li/ul', $xpath);
+    $this->assertNoElementByXPath($xpath, $args, $message . ' link not found.');
+  }
+}
+
+/**
+ * Tests menu links depending on user permissions.
+ */
+class AdminMenuPermissionsTestCase extends AdminMenuWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Menu link access permissions',
+      'description' => 'Tests appearance of menu links depending on user permissions.',
+      'group' => 'Administration menu',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('node'));
+  }
+
+  /**
+   * Test that the links are added to the page (no JS testing).
+   */
+  function testPermissions() {
+    module_enable(array('contact'));
+    $this->resetAll();
+
+    // Anonymous users should not see the menu.
+    $this->drupalGet('');
+    $this->assertNoElementByXPath('//div[@id="admin-menu"]', array(), t('Administration menu not found.'));
+
+    // Create a user who
+    // - can access content overview
+    // - cannot access drupal.org links
+    // - cannot administer Contact module
+    $permissions = $this->basePermissions + array(
+      'access content overview',
+    );
+    $admin_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($admin_user);
+
+    // Check that the user can see the admin links, but not the drupal links.
+    $this->assertElementByXPath('//div[@id="admin-menu"]', array(), 'Administration menu found.');
+    $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/content'), 'Content link found.');
+    $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[@href=:path]', array(':path' => 'http://drupal.org'), 'Icon » Drupal.org link not found.');
+    $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/contact'), 'Structure » Contact link not found.');
+
+    // Create a user "reversed" to the above; i.e., who
+    // - cannot access content overview
+    // - can access drupal.org links
+    // - can administer Contact module
+    $permissions = $this->basePermissions + array(
+      'display drupal links',
+      'administer contact forms',
+    );
+    $admin_user2 = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($admin_user2);
+    $this->assertElementByXPath('//div[@id="admin-menu"]', array(), 'Administration menu found.');
+    $this->assertNoElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/content'), 'Content link not found.');
+    $this->assertElementByXPath('//div[@id="admin-menu"]//a[@href=:path]', array(':path' => 'http://drupal.org'), 'Icon » Drupal.org link found.');
+    $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/contact'), 'Structure » Contact link found.');
+  }
+
+  /**
+   * Tests handling of links pointing to category/overview pages.
+   */
+  function testCategories() {
+    // Create a user with minimum permissions.
+    $admin_user = $this->drupalCreateUser($this->basePermissions);
+    $this->drupalLogin($admin_user);
+
+    // Verify that no category links appear.
+    $this->assertNoLinkTrailByTitle(array(t('Structure')));
+    $this->assertNoLinkTrailByTitle(array(t('Configuration')));
+
+    // Create a user with access to one configuration category.
+    $permissions = $this->basePermissions + array(
+      'administer users',
+    );
+    $admin_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($admin_user);
+
+    // Verify that only expected category links appear.
+    $this->assertNoLinkTrailByTitle(array(t('Structure')));
+    $this->assertLinkTrailByTitle(array(t('People')));
+    $this->assertLinkTrailByTitle(array(t('Configuration')));
+    $this->assertLinkTrailByTitle(array(t('Configuration'), t('People')));
+    // Random picks are sufficient.
+    $this->assertNoLinkTrailByTitle(array(t('Configuration'), t('Media')));
+    $this->assertNoLinkTrailByTitle(array(t('Configuration'), t('System')));
+  }
+
+  /**
+   * Tests that user role and permission changes are properly taken up.
+   */
+  function testPermissionChanges() {
+    // Create a user who is able to change permissions.
+    $permissions = $this->basePermissions + array(
+      'administer permissions',
+    );
+    $admin_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($admin_user);
+
+    // Extract the user role ID that was created for above permissions.
+    $rid = key(array_diff_key($admin_user->roles, array(DRUPAL_AUTHENTICATED_RID => 0)));
+
+    // Verify that Configuration does not appear.
+    $this->assertNoLinkTrailByTitle(array(t('Configuration')));
+    // Grant the 'administer site configuration' permission to ourselves.
+    $edit = array(
+      $rid . '[administer site configuration]' => TRUE,
+    );
+    $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
+    // Verify that Configuration appears.
+    $this->assertLinkTrailByTitle(array(t('Configuration')));
+
+    // Verify that Structure » Content types does not appear.
+    $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
+    // Create a new role.
+    $edit = array(
+      'name' => 'test',
+    );
+    $this->drupalPost('admin/people/permissions/roles', $edit, t('Add role'));
+    // It should be safe to assume that the new role gets the next ID.
+    $test_rid = $rid + 1;
+    // Grant the 'administer content types' permission for the role.
+    $edit = array(
+      $test_rid . '[administer content types]' => TRUE,
+    );
+    $this->drupalPost('admin/people/permissions/' . $test_rid, $edit, t('Save permissions'));
+    // Verify that Structure » Content types does not appear.
+    $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
+
+    // Assign the role to ourselves.
+    $edit = array(
+      'roles[' . $test_rid . ']' => TRUE,
+    );
+    $this->drupalPost('user/' . $admin_user->uid . '/edit', $edit, t('Save'));
+    // Verify that Structure » Content types appears.
+    $this->assertLinkTrailByTitle(array(t('Structure'), t('Content types')));
+
+    // Delete the role.
+    $this->drupalPost('admin/people/permissions/roles/edit/' . $test_rid, array(), t('Delete role'));
+    $this->drupalPost(NULL, array(), t('Delete'));
+    // Verify that Structure » Content types does not appear.
+    $this->assertNoLinkTrailByTitle(array(t('Structure'), t('Content types')));
+  }
+}
+
+/**
+ * Tests appearance, localization, and escaping of dynamic links.
+ */
+class AdminMenuDynamicLinksTestCase extends AdminMenuWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Dynamic links',
+      'description' => 'Tests appearance, localization, and escaping of dynamic links.',
+      'group' => 'Administration menu',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('node'));
+  }
+
+  /**
+   * Tests node type links.
+   */
+  function testNode() {
+    $type = $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+    // Create a content-type with special characters.
+    $type = $this->drupalCreateContentType(array('type' => 'special', 'name' => 'Cool & Special'));
+
+    $permissions = $this->basePermissions + array(
+      'administer content types',
+      'create article content',
+      'create special content',
+    );
+    $this->admin_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->admin_user);
+
+    // Verify that dynamic links are displayed.
+    $this->drupalGet('');
+    $this->assertElementByXPath('//div[@id="admin-menu"]', array(), t('Administration menu found.'));
+    $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path)]', array(':path' => 'admin/structure/types'), "Structure » Content types link found.");
+
+    // Verify link title output escaping.
+    $this->assertNoRaw('Cool & Special');
+    $this->assertRaw(check_plain('Cool & Special'));
+
+    // Verify Manage content type links.
+    $links = array(
+      'admin/structure/types/manage/article' => 'Article',
+      'admin/structure/types/manage/special' => 'Cool & Special',
+    );
+    foreach ($links as $path => $title) {
+      $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
+        ':path' => $path,
+        ':title' => $title,
+      ), "Structure » Content types » $title link found.");
+    }
+
+    // Verify Add content links.
+    $links = array(
+      'node/add/article' => 'Article',
+      'node/add/special' => 'Cool & Special',
+    );
+    foreach ($links as $path => $title) {
+      $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
+        ':path' => $path,
+        ':title' => $title,
+      ), "Add content » $title link found.");
+    }
+  }
+
+  /**
+   * Tests Add content links.
+   */
+  function testNodeAdd() {
+    $type = $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+
+    // Verify that "Add content" does not appear for unprivileged users.
+    $permissions = $this->basePermissions + array(
+      'access content',
+    );
+    $this->web_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->web_user);
+    $this->assertNoText(t('Add content'));
+
+    // Verify "Add content" appears below "Content" for administrative users.
+    $permissions = $this->basePermissions + array(
+      'access content overview',
+      'access content',
+      'create article content',
+    );
+    $this->admin_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->admin_user);
+    $this->assertLinkTrailByTitle(array(
+      t('Content'),
+      t('Add content'),
+    ));
+
+    // Verify "Add content" appears on the top-level for regular users.
+    $permissions = $this->basePermissions + array(
+      'access content',
+      'create article content',
+    );
+    $this->web_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->web_user);
+    $this->assertLinkTrailByTitle(array(
+      t('Add content'),
+    ));
+  }
+}
+
+/**
+ * Tests appearance of different types of links.
+ */
+class AdminMenuLinkTypesTestCase extends AdminMenuWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Link types',
+      'description' => 'Tests appearance of different types of links.',
+      'group' => 'Administration menu',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('help'));
+
+    $permissions = module_invoke_all('permission');
+    $permissions = array_keys($permissions);
+    $this->admin_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->admin_user);
+  }
+
+  /**
+   * Tests appearance of different router item link types.
+   */
+  function testLinkTypes() {
+    // Verify that MENU_NORMAL_ITEMs appear.
+    $this->assertLinkTrailByTitle(array(
+      t('Configuration'),
+      t('System'),
+      t('Site information'),
+    ));
+
+    // Verify that MENU_LOCAL_TASKs appear.
+    $this->assertLinkTrailByTitle(array(t('People'), t('Permissions')));
+    $this->assertLinkTrailByTitle(array(t('Appearance'), t('Settings')));
+    $this->assertLinkTrailByTitle(array(t('Modules'), t('Uninstall')));
+
+    // Verify that MENU_LOCAL_ACTIONs appear.
+    $this->assertLinkTrailByTitle(array(
+      t('People'),
+      t('Add user'),
+    ));
+
+    // Verify that MENU_DEFAULT_LOCAL_TASKs do NOT appear.
+    $this->assertNoLinkTrailByTitle(array(t('Modules'), t('List')));
+    $this->assertNoLinkTrailByTitle(array(t('People'), t('List')));
+    $this->assertNoLinkTrailByTitle(array(t('People'), t('Permissions'), t('Permissions')));
+    $this->assertNoLinkTrailByTitle(array(t('Appearance'), t('List')));
+
+    // Verify that MENU_VISIBLE_IN_BREADCRUMB items (exact type) do NOT appear.
+    $this->assertNoLinkTrailByTitle(array(t('Modules'), t('Uninstall'), t('Uninstall')));
+    $this->assertNoLinkTrailByTitle(array(t('Help'), 'admin_menu'));
+
+    // Verify that special "Index" link appears below icon.
+    $this->assertElementByXPath('//div[@id="admin-menu"]//a[contains(@href, :path) and text()=:title]', array(
+      ':path' => 'admin/index',
+      ':title' => t('Index'),
+    ), "Icon » Index link found.");
+  }
+}
+
+/**
+ * Tests customized menu links.
+ */
+class AdminMenuCustomizedTestCase extends AdminMenuWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Customized links',
+      'description' => 'Tests customized menu links.',
+      'group' => 'Administration menu',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('menu'));
+
+    $this->admin_user = $this->drupalCreateUser($this->basePermissions + array(
+      'administer menu',
+    ));
+    $this->drupalLogin($this->admin_user);
+  }
+
+  /**
+   * Test disabled custom links.
+   */
+  function testCustomDisabled() {
+    $type = $this->drupalCreateContentType();
+    $node = $this->drupalCreateNode(array('type' => $type->type));
+    $text = $this->randomName();
+    $xpath = $this->buildXPathQuery('//div[@id=:id]//a[contains(text(), :text)]', array(
+      ':id' => 'admin-menu',
+      ':text' => $text,
+    ));
+
+    // Verify that the link does not appear in the menu.
+    $this->drupalGet('node');
+    $elements = $this->xpath($xpath);
+    $this->assertFalse($elements, 'Custom link not found.');
+
+    // Add a custom link to the node to the menu.
+    $edit = array(
+      'link_path' => 'node/' . $node->nid,
+      'link_title' => $text,
+      'parent' => 'management:' . $this->queryMlidByPath('admin'),
+    );
+    $this->drupalPost('admin/structure/menu/manage/management/add', $edit, t('Save'));
+
+    // Verify that the link appears in the menu.
+    $this->drupalGet('node');
+    $elements = $this->xpath($xpath);
+    $this->assertTrue($elements, 'Custom link found.');
+
+    // Disable the link.
+    $edit = array(
+      'enabled' => FALSE,
+    );
+    $this->drupalPost('admin/structure/menu/item/' . $this->queryMlidByPath('node/' . $node->nid) . '/edit', $edit, t('Save'));
+
+    // Verify that the disabled link does not appear in the menu.
+    $this->drupalGet('node');
+    $elements = $this->xpath($xpath);
+    $this->assertFalse($elements, 'Disabled custom link not found.');
+  }
+
+  /**
+   * Tests external links.
+   */
+  function testCustomExternal() {
+    // Add a custom link to the node to the menu.
+    $edit = array(
+      'link_path' => 'http://example.com',
+      'link_title' => 'Example',
+      'parent' => 'management:' . $this->queryMlidByPath('admin'),
+    );
+    $this->drupalPost('admin/structure/menu/manage/management/add', $edit, t('Save'));
+
+    // Verify that the link appears in the menu.
+    $this->drupalGet('');
+    $elements = $this->xpath('//div[@id=:id]//a[@href=:href and contains(text(), :text)]', array(
+      ':id' => 'admin-menu',
+      ':href' => $edit['link_path'],
+      ':text' => $edit['link_title'],
+    ));
+    $this->assertTrue($elements, 'External link found.');
+  }
+
+  /**
+   * Returns the menu link ID for a given link path in the management menu.
+   */
+  protected function queryMlidByPath($path) {
+    return db_query('SELECT mlid FROM {menu_links} WHERE menu_name = :menu AND link_path = :path', array(
+      ':menu' => 'management',
+      ':path' => $path,
+    ))->fetchField();
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/autocomplete_deluxe/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/autocomplete_deluxe/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,2 @@
+
+Enhanced autocomplete widget for drupal 7.x
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,54 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * This contains documentation only.
+ */
+
+/**
+ * Using the Autocomplete Deluxe element.
+ *
+ * When you want to use the Autocomplete Deluxe element, you have to choose
+ * between two types sources for the suggestion data: Ajax Callbacks or Lists.
+ * You can set the source type by using the appropriate options:
+ * - #autocomplete_deluxe_path expects a string with an url, that points to the ajax
+ *   callback. The response should be encoded as json(like for the core
+ *   autocomplete).
+ * - #autocomplete_options needs an array in the form of an array(similar to #options in core
+ *   for selects or checkboxes): array('a', 'b', 'c') or array(1 => 'a', 2 =>
+ *   'b', 3 => 'c').
+ *
+ * Besides this two, there are three other options, wich autocomplete deluxe
+ * accepts:
+ * - #multiple Indicates whether the user may select more than one item. Expects
+ *   TRUE or FALSE, by default it is set to FALSE.
+ * - #autocomplete_multiple_delimiter If #multiple is TRUE, then you can use
+ *   this option to set a seperator for multiple values. By default a string
+ *   with the follwing content will be used: ', '.
+ * - #autocomplete_min_length Indicates how many characters must be entered
+ *   until, the suggesion list can be opened. Especially helpfull, when your
+ *   ajax callback returns only valid suggestion for a minimum characters.
+ *   The default is 0.
+ */
+function somefunction() {
+  switch ($type) {
+    case 'list':
+      $element = array(
+        '#type' => 'autocomplete_deluxe',
+        '#autocomplete_options' => $options,
+        '#multiple' => FALSE,
+        '#autocomplete_min_length' => 0,
+      );
+      break;
+    case 'ajax':
+      $element = array(
+        '#type' => 'autocomplete_deluxe',
+        '#autocomplete_deluxe_path' => url('some_uri', array('absolute' => TRUE)),
+        '#multiple' => TRUE,
+        '#autocomplete_min_length' => 1,
+        '#autocomplete_multiple_delimiter' => '|',
+      );
+      break;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,184 @@
+@CHARSET "UTF-8";
+
+
+ul.ui-autocomplete {
+  max-height: 240px;
+  overflow-x: hidden;
+  overflow-y: scroll;
+  padding: 3px;
+}
+
+a.autocomplete-deluxe-single:hover {
+  text-decoration: none;
+}
+
+.ui-autocomplete .ui-state-hover {
+  background-color: #3875d7;
+  background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
+  background-image: -webkit-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
+  background-image: -moz-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
+  background-image: -o-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
+  background-image: -ms-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
+  background-image: linear-gradient(top, #3875d7 20%, #2a62bc 90%);
+  color: #fff;
+  padding: 0;
+  margin: 0;
+}
+
+.autocomplete-deluxe-container {
+  display: inline-block;
+  position: relative;
+  padding: 0;
+  border: 1px solid #CCCCCC;
+  background: no-repeat -38px -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
+  background: no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+}
+div.autocomplete-deluxe-container input.autocomplete-deluxe-form {
+  background: #fff no-repeat -38px -22px;
+  padding: 4px 5px 4px 5px;
+  border: none;
+}
+
+div.autocomplete-deluxe-container input.autocomplete-deluxe-form-single  {
+  width: 90%;
+  border: none;
+  background: no-repeat -38px -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
+  background: no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+}
+
+.autocomplete-deluxe-search {
+  margin: 0px 0px 4px 0px;
+  padding: 3px 4px;
+  position: relative;
+  white-space: nowrap;
+  z-index: 1010;
+}
+
+span.autocomplete-deluxe-value-delete {
+  display: inline-block;
+  float: right;
+  background:url('x.gif') no-repeat center;
+  width: 18px;
+  width: 18px;
+
+  /* Prevent text selection. */
+  -moz-user-select: -moz-none;
+  -khtml-user-select: none;
+  -webkit-user-select: none;
+  -o-user-select: none;
+  user-select: none;
+}
+
+.autocomplete-deluxe-single-open {
+  border: 1px solid #aaa;
+  -webkit-box-shadow: 0 1px 0 #fff inset;
+  -moz-box-shadow   : 0 1px 0 #fff inset;
+  -o-box-shadow     : 0 1px 0 #fff inset;
+  box-shadow        : 0 1px 0 #fff inset;
+  background-color: #eee;
+  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0 );
+  background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff));
+  background-image: -webkit-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
+  background-image: -moz-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
+  background-image: -o-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
+  background-image: -ms-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
+  background-image: linear-gradient(top, #eeeeee 20%, #ffffff 80%);
+  -webkit-border-bottom-left-radius : 0;
+  -webkit-border-bottom-right-radius: 0;
+  -moz-border-radius-bottomleft : 0;
+  -moz-border-radius-bottomright: 0;
+  border-bottom-left-radius : 0;
+  border-bottom-right-radius: 0;
+}
+
+input.autocomplete-deluxe-closed {
+}
+
+div.autocomplete-deluxe-multiple {
+  display: inline-block;
+  font-size: 13px;
+  position: relative;
+  background-color: #FFFFFF;
+  background: #fff no-repeat -38px -22px;
+  background: no-repeat -38px -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
+  background: no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  background: no-repeat -38px -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%);
+  padding: 4px 5px 4px 20px;
+  border: 1px solid #AAAAAA;
+  cursor: text;
+  height: auto !important;
+  margin: 0;
+  overflow: hidden;
+  padding: 5px;
+  position: relative;
+  line-height:15pt;
+  width: 503px;
+  cursor: text;
+}
+
+input.autocomplete-deluxe-form.autocomplete-deluxe-multiple {
+  border: 3px none;
+  width: 25px;
+  margin-left: 5px;
+  float: left;
+}
+
+div.autocomplete-deluxe-throbber {
+  width: 16px;
+  float: right;
+  height: 50%;
+}
+
+.autocomplete-deluxe-closed {
+  background: url(throbber.gif) no-repeat 100% 6px;
+}
+
+.autocomplete-deluxe-open {
+  background: url(throbber.gif) no-repeat 100% -14px;
+}
+
+.autocomplete-deluxe-item {
+  float: left;
+  background-clip: padding-box;
+  background-color: #E4E4E4;
+  background-image: -moz-linear-gradient(center top , #F4F4F4 20%, #F0F0F0 50%, #E8E8E8 52%, #EEEEEE 100%);
+  border: 1px solid #AAAAAA;
+  border-radius: 3px 3px 3px 3px;
+  box-shadow: 0 0 2px #FFFFFF inset, 0 1px 0 rgba(0, 0, 0, 0.05);
+  color: #333333;
+  cursor: default;
+  line-height: 13px;
+  margin: 3px 0 3px 5px;
+  padding: 3px 20px 3px 5px;
+  position: relative;
+}
+
+.autocomplete-deluxe-item-delete {
+  background: url("x.gif");
+  display: block;
+  font-size: 1px;
+  height: 13px;
+  position: absolute;
+  right: 3px;
+  top: 3px;
+  width: 12px;
+}
+.autocomplete-deluxe-item-focus {
+  background: none repeat scroll 0 0 #D4D4D4;
+}
+
+.autocomplete-deluxe-highlight-char {
+  color: blue;
+  font-weight: bold;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Autocomplete Deluxe
+description = Enhanced autocomplete using Jquery UI autocomplete.
+package = User interface
+core = 7.x
+files[] = autocomplete_deluxe.module
+dependencies[] = taxonomy
+
+; Information added by drupal.org packaging script on 2013-08-05
+version = "7.x-2.0-beta3"
+core = "7.x"
+project = "autocomplete_deluxe"
+datestamp = "1375695669"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,444 @@
+
+/**
+ * @file:
+ * Converts textfield to a autocomplete deluxe widget.
+ */
+
+(function($) {
+  Drupal.autocomplete_deluxe = Drupal.autocomplete_deluxe || {};
+
+  Drupal.behaviors.autocomplete_deluxe = {
+    attach: function(context) {
+      var autocomplete_settings = Drupal.settings.autocomplete_deluxe;
+
+      $('input.autocomplete-deluxe-form').once( function() {
+        if (autocomplete_settings[$(this).attr('id')].multiple === true) {
+          new Drupal.autocomplete_deluxe.MultipleWidget(this, autocomplete_settings[$(this).attr('id')]);
+        } else {
+          new Drupal.autocomplete_deluxe.SingleWidget(autocomplete_settings[$(this).attr('id')]);
+        }
+      });
+    }
+  };
+
+  /**
+   * Autogrow plugin which auto resizes the input of the multiple value.
+   *
+   * http://stackoverflow.com/questions/931207/is-there-a-jquery-autogrow-plugin-for-text-fields
+   *
+   */
+  $.fn.autoGrowInput = function(o) {
+
+    o = $.extend({
+      maxWidth: 1000,
+      minWidth: 0,
+      comfortZone: 70
+    }, o);
+
+    this.filter('input:text').each(function(){
+
+      var minWidth = o.minWidth || $(this).width(),
+        val = '',
+        input = $(this),
+        testSubject = $('<tester/>').css({
+          position: 'absolute',
+          top: -9999,
+          left: -9999,
+          width: 'auto',
+          fontSize: input.css('fontSize'),
+          fontFamily: input.css('fontFamily'),
+          fontWeight: input.css('fontWeight'),
+          letterSpacing: input.css('letterSpacing'),
+          whiteSpace: 'nowrap'
+        }),
+        check = function() {
+
+          if (val === (val = input.val())) {return;}
+
+          // Enter new content into testSubject
+          var escaped = val.replace(/&/g, '&amp;').replace(/\s/g,'&nbsp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+          testSubject.html(escaped);
+
+          // Calculate new width + whether to change
+          var testerWidth = testSubject.width(),
+            newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
+            currentWidth = input.width(),
+            isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
+              || (newWidth > minWidth && newWidth < o.maxWidth);
+
+          // Animate width
+          if (isValidWidthChange) {
+            input.width(newWidth);
+          }
+
+        };
+
+      testSubject.insertAfter(input);
+
+      $(this).bind('keyup keydown blur update', check);
+
+    });
+
+    return this;
+  };
+
+
+  Drupal.autocomplete_deluxe.empty =  {label: '- ' + Drupal.t('None') + ' -', value: "" };
+
+  /**
+   * EscapeRegex function from jquery autocomplete, is not included in drupal.
+   */
+  Drupal.autocomplete_deluxe.escapeRegex = function(value) {
+    return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/gi, "\\$&");
+  };
+
+  /**
+   * Filter function from jquery autocomplete, is not included in drupal.
+   */
+  Drupal.autocomplete_deluxe.filter = function(array, term) {
+    var matcher = new RegExp(Drupal.autocomplete_deluxe.escapeRegex(term), "i");
+    return $.grep(array, function(value) {
+      return matcher.test(value.label || value.value || value);
+    });
+  };
+
+  Drupal.autocomplete_deluxe.Widget = function() {
+  };
+
+  Drupal.autocomplete_deluxe.Widget.prototype.uri = null;
+
+  /**
+   * Allows widgets to filter terms.
+   * @param term
+   *   A term that should be accepted or not.
+   * @return {Boolean}
+   *   True if the term should be accepted.
+   */
+  Drupal.autocomplete_deluxe.Widget.prototype.acceptTerm = function(term) {
+    return true;
+  };
+
+  Drupal.autocomplete_deluxe.Widget.prototype.init = function(settings) {
+    if ($.browser.msie && $.browser.version === "6.0") {
+      return;
+    }
+
+    this.id = settings.input_id;
+    this.jqObject = $('#' + this.id);
+
+    this.uri = settings.uri;
+    this.multiple = settings.multiple;
+    this.required = settings.required;
+    this.limit = settings.limit;
+    this.synonyms = typeof settings.use_synonyms == 'undefined' ? false : settings.use_synonyms;
+
+    this.wrapper = '""';
+
+    if (typeof settings.delimiter == 'undefined') {
+      this.delimiter = true;
+    } else {
+      this.delimiter =  settings.delimiter.charCodeAt(0);
+    }
+
+
+    this.items = {};
+
+    var self = this;
+    var parent = this.jqObject.parent();
+    var parents_parent = this.jqObject.parent().parent();
+
+    parents_parent.append(this.jqObject);
+    parent.remove();
+    parent = parents_parent;
+
+    var generateValues = function(data, term) {
+      var result = new Array();
+      for (var terms in data) {
+        if (self.acceptTerm(terms)) {
+          result.push({
+            label: data[terms],
+            value: terms
+          });
+        }
+      }
+      if ($.isEmptyObject(result)) {
+        result.push({
+          label: Drupal.t("The term '@term' will be added.", {'@term' : term}),
+          value: term,
+          newTerm: true
+        });
+      }
+      return result;
+    };
+
+    var cache = {}
+    var lastXhr = null;
+
+    this.source = function(request, response) {
+      var term = request.term;
+      if (term in cache) {
+        response(generateValues(cache[term], term));
+        return;
+      }
+
+      // Some server collapse two slashes if the term is empty, so insert at
+      // least a whitespace. This whitespace will later on be trimmed in the
+      // autocomplete callback.
+      if (!term) {
+        term = " ";
+      }
+      request.synonyms = self.synonyms;
+      var url = settings.uri + '/' + term +'/' +  self.limit;
+      lastXhr = $.getJSON(url, request, function(data, status, xhr) {
+        cache[term] = data;
+        if (xhr === lastXhr) {
+          response(generateValues(data, term));
+        }
+      });
+    };
+
+    this.jqObject.autocomplete({
+      'source' : this.source,
+      'minLength': settings.min_length
+    });
+
+    var jqObject = this.jqObject;
+    var throbber = $('<div class="autocomplete-deluxe-throbber autocomplete-deluxe-closed">&nbsp;</div>').insertAfter(jqObject);
+
+    this.jqObject.bind("autocompletesearch", function(event, ui) {
+      throbber.removeClass('autocomplete-deluxe-closed');
+      throbber.addClass('autocomplete-deluxe-open');
+    });
+
+    this.jqObject.bind("autocompleteopen", function(event, ui) {
+      throbber.addClass('autocomplete-deluxe-closed');
+      throbber.removeClass('autocomplete-deluxe-open');
+    });
+
+    // Monkey patch the _renderItem function jquery so we can highlight the
+    // text, that we already entered.
+    $.ui.autocomplete.prototype._renderItem = function( ul, item) {
+      var t = item.label;
+      if (this.term != "") {
+        var escapedValue = Drupal.autocomplete_deluxe.escapeRegex( this.term );
+        var re = new RegExp('()*""' + escapedValue + '""|' + escapedValue + '()*', 'gi');
+        var t = item.label.replace(re,"<span class='autocomplete-deluxe-highlight-char'>$&</span>");
+      }
+      return $( "<li></li>" )
+        .data( "item.autocomplete", item )
+        .append( "<a>" + t + "</a>" )
+        .appendTo( ul );
+    };
+  };
+
+  Drupal.autocomplete_deluxe.Widget.prototype.generateValues = function(data) {
+    var result = new Array();
+    for (var index in data) {
+      result.push(data[index]);
+    }
+    return result;
+  };
+
+  /**
+   * Generates a single selecting widget.
+   */
+  Drupal.autocomplete_deluxe.SingleWidget = function(settings) {
+    this.init(settings);
+    this.setup();
+    this.jqObject.addClass('autocomplete-deluxe-form-single');
+  };
+
+  Drupal.autocomplete_deluxe.SingleWidget.prototype = new Drupal.autocomplete_deluxe.Widget();
+
+  Drupal.autocomplete_deluxe.SingleWidget.prototype.setup = function() {
+    var jqObject = this.jqObject;
+    var parent = jqObject.parent();
+
+    parent.mousedown(function() {
+      if (parent.hasClass('autocomplete-deluxe-single-open')) {
+        jqObject.autocomplete('close');
+      } else {
+        jqObject.autocomplete('search', '');
+      }
+    });
+  };
+
+  /**
+   * Creates a multiple selecting widget.
+   */
+  Drupal.autocomplete_deluxe.MultipleWidget = function(input, settings) {
+    this.init(settings);
+    this.setup();
+  };
+
+  Drupal.autocomplete_deluxe.MultipleWidget.prototype = new Drupal.autocomplete_deluxe.Widget();
+  Drupal.autocomplete_deluxe.MultipleWidget.prototype.items = new Object();
+
+
+  Drupal.autocomplete_deluxe.MultipleWidget.prototype.acceptTerm = function(term) {
+    // Accept only terms, that are not in our items list.
+    return !(term in this.items);
+  };
+
+  Drupal.autocomplete_deluxe.MultipleWidget.Item = function (widget, item) {
+    if (item.newTerm === true) {
+      item.label = item.value;
+    }
+
+    this.value = item.value;
+    this.element = $('<span class="autocomplete-deluxe-item">' + item.label + '</span>');
+    this.widget = widget;
+    this.item = item;
+    var self = this;
+
+    var close = $('<a class="autocomplete-deluxe-item-delete" href="javascript:void(0)"></a>').appendTo(this.element);
+    // Use single quotes because of the double quote encoded stuff.
+    var input = $('<input type="hidden" value=\'' + this.value + '\'/>').appendTo(this.element);
+
+    close.mousedown(function() {
+      self.remove(item);
+    });
+  };
+
+  Drupal.autocomplete_deluxe.MultipleWidget.Item.prototype.remove = function() {
+    this.element.remove();
+    var values = this.widget.valueForm.val();
+    var escapedValue = Drupal.autocomplete_deluxe.escapeRegex( this.item.value );
+    var regex = new RegExp('()*""' + escapedValue + '""|' + escapedValue + '()*', 'gi');
+    this.widget.valueForm.val(values.replace(regex, ''));
+    delete this.widget.items[this.value];
+  };
+
+  Drupal.autocomplete_deluxe.MultipleWidget.prototype.setup = function() {
+    var jqObject = this.jqObject;
+    var parent = jqObject.parent();
+    var value_container = jqObject.parent().parent().children('.autocomplete-deluxe-value-container');
+    var value_input = value_container.children().children();
+    var items = this.items;
+    var self = this;
+    this.valueForm = value_input;
+
+    // Override the resize function, so that the suggestion list doesn't resizes
+    // all the time.
+    jqObject.data("autocomplete")._resizeMenu = function()  {};
+
+    jqObject.show();
+
+    value_container.hide();
+
+    // Add the default values to the box.
+    var default_values = value_input.val();
+    default_values = $.trim(default_values);
+    default_values = default_values.substr(2, default_values.length-4);
+    default_values = default_values.split('"" ""');
+
+    for (var index in default_values) {
+      var value = default_values[index];
+      if (value != '') {
+        // If a terms is encoded in double quotes, then the label should have
+        // no double quotes.
+        var label = value.match(/["][\w|\s|\D|]*["]/gi) !== null ? value.substr(1, value.length-2) : value;
+        var item = {
+          label : label,
+          value : value
+        };
+        var item = new Drupal.autocomplete_deluxe.MultipleWidget.Item(self, item);
+        item.element.insertBefore(jqObject);
+        items[item.value] = item;
+      }
+    }
+
+    jqObject.addClass('autocomplete-deluxe-multiple');
+    parent.addClass('autocomplete-deluxe-multiple');
+
+
+    // Adds a value to the list.
+    this.addValue = function(ui_item) {
+      var item = new Drupal.autocomplete_deluxe.MultipleWidget.Item(self, ui_item);
+      item.element.insertBefore(jqObject);
+      items[ui_item.value] = item;
+      var new_value = ' ' + self.wrapper + ui_item.value + self.wrapper;
+      var values = value_input.val();
+      value_input.val(values + new_value);
+      jqObject.val('');
+    };
+
+    parent.mouseup(function() {
+      jqObject.autocomplete('search', '');
+      jqObject.focus();
+    });
+
+    jqObject.bind("autocompleteselect", function(event, ui) {
+      self.addValue(ui.item);
+      jqObject.width(25);
+      // Return false to prevent setting the last term as value for the jqObject.
+      return false;
+    });
+
+    jqObject.bind("autocompletechange", function(event, ui) {
+      jqObject.val('');
+    });
+
+    jqObject.blur(function() {
+      var last_element = jqObject.parent().children('.autocomplete-deluxe-item').last();
+      last_element.removeClass('autocomplete-deluxe-item-focus');
+    });
+
+    var clear = false;
+
+    jqObject.keypress(function (event) {
+      var value = jqObject.val();
+      // If a comma was entered and there is none or more then one comma,or the
+      // enter key was entered, then enter the new term.
+      if ((event.which == self.delimiter && (value.split('"').length - 1) != 1) || (event.which == 13 && jqObject.val() != "")) {
+        value = value.substr(0, value.length);
+        if (typeof self.items[value] == 'undefined' && value != '') {
+          var ui_item = {
+            label: value,
+            value: value
+          };
+          self.addValue(ui_item);
+        }
+        clear = true;
+        if (event.which == 13) {
+          return false;
+        }
+      }
+
+      // If the Backspace key was hit and the input is empty
+      if (event.which == 8 && value == '') {
+        var last_element = jqObject.parent().children('.autocomplete-deluxe-item').last();
+        // then mark the last item for deletion or deleted it if already marked.
+        if (last_element.hasClass('autocomplete-deluxe-item-focus')) {
+          var value = last_element.children('input').val();
+          self.items[value].remove(self.items[value]);
+          jqObject.autocomplete('search', '');
+        } else {
+          last_element.addClass('autocomplete-deluxe-item-focus');
+        }
+      } else {
+        // Remove the focus class if any other key was hit.
+        var last_element = jqObject.parent().children('.autocomplete-deluxe-item').last();
+        last_element.removeClass('autocomplete-deluxe-item-focus');
+      }
+    });
+
+    jqObject.autoGrowInput({
+      comfortZone: 50,
+      minWidth: 10,
+      maxWidth: 460
+    });
+
+
+    jqObject.keyup(function (event) {
+      if (clear) {
+        // Trigger the search, so it display the values for an empty string.
+        jqObject.autocomplete('search', '');
+        jqObject.val('');
+        clear = false;
+        // Return false to prevent entering the last character.
+        return false;
+      }
+    });
+  };
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,392 @@
+<?php
+
+/**
+ * @file
+ * Define enhanced autocomplete wdiget.
+ */
+
+/**
+ * Implements hook_field_info().
+ */
+function autocomplete_deluxe_field_widget_info() {
+  return array(
+    'autocomplete_deluxe_taxonomy' => array(
+      'label' => t('Autocomplete Deluxe'),
+      'field types' => array('taxonomy_term_reference'),
+      'settings' => array(
+        'size' => 60,
+        'autocomplete_deluxe_path' => 'autocomplete_deluxe/taxonomy',
+      ),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+      ),
+    ),
+  );
+}
+
+/**
+ * Custom taxonomy callback, which also accepts an empty string search.
+ */
+function taxonomy_autocomplete_deluxe($field_name, $tags_typed = '', $limit = 10) {
+  $field = field_info_field($field_name);
+  $use_synonyms = !empty($_GET['synonyms']);
+
+  // The user enters a comma-separated list of tags. We only autocomplete the last tag.
+  $tags_typed = drupal_explode_tags($tags_typed);
+  $tag_last = drupal_strtolower(array_pop($tags_typed));
+
+  $matches = array();
+
+  // Part of the criteria for the query come from the field's own settings.
+  $vids = array();
+  $vocabularies = taxonomy_vocabulary_get_names();
+  foreach ($field['settings']['allowed_values'] as $tree) {
+    // If the content taxonomy setting content_taxonomy_ignore_in_suggestions
+    // is set, then the vocabulary is ignored.
+    if (empty($tree['content_taxonomy_ignore_in_suggestions'])) {
+      $vids[] = $vocabularies[$tree['vocabulary']]->vid;
+    }
+  }
+
+  $query = db_select('taxonomy_term_data', 't');
+  $query->addTag('translatable');
+  $query->addTag('term_access');
+
+  if (module_exists('synonyms') && !empty($use_synonyms)) {
+    $query->leftJoin('field_data_synonyms_synonym', 'fdss', 'fdss.entity_id = t.tid');
+  }
+
+  if ($tag_last != '') {
+    // Do not select already entered terms.
+    if (!empty($tags_typed)) {
+      $query->condition('t.name', $tags_typed, 'NOT IN');
+    }
+    // Select rows that match by term name.
+    $query
+      ->fields('t', array('tid', 'name'))
+      ->condition('t.vid', $vids);
+
+    if (module_exists('synonyms') && !empty($use_synonyms)) {
+      $or = db_or();
+      $or->condition('fdss.synonyms_synonym_value', '%' . db_like($tag_last) . '%', 'LIKE');
+      $or->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE');
+      $query->condition($or);
+    }
+    else {
+      $query->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE');
+    }
+
+    if (isset($limit) && $limit > 0) {
+      $query->range(0, $limit);
+    }
+
+    $tags_return = $query->execute()
+      ->fetchAllKeyed();
+  }
+  else {
+    $query
+      ->fields('t', array('tid', 'name'))
+      ->condition('t.vid', $vids);
+
+    if (isset($limit) && $limit > 0) {
+      $query->range(0, $limit);
+    }
+
+    $tags_return = $query->execute()
+      ->fetchAllKeyed();
+  }
+
+  $prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
+
+  $term_matches = array();
+  foreach ($tags_return as $tid => $name) {
+    $n = $name;
+    // Term names containing commas or quotes must be wrapped in quotes.
+    if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
+      $n = '"' . str_replace('"', '""', $name) . '"';
+    }
+    $term_matches[$prefix . $n] = check_plain($name);
+  }
+
+  drupal_json_output($term_matches);
+}
+
+/**
+ * Returns all allowed terms for a field without any prefix.
+ */
+function autocomplete_deluxe_allowed_terms($field) {
+  $options = array();
+  foreach ($field['settings']['allowed_values'] as $tree) {
+    if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
+      if ($terms = taxonomy_get_tree($vocabulary->vid, $tree['parent'])) {
+        foreach ($terms as $term) {
+          $options[$term->name] = $term->name;
+        }
+      }
+    }
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function autocomplete_deluxe_field_widget_settings_form($field, $instance) {
+  $widget = $instance['widget'];
+  $settings = $widget['settings'];
+
+  $form['size'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Size of textfield'),
+    '#default_value' => isset($settings['size']) ? $settings['size'] : 6,
+    '#element_validate' => array('_element_validate_integer_positive'),
+    '#required' => TRUE,
+  );
+  $form['limit'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Limit of the output.'),
+    '#description' => t('If set to zero no limit will be used'),
+    '#default_value' => isset($settings['limit']) ? $settings['limit'] : 10,
+    '#element_validate' => array('_element_validate_integer'),
+  );
+  $form['min_length'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Mininum length.'),
+    '#description' => t('The minimum length of characters to enter to open the suggestion list.'),
+    '#default_value' => isset($settings['min_length']) ? $settings['min_length'] : 0,
+    '#element_validate' => array('_element_validate_integer'),
+  );
+  $form['delimiter'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Delimiter.'),
+    '#description' => t('A character which should be used beside the enter key, to seperate terms.'),
+    '#default_value' => isset($settings['delimiter']) ? $settings['delimiter'] : '',
+    '#size' => 1,
+  );
+
+  if (module_exists('synonyms')) {
+    $form['use_synonyms'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Allow synonyms'),
+      '#description' => t('Should users be able to search for synonyms of terms?'),
+      '#default_value' => isset($settings['use_synonyms']) ? $settings['use_synonyms'] : FALSE,
+    );
+  }
+  return $form;
+}
+
+/**
+ * Implodes the tags from the taxonomy module.
+ *
+ * This function is essentially the same as axonomy_implode_tags, with the
+ * difference, that it uses only a comma instead of a comma and a space to
+ * implode the tags. It will help keep problems with delimiters to a minimum.
+ */
+function autocomplete_deluxe_taxonomy_implode_tags($tags, $vid = NULL) {
+  $typed_tags = array();
+  foreach ($tags as $tag) {
+    // Extract terms belonging to the vocabulary in question.
+    if (!isset($vid) || $tag->vid == $vid) {
+      // Make sure we have a completed loaded taxonomy term.
+      if (isset($tag->name)) {
+        // Commas and quotes in tag names are special cases, so encode 'em.
+        if (strpos($tag->name, ',') !== FALSE || strpos($tag->name, '"') !== FALSE) {
+          $tag->name = '"' . str_replace('"', '""', $tag->name) . '"';
+        }
+
+        $typed_tags[] = $tag->name;
+      }
+    }
+  }
+  return implode(',', $typed_tags);
+}
+
+/**
+ * Implements hook_field_widget_error().
+ */
+function autocomplete_deluxe_field_widget_error($element, $error, $form, &$form_state) {
+  form_error($element, $error['message']);
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function autocomplete_deluxe_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  $element += array(
+    '#type' => 'autocomplete_deluxe',
+    '#size' => $instance['widget']['settings']['size'],
+    '#limit' => isset($instance['widget']['settings']['limit']) ? $instance['widget']['settings']['limit'] : 10,
+    '#min_length' => isset($instance['widget']['settings']['min_length']) ? $instance['widget']['settings']['min_length'] : 0,
+    '#use_synonyms' =>isset($instance['widget']['settings']['use_synonyms']) ? $instance['widget']['settings']['use_synonyms'] : 0,
+    '#delimiter' =>isset($instance['widget']['settings']['delimiter']) ? $instance['widget']['settings']['delimiter'] : '',
+  );
+
+  $multiple = $field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED ? TRUE : FALSE;
+
+  $tags = array();
+  foreach ($items as $item) {
+    $tags[$item['tid']] = isset($item['taxonomy_term']) ? $item['taxonomy_term'] : taxonomy_term_load($item['tid']);
+  }
+
+  $element['#element_validate'] = array('taxonomy_autocomplete_validate');
+  $element += array(
+    '#multiple' => $multiple,
+    '#autocomplete_deluxe_path' => url($instance['widget']['settings']['autocomplete_deluxe_path'] . '/' . $field['field_name'], array('absolute' => TRUE)),
+    '#default_value' => autocomplete_deluxe_taxonomy_implode_tags($tags),
+  );
+
+  return $element;
+}
+
+/**
+ * Generates the basic form elements and javascript settings.
+ */
+function autocomplete_deluxe_element_process($element) {
+  $element['#attached'] = array(
+    'library' => array(array('system', 'ui.autocomplete'), array('system', 'ui.button')),
+    'js' => array(drupal_get_path('module', 'autocomplete_deluxe') . '/autocomplete_deluxe.js'),
+    'css' => array(drupal_get_path('module', 'autocomplete_deluxe') . '/autocomplete_deluxe.css'),
+  );
+  // Workaround for problems with jquery css in seven theme.
+  if ($GLOBALS['theme'] == 'seven') {
+    $element['#attached']['css'][] = drupal_get_path('module', 'autocomplete_deluxe') . '/autocomplete_deluxe.seven.css';
+  }
+
+  $html_id = drupal_html_id('autocomplete-deluxe-input');
+
+  $element['#after_build'][] = 'autocomplete_deluxe_after_build';
+
+  // Set default options for multiple values.
+  $element['#multiple'] = isset($element['#multiple']) ? $element['#multiple'] : FALSE;
+
+  $element['textfield'] = array(
+    '#type' => 'textfield',
+    '#size' => isset($element['#size']) ? $element['#size'] : '',
+    '#attributes' => array('class' => array('autocomplete-deluxe-form'), 'id' => array($html_id)),
+    '#default_value' => '',
+    '#prefix' => '<div class="autocomplete-deluxe-container">',
+    '#suffix' => '</div>',
+  );
+
+  $js_settings['autocomplete_deluxe'][$html_id] = array(
+    'input_id' => $html_id,
+    'multiple' => $element['#multiple'],
+    'required' => $element['#required'],
+    'limit' => isset($element['#limit']) ? $element['#limit'] : 10,
+    'min_length' => isset($element['#min_length']) ? $element['#min_length'] : 0,
+    'use_synonyms' => isset($element['#use_synonyms']) ? $element['#use_synonyms'] : 0,
+    'delimiter' => isset($element['#delimiter']) ? $element['#delimiter'] : '',
+  );
+
+  if (isset($element['#autocomplete_deluxe_path'])) {
+    if (isset($element['#default_value'])) {
+      // Split on the comma only if that comma has zero, or an even number of
+      // quotes in ahead of it.
+      // http://stackoverflow.com/questions/1757065/java-splitting-a-comma-separated-string-but-ignoring-commas-in-quotes
+      $default_value = preg_replace('/,(?=([^\"]*\"[^\"]*\")*[^\"]*$)/i', '"" ""', $element['#default_value']);
+      $default_value = '""' . $default_value . '""';
+    }
+    else {
+      $default_value = '';
+    }
+
+    if ($element['#multiple']) {
+      $element['value_field'] = array(
+        '#type' => 'textfield',
+        '#attributes' => array('class' => array('autocomplete-deluxe-value-field')),
+        '#default_value' => $default_value,
+        '#prefix' => '<div class="autocomplete-deluxe-value-container">',
+        '#suffix' => '</div>',
+      );
+      $element['textfield']['#attributes']['style'] = array('display:none');
+    }
+    else {
+      $element['textfield']['#default_value'] = isset($element['#default_value']) ? $element['#default_value'] : '';
+    }
+
+    $js_settings['autocomplete_deluxe'][$html_id] += array(
+      'type' => 'ajax',
+      'uri' => $element['#autocomplete_deluxe_path'],
+    );
+  }
+  else {
+    // If there is no source (path or data), we don't want to add the js
+    // settings and so the functions will be abborted.
+    return $element;
+  }
+  $element['#attached']['js'][] = array('data' => $js_settings, 'type' => 'setting');
+  $element['#tree'] = TRUE;
+
+  return $element;
+}
+
+/**
+ * Helper function to determine the value for a autocomplete deluxe form
+ * element.
+ */
+function autocomplete_deluxe_value(&$element, $input = FALSE, $form_state = NULL) {
+  // This runs before child elements are processed, so we cannot calculate the
+  // value here. But we have to make sure the value is an array, so the form
+  // API is able to proccess the children to set their values in the array. Thus
+  // once the form API has finished processing the element, the value is an
+  // array containing the child element values. Then finally the after build
+  // callback converts it back to the numeric value and sets that.
+  return array();
+}
+
+/**
+ * FAPI after build callback for the duration parameter type form.
+ * Fixes up the form value by applying the multiplier.
+ */
+function autocomplete_deluxe_after_build($element, &$form_state) {
+  // By default drupal sets the maxlength to 128 if the property isn't
+  // specified, but since the limit isn't useful in some cases,
+  // we unset the property.
+  unset($element['textfield']['#maxlength']);
+
+  // Set the elements value from either the value field or text field input.
+  $element['#value'] = isset($element['value_field']) ? $element['value_field']['#value'] : $element['textfield']['#value'];
+
+  if (isset($element['value_field'])) {
+    $element['#value'] = trim($element['#value']);
+    // Replace all double double quotes and space with a comma. This will allows
+    // us to keep entries in double quotes.
+    $element['#value'] = str_replace('"" ""', ',', $element['#value']);
+    $element['#value'] = str_replace('""  ""', ',', $element['#value']);
+    // Remove the double quotes at the beginning and the end from the first and
+    // the last term.
+    $element['#value'] = substr($element['#value'], 2, strlen($element['#value']) - 4);
+
+    unset($element['value_field']['#maxlength']);
+  }
+
+
+  form_set_value($element, $element['#value'], $form_state);
+  return $element;
+}
+
+/**
+ * Implements hook_element_info().
+ */
+function autocomplete_deluxe_element_info() {
+  $types['autocomplete_deluxe'] = array(
+    '#input' => TRUE,
+    '#value_callback' => 'autocomplete_deluxe_value',
+    '#pre_render' => array('form_pre_render_conditional_form_element'),
+    '#process' => array('autocomplete_deluxe_element_process'),
+  );
+  return $types;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function autocomplete_deluxe_menu() {
+  $items['autocomplete_deluxe/taxonomy'] = array(
+    'title' => 'Autocomplete deluxe taxonomy',
+    'page callback' => 'taxonomy_autocomplete_deluxe',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/autocomplete_deluxe/autocomplete_deluxe.seven.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,89 @@
+@CHARSET "UTF-8";
+
+/**
+ * JQuery UI style sheet fix for seven.
+ */
+
+.ui-button {
+  border: 1px solid #cccccc;
+  background: #e6e6e6;
+}
+
+.ui-state-hover,
+.ui-state-focus {
+  border: 1px solid #bbbbbb;
+}
+
+.ui-button.ui-state-active {
+  border: 1px solid #777777;
+  font-weight: bold;
+}
+
+/**
+ * Corner radius
+ */
+.ui-corner-tl {
+  -moz-border-radius-topleft: 4px;
+  -webkit-border-top-left-radius: 4px;
+  border-top-left-radius: 4px;
+}
+
+.ui-corner-tr {
+  -moz-border-radius-topright: 4px;
+  -webkit-border-top-right-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.ui-corner-bl {
+  -moz-border-radius-bottomleft: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+}
+
+.ui-corner-br {
+  -moz-border-radius-bottomright: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+}
+
+.ui-corner-top {
+  -moz-border-radius-topleft: 4px;
+  -moz-border-radius-topright: 4px;
+  -webkit-border-top-left-radius: 4px;
+  -webkit-border-top-right-radius: 4px;
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.ui-corner-bottom {
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-bottomright: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+  border-bottom-left-radius: 4px;
+  border-bottom-right-radius: 4px;
+}
+
+.ui-corner-right {
+  -moz-border-radius-bottomright: 4px;
+  -moz-border-radius-topright: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+  -webkit-border-top-right-radius: 4px;
+  border-bottom-right-radius: 4px;
+  border-top-right-radius: 4px;
+}
+
+.ui-corner-left {
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-topleft: 4px;
+  -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-top-left-radius: 4px;
+  border-bottom-left-radius: 4px;
+  border-top-left-radius: 4px;
+}
+
+.ui-corner-all {
+  -moz-border-radius: 4px;
+  -webkit-border-radius: 4px;
+  border-radius: 4px;
+}
Binary file sites/all/modules/autocomplete_deluxe/throbber.gif has changed
Binary file sites/all/modules/autocomplete_deluxe/x.gif has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,143 @@
+
+                           biblio.module
+
+Author:  Ron Jerome 
+Released under the GPL
+
+
+Description:
+============
+This module extends the node data type with additional fields to manage lists 
+of scholarly publications.
+
+It closely follows the EndNote model, thus both importing from and exporting 
+to Endote are supported. Other formats such as bibtex and RIS are also supported.
+
+Bibliographic information is displayed in lists with links to detailed 
+information on each publication.
+
+The lists can be sorted, filtered and ordered in many different ways.
+
+
+
+
+Requirements:
+=============
+Drupal 7.x, Upgrades supported from any Biblio version after 6.x-1.9
+
+Installation:
+=============
+Create a directory called biblio in the sites/all/modules directory, then place all of the
+files packaged with this module in that directory.
+
+This module will auto-install the required database tables the first time you 
+enable it on the admin/modules page.   This will also setup a number of pre-defined 
+publication types.  These types can be changed or deleted on the 
+admin/config/content/biblio/types page.
+
+Robots.txt
+==========
+In order to limit recursive searches by web bots, it is recommended that you add the following
+to your robots.txt file.  Note: if you change the base url for biblio you will have to make the 
+corresponding change here.  i.e. if you base url for biblio is "publications" then replace "biblio"
+with "publications" in the directives below.
+
+# Biblio
+Disallow: /biblio/export/
+Disallow: /biblio?*
+Disallow: /biblio?page=*&*
+Allow: /biblio?page=*
+
+
+Settings:
+=========
+A number of settings are available at admin/config/content/biblio.  They control how 
+the author names are displayed, whether export links are added to pages and the
+number of entries per page to display.
+
+The 'admin/config/content/biblio/fields' page allows the the site administrator to set
+the default field titles and set which fields are common to all publication 
+types.  When a new publication type is added, it will contain all the common 
+fields and any that are specifically activated (custom is checked).  This also
+allows the admin to over ride any of the default settings for any given type.
+
+Access Control:
+===============
+Three permissions are controlable on the admin/access page.  I think they are fairly
+self evident, they control who can create biblio entries, edit entries and who can
+import from file.
+
+Adding/importing records:
+=========================
+Bibliographic entries can be added to the database in one of two ways, individualy
+from the node/add/biblio link, or by importing records from one of the supported file 
+formats.  Administrators can go to 'admin/config/content/biblio/import' and fill in 
+the form to upload and import publication data from files.
+
+
+Features:
+=========
+By default, the /biblio page will list all of the entries in the database sorted
+by Year in descending order. If you wish to sort by "Title" or "Type", you may 
+do so by clicking on the appropriate links at the top of the page. To reverse 
+the sort order, simply click the link a second time.
+
+
+Filtering Search Results:
+=========================
+If you wish to filter the results, click on the "Filter" tab at the top of the 
+page. To add a filter, click the radio button to the left of the filter type 
+you wish to apply, then select the filter criteria from the drop down list 
+on the right, then click the filter button.
+
+It is possible to create complex filters by returning to the "Filter" tab and 
+adding additional filters. Simply follow the steps outlined above and press 
+the "Refine" button.
+
+All filters can be removed by clicking the Clear All Filters link at the top 
+of the result page, or on the "Filter" tab they can be removed one at a time 
+using the "Undo" button, or you can remove them all using the "Clear All" button
+
+You may also construct URLs which filter. For example, /biblio/year/2005 will 
+show all of the entries for 2005. /biblio/year/2005/author/smith will show all 
+of entries from 2005 for smith.
+
+
+Exporting Search Results:
+=========================
+Assuming this option has been enabled by the administrator, you can export 
+search results directly into EndNote. The link at the top of the result page 
+will export all of the search results, and the links on individual entries will 
+export the information related to that single entry.
+
+Clicking on one of the export links should cause your browser to ask you 
+whether you want to Open, or Save To Disk, the file endnote.enw. If you choose 
+to open it, Endnote should start and ask you which library you would like 
+store the results in. Alternatively, you can save the file to disk and manually 
+import it into EndNote.
+
+
+The information is exported in either EndNote "Tagged" format similar to this...
+
+              %0  Book
+              %A  John Smith 
+              %D  1959
+              %T  The Works of John Smith
+              ...
+              
+Or Endnote 7 XML format which is similar to this...
+
+              <XML>
+                <RECORDS>
+                  <RECORD>
+                    <REFERENCE_TYPE>10</REFERENCE_TYPE>
+                    <YEAR>1959</YEAR>
+                    <TITLE>The Works of John Smith</TITLE>
+                    <AUTHORS>
+                      <AUTHOR>John Smith </AUTHOR>
+                    </AUTHORS>
+                  </RECORD>
+                </RECORDS>
+              </XML>
+              
+              
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/biblio.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,338 @@
+#biblio-filter ul {
+  padding: 1px;
+  margin: 1px;
+  width: 100%;
+}
+
+#biblio-buttons {
+  float: left;
+  margin-left: 0.5em;
+  margin-top: 1em;
+  /* clear:                      right; */
+}
+
+.biblio-alpha-line {
+  text-align: center;
+}
+
+dl.bibliomultiselect dd.b,dl.bibliomultiselect dd.b .form-item,dl.bibliomultiselect dd.b select
+  {
+  font-family: inherit;
+  font-size: inherit;
+  width: 14em;
+}
+
+dl.bibliomultiselect dd.a,dl.bibliomultiselect dd.a .form-item {
+  width: 8em;
+}
+
+dl.bibliomultiselect dt,dl.bibliomultiselect dd {
+  float: left;
+  line-height: 1.75em;
+  padding: 0;
+  margin: 0 1em 0 0;
+}
+
+dl.bibliomultiselect .form-item {
+  height: 1.75em;
+  margin: 0;
+}
+#biblio-authors table, #biblio-tertiary-authors  table  {
+  width: 100%;  
+}
+#biblio-authors  .form-text {
+  width: 95%;  
+}
+#biblio-authors  td.biblio-contributor,
+#biblio-secondary-authors td.biblio-contributor,
+#biblio-tertiary-authors td.biblio-contributor,
+#biblio-subsidiary-authors  td.biblio-contributor,
+#biblio-corp-authors td.biblio-contributor{
+  width: 98%;
+}
+#biblio-authors #biblio-tertiary-authors .draggable a.tabledrag-handle {
+  padding: 0;
+}
+
+.biblio-head {
+  width: 97%;
+  color: Black;
+  font-weight: normal;
+  background-color: #EAEAEA;
+  border: medium solid;
+  border-left-color: #F0F8FF;
+  border-right-color: Gray;
+  border-bottom-color: Gray;
+  border-top-color: #F0F8FF;
+  padding: 3px;
+}
+
+.biblio-head a:link,.biblio-head a.active,.biblio-head a:visited,.biblio-head a:focus,.biblio-head a:hover
+  {
+  color: black;
+}
+
+.biblio-current-filters {
+  background-color: #ffe1e1;
+}
+
+.biblio-separator-bar {
+  color: #000000;
+  font-weight: bold;
+  background-color: #e1e1e1;
+  border: 1px solid #ccc;
+  padding: 0.5em;
+  margin: 1em 0 1em 0;
+}
+
+.biblio-toolbar {
+  width: 97%;
+  color: Red;
+  font-weight: bold;
+  background-color: Silver;
+  border: medium solid;
+  border-left-color: #F0F8FF;
+  border-right-color: Gray;
+  border-bottom-color: Gray;
+  border-top-color: #F0F8FF;
+  padding: 3px;
+}
+
+.biblio-entry {
+  margin: 1em 0 1em 0;
+}
+
+.biblio-style-mla {
+  text-indent: -25px;
+  padding-left: 25px;
+}
+
+.biblio-publisher {
+  font-style: oblique;
+  font-weight: bold;
+}
+
+.biblio-title {
+  font-weight: bold;
+  text-decoration: none;
+  font-style: normal;
+  line-height: normal;
+  text-align: left;
+  font-family: "@Arial Unicode MS", Arial, sans-serif;
+  color: #336599;
+}
+
+a:active {
+  
+}
+
+.biblio-authors a {
+  font-weight: normal;
+  text-decoration: none;
+  font-style: normal;
+}
+
+.biblio_type-1 {
+  background-color: #F2F2D9;
+}
+
+.biblio_type-2 {
+  background-color: #D9E6F2;
+}
+
+.biblio_type-3 {
+  background-color: #E5F2D9;
+}
+
+.biblio_type-4 {
+  background-color: #D9F2E6;
+}
+
+.biblio_type-5 {
+  background-color: #F2E6D9;
+}
+
+.biblio_type-6 {
+  background-color: #D9E6F2;
+}
+
+.biblio_type-7 {
+  background-color: #D9E6F2;
+}
+
+.biblio_type-8 {
+  background-color: #D9E6F2;
+}
+
+.biblio_type-9 {
+  background-color: #D9E6F2;
+}
+
+.biblio-export {
+  text-align: right;
+  text-decoration: none;
+  float: right;
+}
+
+.biblio-abstract-link {
+  text-align: left;
+  text-decoration: none;
+  font-style: normal;
+  font-weight: normal;
+  font-size: 75%;
+}
+
+.biblio-export-links {
+  float: right;
+  text-align: left;
+  text-decoration: none;
+  font-style: normal;
+  font-weight: normal;
+  font-size: 75%;
+  line-height: 100%;
+}
+
+ul.biblio-export-buttons,ul.biblio-export-buttons li {
+  background: transparent;
+  list-style-image: none;
+  list-style-type: none;
+  display: inline;
+  border-bottom: 0px;
+  border-right: 1px;
+  padding: 0;
+  margin: 0.1em;
+}
+
+.biblio-annotation {
+  text-align: left;
+  text-decoration: none;
+  margin-left: 2.5em;
+  margin-top: 0.5em;
+  margin-right: 2.5em;
+}
+
+.biblio-sort {
+  text-decoration: none;
+  text-align: left;
+}
+
+.biblio-openurl-text {
+  text-align: right;
+  text-decoration: none;
+  float: right;
+}
+
+.biblio-left-td {
+  text-align: right;
+  vertical-align: top;
+  width: 20%;
+}
+
+#biblio-header {
+  display: block;
+}
+/*
+#biblio-header ul.tabs {
+  border-bottom: 1px solid #BBBBBB;
+  padding: 0 0 1.765em 1em;
+}
+
+#biblio-header ul li {
+  padding: 0 0 0 0;
+  float: left;
+  display: block;
+}
+
+#biblio-header ul.tabs li a .a {
+  float: left;
+  height: 20px;
+  padding: 2px 0em 3px 0em;
+  margin: 0px;
+  padding: 0px;
+  background-image: url(main-tab1.png);
+  background-repeat: no-repeat;
+  background-position: 100% 0px;
+}
+
+#biblio-header ul.tabs li a .a .b {
+  display: block;
+  margin: 0px;
+  height: 20px;
+  padding: 0px 1em 3px;
+  background-image: url(main-tab2.png);
+  background-repeat: no-repeat;
+  background-position: 0% 0px;
+}
+
+#biblio-header ul.tabs li.active a {
+  background-color: transparent;
+  border-width: 0px;
+}
+
+#biblio-header ul.tabs li.active a .a {
+  background-position: 100% -60px;
+}
+
+#biblio-header ul.tabs li.active a .a .b {
+  background-position: 0% -60px;
+}
+
+#biblio-header ul.tabs li a:hover {
+  border-width: 0px;
+  text-decoration: none !important;
+}
+
+#biblio-header ul.tabs li a:hover .a {
+  background-position: 100% -30px;
+}
+
+#biblio-header ul.tabs li a:hover .a .b {
+  background-position: 0% -30px;
+}
+
+#biblio-header ul.tabs li.active a:hover {
+  background-color: #fff;
+  border-width: 0px;
+}
+
+#biblio-header ul.tabs li.active a:hover .a {
+  background-position: 100% -60px;
+}
+
+#biblio-header ul.tabs li.active a:hover .a .b {
+  background-position: 0% -60px;
+}
+*/
+.exposed-filters .filters {
+  float: left; /* LTR */
+  margin-right: 1em; /* LTR */
+  width: 25em; /* IE6 */
+}
+.exposed-filters .form-item {
+  margin: 0 0 0.1em 0;
+  padding: 0;
+}
+.exposed-filters .form-item label {
+  float: left; /* LTR */
+  font-weight: normal;
+  width: 10em;
+}
+.exposed-filters .form-select {
+  width: 14em;
+}
+/* Current filters */
+.exposed-filters .current-filters {
+  margin-bottom: 1em;
+}
+.exposed-filters .current-filters .placeholder {
+  font-style: normal;
+  font-weight: bold;
+}
+.exposed-filters .additional-filters {
+  float: left; /* LTR */
+  margin-right: 1em; /* LTR */
+}
+.biblio-highlight {
+    background-color: #FFF4F4;
+    border: 2px solid #494949;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/biblio.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,39 @@
+name = Biblio
+description = Maintains bibliographic lists.
+core = 7.x
+dependencies[] = taxonomy
+package = Biblio
+
+configure = admin/config/content/biblio
+files[] = tests/biblio.test
+files[] = tests/keyword.test
+files[] = tests/contributor.test
+files[] = tests/import.export.test
+
+files[] = includes/Name.php
+files[] = includes/Parser.php
+
+files[] = views/biblio_handler_citation.inc
+files[] = views/biblio_handler_field_keyword.inc
+files[] = views/biblio_handler_field_biblio_keyword_data_word.inc
+files[] = views/biblio_handler_field_biblio_keyword_kid.inc
+files[] = views/biblio_handler_field_biblio_type.inc
+files[] = views/biblio_handler_field_contributor.inc
+files[] = views/biblio_handler_field.inc
+files[] = views/biblio_handler_field_markup.inc
+files[] = views/biblio_handler_filter_biblio_contributor_auth_type.inc
+files[] = views/biblio_handler_filter_biblio_keyword_kid.inc
+files[] = views/biblio_handler_filter_biblio_keyword_word.inc
+files[] = views/biblio_handler_filter_biblio_type.inc
+files[] = views/biblio_handler_filter_contributor_lastname.inc
+files[] = views/biblio_handler_filter_contributor_uid.inc
+files[] = views/biblio_handler_filter_contributor.inc
+files[] = views/biblio_handler_sort_contributor_lastname.inc
+files[] = views/biblio_handler_argument_many_to_one.inc
+files[] = views/biblio_handler_field_export_link.inc
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/biblio.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,2218 @@
+<?php
+function biblio_install() {
+
+  $t = get_t();
+
+  // Define the node type.
+  $biblio = array(
+    'type' => 'biblio',
+    'name' => $t('Biblio'),
+    'base' => 'biblio',
+    'description' => $t('Use Biblio for scholarly content, such as journal papers and books.'),
+    'body_label' => $t('Full text')
+  );
+
+  // Complete the node type definition by setting any defaults not explicitly
+  // declared above.
+  // http://api.drupal.org/api/function/node_type_set_defaults/7
+  $content_type = node_type_set_defaults($biblio);
+  node_add_body_field($content_type);
+
+  // Save the content type
+  node_type_save($content_type);
+
+  drupal_set_time_limit(300);
+
+  $result[] = _add_db_field_data();
+
+  $result[] = _add_publication_types();
+
+  $result[] = _add_custom_field_data();
+
+  //_enable_biblio_keyword_vocabulary();
+
+  $result[] = _set_system_weight();
+
+
+
+//  if (count($result) == count(array_filter($result))) {
+//    drupal_set_message(t('The biblio module has successfully added its tables to the database.'));
+//  }
+//  else {
+//    drupal_set_message(t('Drupal encountered some errors while attempting to install the database tables for the biblio module.'), 'error');
+//  }
+}
+
+function biblio_enable() {
+//TODO taxonomy
+  //if (module_exists('taxonomy')) _enable_biblio_vocabularies();
+  _set_system_weight();
+  //_enable_biblio_collection_vocabulary();
+ // _add_biblio_keywords();
+}
+
+function _enable_biblio_vocabularies() {
+  $vids = variable_get('biblio_vocabularies', array());
+  foreach ($vids as $vid ) {
+    if (($voc = taxonomy_vocabulary_load($vid)))  {
+      $voc = (array) $voc;
+      $voc['nodes']['biblio'] = 1;
+      taxonomy_save_vocabulary($voc);
+    }
+  }
+}
+
+function biblio_disable() {
+  $vids = array();
+//TODO taxonomy
+/*
+  if (module_exists('taxonomy')) {
+    $voc = taxonomy_get_vocabularies();
+    foreach ($voc as $vid => $vocabulary) {
+      if (isset($vocabulary->nodes['biblio']))  {
+        $vids[] = $vid;
+      }
+    }
+    variable_set('biblio_vocabularies', $vids);
+  }
+*/
+}
+
+function biblio_uninstall() {
+  $batch = array(
+      'title' => t('Remove all Biblio nodes'),
+      'operations' => array(
+          array('biblio_batch_uninstall', array()),
+      ),
+      'progress_message' => t('Deleteing Biblio nodes...'),
+      'finished' => 'biblio_batch_uninstall_finished',
+      'file' =>  drupal_get_path('module', 'biblio') . '/biblio.install'
+  );
+
+  batch_set($batch);
+}
+function biblio_batch_uninstall(&$context) {
+
+  $limit = 5;
+  if (empty($context['sandbox'])) {
+    $context['sandbox']['progress'] = 0;
+    $context['sandbox']['current_node'] = 0;
+    $context['sandbox']['max'] = db_query("SELECT COUNT(DISTINCT nid) FROM {node} WHERE type='biblio'")->fetchField();
+    $context['sandbox']['itters'] = $context['sandbox']['max'] / $limit;
+    $context['sandbox']['eta'] = 0;
+  }
+  // Bail out if the cache is empty.
+  if ($context['sandbox']['max'] == 0) {
+    $context['finished'] = 1;
+    return;
+  }
+
+  timer_start('biblio_delete');
+
+  $result = db_select('node')
+  ->fields('node', array('nid'))
+  ->condition('nid', $context['sandbox']['current_node'], '>')
+  ->condition('type', 'biblio')
+  ->orderBy('nid')
+  ->range(0, $limit)
+  ->execute();
+
+  foreach ($result as $row) {
+    $node = node_delete($row->nid);
+    if (function_exists('search_wipe')) {
+      search_wipe($row->nid, 'node');
+    }
+    $context['sandbox']['progress']++;
+    $context['sandbox']['current_node'] = $row->nid;
+  }
+
+  $looptime = timer_stop('biblio_delete');
+  $context['sandbox']['eta'] += $looptime['time'];
+  $itters = $context['sandbox']['progress'] / $limit;
+  if ($itters) {
+    $average_time = $context['sandbox']['eta'] / $itters;
+    $eta = (($context['sandbox']['itters'] * $average_time) - ($average_time * $itters)) / 1000;
+    if ($eta >= 60) {
+      $min = (int) $eta / 60;
+    }
+    else {
+      $min = 0;
+    }
+    $sec = $eta % 60;
+    $eta = sprintf("%d:%02d", $min, $sec);
+    $progress = sprintf("%d / %d", $context['sandbox']['progress'],  $context['sandbox']['max'] );
+    $context['message'] = t('<br>Biblio nodes deleted: %progress <br> Time remaining: %eta min.<br>' , array('%progress' => $progress, '%eta' => $eta));
+  }
+  if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
+    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+  }
+}
+
+
+function biblio_batch_uninstall_finished($success, $results, $operations) {
+  if ($success) {
+//TODO taxonomy
+/*
+    if (module_exists('taxonomy')) {
+      $voc = taxonomy_get_vocabularies();
+      foreach ($voc as $vid => $vocabulary) {
+        if ($vocabulary->module == 'biblio')  taxonomy_del_vocabulary($vid);
+      }
+    }
+*/
+    $vars = db_query("SELECT * FROM {variable} WHERE name LIKE 'biblio_%'");
+    foreach ($vars as $var) {
+      variable_del($var->name);
+    }
+  }
+}
+
+function biblio_requirements($phase) {
+  $requirements = array();
+  $message = '';
+ // Ensure translations don't break at install time
+  $t = get_t();
+
+  // Report Drupal version
+  if ($phase == 'runtime') {
+    $dir = drupal_get_path('module', 'biblio');
+    $files = file_scan_directory($dir, '/..*.inc$/',  array('recurse' => FALSE));
+    if (count($files) > 1) {
+      $message = $t('There is a problem with your Biblio installation! There should not be any ".inc" files in the %biblio directory.  You probably forgot to delete the old biblio files when you upgraded the module.  You should remove the following files from that directory...', array('%biblio' => $dir));
+      $message .= "<ul>";
+      foreach ($files as $file) {
+        $message .= "<li>" . $file->filename;
+      }
+      $message .= "</ul>";
+      $requirements['biblio'] = array(
+        'title' => $t('Biblio'),
+        'value' => BIBLIO_VERSION,
+        'severity' => empty($message) ? REQUIREMENT_OK : REQUIREMENT_WARNING,
+        'description' => $message,
+      );
+    }
+
+  }
+  return $requirements;
+}
+
+function _biblio_helper_modules($mode) {
+
+  $modules = _biblio_get_helper_modules();
+  switch ($mode) {
+    case 'install':
+      module_enable($modules);
+      break;
+    case 'uninstall':
+      foreach ($modules as $module) {
+        drupal_uninstall_modules($module);
+      }
+      break;
+  }
+}
+
+function _biblio_get_helper_modules() {
+  return array(
+    'biblio_bibtex',
+    'biblio_crossref',
+    'biblio_marc',
+    'biblio_pm',
+    'biblio_ris',
+    'biblio_tagged',
+    'biblio_xml',
+    'biblio_citeproc',
+    'biblio_rtf',
+  );
+
+}
+
+function _set_system_weight() {
+      db_update('system')
+              ->fields(array(
+                'weight' => 9,
+              ))
+              ->condition('name', 'biblio')
+              ->execute();
+   return;
+}
+
+function _enable_biblio_keyword_vocabulary() {
+
+//TODO taxonomy
+/*
+  if ($vocabulary = taxonomy_vocabulary_load(variable_get('biblio_keyword_vocabulary', 0))) {
+      // Existing install. Add back forum node type, if the biblio
+    // vocabulary still exists. Keep all other node types intact there.
+    $vocabulary = (array) $vocabulary;
+    $vocabulary['nodes']['biblio'] = 1;
+    taxonomy_save_vocabulary($vocabulary);
+  }
+
+
+
+  return $vocabulary['vid'];
+*/
+}
+
+function _enable_biblio_collection_vocabulary() {
+//TODO taxonomy
+/*
+  if ($vocabulary = taxonomy_vocabulary_load(variable_get('biblio_collection_vocabulary', 0))) {
+    // Existing install. Add back forum node type, if the biblio
+    // vocabulary still exists. Keep all other node types intact there.
+    $vocabulary = (array) $vocabulary;
+    $vocabulary['nodes']['biblio'] = 1;
+    taxonomy_save_vocabulary($vocabulary);
+  }
+  else {
+    // Create the forum vocabulary if it does not exist. Assign the vocabulary
+    // a low weight so it will appear first in forum topic create and edit
+    // forms.
+    $vocabulary = array(
+      'name' => 'Biblio Collections',
+      'description' => 'You may organize your publications into collections by adding a collection names to this vocabulary',
+      'help' => '',
+      'nodes' => array('biblio' => 1),
+      'hierarchy' => 0,
+      'relations' => 1,
+      'tags' => 0,
+      'multiple' => 1,
+      'required' => 0,
+      'weight' => 0,
+      'module' => 'biblio',
+    );
+    taxonomy_save_vocabulary($vocabulary);
+    variable_set('biblio_collection_vocabulary', $vocabulary['vid']);
+    $default_collection = array(
+      'name' => t('Default'),
+      'description' => t("This is the collection that all biblio entries will be a part of if no other collection is selected. Deleting this term will render all your biblio entries inaccessable. (You've been warned!)" ),
+      'parent' => array(),
+      'relations' => array(),
+      'synonyms' => '',
+      'weight' => 0,
+      'vid' => variable_get('biblio_collection_vocabulary', 0),
+    );
+    taxonomy_save_term($default_collection);
+  }
+  return $vocabulary['vid'];
+*/
+}
+
+/**
+ * Copies keywords from the biblio_keyword column of the biblio table
+ * to a taxonomy vocabulary
+ *
+ * @return none
+ */
+function _add_biblio_keywords() {
+//TODO taxonomy
+/*
+  set_time_limit(300);
+  $kw_sep = variable_get('biblio_keyword_sep', ',');
+  $vid = ($vid = variable_get('biblio_keyword_vocabulary', 0))? $vid:_enable_biblio_keyword_vocabulary();
+  if ($vid ) {
+    $db_result  = db_query("SELECT b.biblio_keywords, b.nid, b.vid FROM {biblio} b");
+    $result = array();
+    foreach ($db_result as $row) {
+      foreach (explode($kw_sep, $row->biblio_keywords) as $keyword) {
+        $result[] = array('value' => trim($keyword), 'nid' => $row->nid, 'vid' => $row->vid);
+      }
+      db_query('DELETE tn.* FROM {term_node} tn INNER JOIN {term_data} td ON tn.tid = td.tid WHERE nid = %d AND td.vid = %d', $row->nid, $vid);
+    }
+    $inserted = array();
+    $count = 0;
+    foreach ($result as $keywords) {
+      // See if the term exists in the chosen vocabulary
+      // and return the tid; otherwise, add a new record.
+      $possibilities = taxonomy_get_term_by_name($keywords['value']);
+      $term_tid = NULL; // tid match, if any.
+      foreach ($possibilities as $possibility) {
+        if ($possibility->vid == $vid) {
+          $term_tid = $possibility->tid;
+        }
+      }
+
+      if (!$term_tid) {
+        $term = array('vid' => $vid, 'name' => $keywords['value']);
+        $status = taxonomy_save_term($term);
+        $term_tid = $term['tid'];
+      }
+
+      // Defend against duplicate, differently cased tags
+      if (!isset($inserted[$keywords['vid']][$term_tid])) {
+        db_query('INSERT INTO {term_node} (nid, vid, tid) VALUES (%d, %d, %d)', $keywords['nid'], $keywords['vid'], $term_tid);
+        $inserted[$keywords['vid']][$term_tid] = TRUE;
+        $count++;
+      }
+    }
+    return array('success' => TRUE, 'query' => 'Added ' . $count . ' keywords to the biblio/taxonomy keyword vocabulary');
+  }
+  return array('success' => FALSE, 'query' => 'Biblio keyword vocabulary not available');
+*/
+}
+
+function biblio_schema() {
+  $schema['biblio'] = array(
+    'fields' => array(
+      'nid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => '',
+      ),
+      'vid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => '',
+      ),
+      'biblio_type' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => '',
+      ),
+      'biblio_number' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_other_number' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_sort_title' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '64',
+        'description' => 'A normalized version of the title, used for sorting on titles. (only first 64 characters saved)',
+      ),
+      'biblio_secondary_title' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_tertiary_title' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_edition' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_publisher' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_place_published' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_year' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 9999,
+        'description' => '',
+      ),
+      'biblio_volume' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_pages' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_date' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '64',
+        'description' => '',
+      ),
+      'biblio_isbn' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_lang' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '24',
+        'default' => 'eng',
+        'description' => '',
+      ),
+      'biblio_abst_e' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_abst_f' => array(
+        'not null' => FALSE,
+        'type' => 'text',
+        'description' => '',
+      ),
+      'biblio_full_text' => array(
+        'type' => 'int',
+        'not null' => FALSE,
+        'default' => 0,
+        'description' => '',
+      ),
+      'biblio_url' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_issue' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_type_of_work' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_accession_number' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_call_number' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_notes' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_custom1' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_custom2' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_custom3' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_custom4' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_custom5' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_custom6' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_custom7' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_research_notes' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_number_of_volumes' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_short_title' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_alternate_title' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_original_publication' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_reprint_edition' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_translated_title' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_section' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_citekey' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_coins' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_doi' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_issn' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '128',
+        'description' => '',
+      ),
+      'biblio_auth_address' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'description' => '',
+      ),
+      'biblio_remote_db_name' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_remote_db_provider' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_label' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_access_date' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => '',
+      ),
+      'biblio_refereed' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '20',
+        'description' => '',
+      ),
+      'biblio_md5' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '32',
+        'description' => '',
+      ),
+      'biblio_formats' => array(
+        'type' => 'blob',
+        'not null' => FALSE,
+        'description' => '',
+        'serialize' => TRUE,
+      ),
+    ),
+    'foreign keys' => array(
+      'node_revision' => array(
+        'table' => 'node_revision',
+        'columns' => array('vid' => 'vid'),
+       ),
+      'node' => array(
+        'table' => 'node',
+        'columns' => array('nid' => 'nid'),
+       ),
+      'biblio_type' => array(
+        'table' => 'biblio_types',
+        'columns' => array('biblio_type' => 'tid'),
+       ),
+     ),
+     'primary key' => array(
+      'vid'
+      ),
+    'indexes' => array(
+      'nid' => array('nid'),
+      'md5' => array('biblio_md5'),
+      'year' => array('biblio_year'),
+      'title_sort' => array('biblio_sort_title'),
+      'date' => array('biblio_date')
+      ),
+    );
+
+   $schema['biblio_fields'] = array(
+    'fields' => array(
+      'fid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+          'unsigned' => TRUE,
+        'default' => 0,
+        'description' => '{biblio_fields}.fid of the node',
+        ),
+      'name' => array(
+        'type' => 'varchar',
+        'length' => '128',
+        'not null' => TRUE,
+        'default' => ''
+        ),
+      'type' => array(
+        'type' => 'varchar',
+        'length' => '128',
+        'not null' => TRUE,
+        'default' => 'textfield'
+        ),
+      'size' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 60,
+        ),
+      'maxsize' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 255,
+        ),
+        ),
+      'primary key' => array('fid'),
+        );
+
+   $schema['biblio_field_type'] = array(
+    'description' => 'Relational table linking {biblio_fields} with {biblio_field_type_data}',
+    'fields' => array(
+      'tid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        'description' => '{biblio_types}.tid of the node',
+        ),
+      'fid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        'description' => '{biblio_fields}.fid of the node',
+        ),
+      'ftdid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        'description' => '{biblio_field_type_data}.ftdid of the node, points to the current data, default or custom',
+        ),
+      'cust_tdid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        'description' => 'This always points to the custom data for this field. Stored so we can switch back an forth between default and custom',
+        ),
+      'common' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        ),
+      'vtab' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        ),
+      'autocomplete' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        ),
+        'required' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        'description' => 'Is input required for this field'
+        ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The weight (location) of the field on the input form'
+        ),
+      'visible' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+        'description' => 'Determines if the field is visible on the input form'
+        ),
+
+        ),
+    'primary key' => array('tid', 'fid'),
+    'indexes' => array(
+      'tid' => array('tid')
+        ),
+        );
+
+   $schema['biblio_field_type_data'] = array(
+    'description' => 'Data used to build the form elements on the input form',
+    'fields' => array(
+      'ftdid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+          'unsigned' => TRUE,
+        'default' => 0,
+        'description' => '{biblio_field_type_data}.ftdid of the node',
+        ),
+      'title' => array(
+        'type' => 'varchar',
+        'length' => '128',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The title, which will be displayed on the form, for a given field'
+        ),
+      'hint' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+        'description' => 'The hint text printed below the input widget'
+        ),
+        ),
+    'primary key' => array('ftdid'),
+        );
+
+  $schema['biblio_types'] = array(
+    'fields' => array(
+        'tid' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => '{biblio_types}.tid of the publication type',
+        ),
+      'name' => array(
+        'type' => 'varchar',
+        'length' => '64',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The name of the publication type'
+        ),
+      'description' => array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '255',
+        'description' => 'Description of the publication type'
+        ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Controls the order the types are listed in'
+        ),
+      'visible' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 1,
+        'description' => 'Determines if the publication type is visible in the list'
+        ),
+        ),
+      'primary key' => array('tid'),
+
+        );
+
+
+
+ $schema['biblio_contributor'] = array(
+  'description' => 'Relational table linking authors to biblio entries',
+  'fields' => array(
+    'nid' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'unsigned' => TRUE,
+      'default' => 0,
+      'description' => '{node}.nid of the node',
+    ),
+    'vid' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'unsigned' => TRUE,
+      'default' => 0,
+      'description' => '{node}.vid of the node',
+    ),
+    'cid' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'unsigned' => TRUE,
+      'default' => 0,
+      'description' => '{biblio_contributor_data}.cid of the node',
+    ),
+    'auth_type' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'unsigned' => TRUE,
+      'default' => 1,
+      'description' => '{biblio_contributor_type}.auth_type of the node',
+    ),
+    'auth_category' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'unsigned' => TRUE,
+      'default' => 1,
+      'description' => '',
+    ),
+    'rank' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'unsigned' => TRUE,
+      'default' => 0,
+      'description' => 'Position of the author name on the publication (first,second,third...)',
+    ),
+    'merge_cid' =>  array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'default'  => 0,
+      'unsigned' => TRUE,
+      'description' => '',
+    ),
+   ),
+   'foreign keys' => array(
+     'node_revision' => array(
+       'table' => 'node_revision',
+       'columns' => array('vid' => 'vid'),
+     ),
+     'node' => array(
+       'table' => 'node',
+       'columns' => array('nid' => 'nid'),
+     ),
+     'biblio_contributor_data' => array(
+       'table' => 'biblio_contributor_data',
+       'columns' => array('cid' => 'cid'),
+     ),
+     'biblio_contributor_type' => array(
+       'table' => 'biblio_contributor_type',
+       'columns' => array('auth_type' => 'auth_type'),
+     ),
+      'biblio_contributor_category' => array(
+       'table' => 'biblio_contributor_type',
+       'columns' => array('auth_category' => 'auth_category'),
+     ),
+   ),
+   'primary key' => array(
+       'vid',
+       'cid',
+       'auth_type',
+       'rank'
+    ),
+   );
+
+  $schema['biblio_contributor_data'] = array(
+    'description' => 'Contains Author information for each publication',
+    'fields' => array(
+      'cid' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'description' => 'Primary Key: Author ID',
+        ),
+      'aka' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default'  => 0,
+        'unsigned' => TRUE,
+        'description' => 'Also known as, links this author entry with others so you can have variation on the name, but listing by cid will find all other (aka) author entries',
+        ),
+      'alt_form' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default'  => 0,
+        'unsigned' => TRUE,
+        'description' => 'Alternate form of an author name, this value points to the desired form (cid), this form is kept in the database so  that future imports of the same name will not create a new author.',
+        ),
+      'drupal_uid' => array(
+        'type' => 'int',
+        'not null' => FALSE,
+        'unsigned' => TRUE,
+        'description' => 'Drupal User ID',
+        ),
+      'name' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Full name',
+        ),
+      'lastname' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Author last name',
+        ),
+      'firstname' => array(
+        'type' => 'varchar',
+        'length' => '128',
+        'not null' => FALSE,
+        'default' => '',
+        'description' => 'Author first name',
+        ),
+      'prefix' => array(
+        'type' => 'varchar',
+        'length' => '128',
+        'not null' => FALSE,
+        'default' => '',
+        'description' => 'Author name prefix',
+        ),
+      'suffix' => array(
+        'type' => 'varchar',
+        'length' => '128',
+        'not null' => FALSE,
+        'default' => '',
+        'description' => 'Author name suffix',
+        ),
+      'initials' => array(
+        'type' => 'varchar',
+        'length' => '10',
+        'not null' => FALSE,
+        'default' => '',
+        'description' => 'Author initials (including first name initial)',
+        ),
+      'affiliation' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+        'default' => '',
+        'description' => 'Author affiliation or address',
+        ),
+      'literal' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default'  => 0,
+        'unsigned' => TRUE,
+        'description' => 'Determines if the author name is allowed to be reformated by the variaous styles or should be used literally.',
+        ),
+      'md5' => array(
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => FALSE,
+        'description' => '',
+        )
+      ),
+    'foreign keys' => array(
+      'biblio_contributor' => array(
+        'table' => 'biblio_contributor',
+        'columns' => array('cid' => 'cid'),
+       ),
+      'node_author' => array(
+        'table' => 'users',
+        'columns' => array('drupal_uid' => 'uid'),
+      ),
+     ),
+    'primary key' => array('cid'),
+    'indexes' => array(
+      'lastname' => array('lastname'),
+      'firstname' => array('firstname'),
+      'initials' => array('initials')
+     )
+    );
+    $schema['biblio_contributor_type'] = array(
+      'description' => 'Contains definitions of the contributor types',
+      'fields' => array(
+        'auth_category' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'There are 5 catagoies of author: Primary, Secondary, Tertiery, Subsidary and Corporate  ',
+        ),
+        'biblio_type' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => '',
+        ),
+        'auth_type' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'This is the pulication type specific verion of a particular catagory',
+        ),
+    ),
+    'foreign keys' => array(
+       'biblio' => array(
+         'table' => 'biblio',
+         'columns' => array('biblio_type' => 'biblio_type'),
+       ),
+       'biblio_contributor_type' => array(
+         'table' => 'biblio_contributor',
+         'columns' => array('auth_type' => 'auth_type'),
+       ),
+      'biblio_contributor_category' => array(
+         'table' => 'biblio_contributor',
+         'columns' => array('auth_category' => 'auth_category'),
+       ),
+     ),
+     'primary key' => array('auth_category', 'biblio_type', 'auth_type'),
+   );
+
+  $schema['biblio_contributor_type_data'] = array(
+    'description' => 'Data used to build the form elements on the input form',
+    'fields' => array(
+      'auth_type' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'description' => '{biblio_contributor_type_data} ctdid of the node',
+      ),
+      'title' => array(
+        'type' => 'varchar',
+        'length' => '128',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The title, which will be displayed on the form, for a given field'
+      ),
+      'hint' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+        'description' => 'The hint text printed below the input widget'
+      ),
+    ),
+    'primary key' => array('auth_type'),
+   );
+
+    $schema['biblio_keyword'] = array(
+      'description' => 'Relational table linking keywords to biblio nodes',
+      'fields' => array(
+        'kid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'Primary Key: The {biblio_keyword_data}.kid of the keyword of the node.',
+        ),
+        'nid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'The {node}.nid of the node.',
+        ),
+        'vid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'Primary Key: The {node}.vid of the node.',
+        ),
+    ),
+    'foreign keys' => array(
+     'node_revision' => array(
+       'table' => 'node_revision',
+       'columns' => array('vid' => 'vid'),
+     ),
+     'node' => array(
+       'table' => 'node',
+       'columns' => array('nid' => 'nid'),
+     ),
+     'keyword' => array(
+       'table' => 'biblio_keyword_data',
+       'columns' => array('kid' => 'kid'),
+     ),
+    ),
+    'primary key' => array('kid', 'vid'),
+      'indexes' => array(
+           'vid' => array('vid'),
+           'nid' => array('nid'),
+        ),
+        );
+
+     $schema['biblio_keyword_data'] = array(
+      'description' => 'Stores the keywords related to nodes.',
+      'fields' => array(
+        'kid' => array(
+          'type' => 'serial',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'description' => 'Primary Key: The id of the keyword assigned to the node',
+        ),
+        'word' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'The keyword',
+        ),
+        ),
+      'primary key' => array('kid'),
+      'indexes' => array(
+           'kword' => array('word'),
+        ),
+        );
+     $schema['biblio_collection'] = array(
+      'description' => 'Relational table grouping biblio nodes into collections',
+      'fields' => array(
+        'cid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'Primary Key: The {biblio_collection_data}.cid of the collection',
+        ),
+        'vid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'Primary Key: The {node}.vid of the node.',
+        ),
+        'pid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'The parent id of the collection',
+        ),
+        'nid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'The {node}.nid of the node.',
+        ),
+        ),
+      'primary key' => array('cid', 'vid'),
+      'indexes' => array(
+           'pid' => array('pid'),
+           'nid' => array('nid'),
+        ),
+        );
+     $schema['biblio_collection_type'] = array(
+      'description' => 'Descriptions of the collections.',
+      'fields' => array(
+        'cid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'Primary Key: The id of the collection',
+        ),
+        'name' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'The name of the collection',
+        ),
+        'description' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'The description of the collection',
+        ),
+        ),
+      'primary key' => array('cid'),
+      'indexes' => array(
+           'name' => array('name'),
+        ),
+        );
+    $schema['biblio_duplicates'] = array(
+      'description' => 'Relational table linking possible duplicate biblio nodes',
+      'fields' => array(
+        'vid' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'Primary Key: The {biblio}.nid of the original node',
+        ),
+        'did' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'The {biblio}.nid of the newly imported node which may be a duplicate.',
+        ),
+        'type' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => 'The type of duplicate 0=biblio, 1=author.',
+        ),
+        ),
+      'primary key' => array('vid', 'did'),
+        'indexes' => array(
+           'did' => array('vid'),
+        ),
+        );
+
+      $schema['biblio_import_cache'] = array(
+        'description' => 'tables used for caching data imported from file and then batch processed',
+        'fields' => array(
+          'id' => array(
+            'type' => 'serial',
+            'not null' => TRUE,
+            'unsigned' => TRUE),
+          'session_id' => array(
+            'type' => 'varchar',
+            'length' => 45,
+            'not null' => TRUE),
+          'data' => array(
+            'description' => 'A collection of data to cache.',
+            'type' => 'blob',
+            'not null' => FALSE,
+            'size' => 'big'),
+        ),
+        'primary key' => array('id'));
+
+  $schema['biblio_type_maps'] = array(
+    'description' => 'Table used to store the mapping information between various file formats and the biblio schema',
+    'fields' => array(
+      'format' => array(
+        'description' => 'The import/export file format',
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE),
+      'type_map' => array(
+        'description' => 'The mapping between the publication types in the file format and biblio',
+        'type' => 'blob',
+        'not null' => FALSE,
+        'size' => 'big'),
+      'type_names' => array(
+        'description' => 'The human readable names of the publication types',
+        'type' => 'blob',
+        'not null' => FALSE,
+        'size' => 'big'),
+      'field_map' => array(
+        'description' => 'The mapping between the fields in the file format and biblio',
+        'type' => 'blob',
+        'not null' => FALSE,
+        'size' => 'big'),
+      'export_map' => array(
+        'description' => 'which fields are exported',
+        'type' => 'blob',
+        'not null' => FALSE,
+        'size' => 'big'),
+      ),
+    'primary key' => array('format'));
+
+   $schema['biblio_vtabs'] = array(
+    'description' => 'Table used to store the information to create the vertical tabs on the input form',
+    'fields' => array(
+        'tab_id' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => ''
+        ),
+        'weight' => array(
+          'type' => 'int',
+          'not null' => TRUE,
+          'unsigned' => TRUE,
+          'default' => 0,
+          'description' => ''
+        ),
+        'title' => array(
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'The title of the tab',
+        ),
+        'description' => array(
+          'type' => 'varchar',
+          'length' => 255,
+          'not null' => TRUE,
+          'default' => '',
+          'description' => 'The description of the tab',
+        ),
+    ),
+    'primary key' => array('tab_id'));
+
+   return ($schema);
+
+}
+
+function biblio_reset_types() {
+  $result = array();
+
+  db_drop_table('biblio_field_type_data');
+  db_drop_table('biblio_field_type');
+  db_drop_table('biblio_fields');
+  db_drop_table('biblio_contributor_type');
+  db_drop_table('biblio_contributor_type_data');
+
+  db_query('DELETE FROM {biblio_types} WHERE tid>999');
+  db_query('UPDATE {biblio_types} SET visible=1 WHERE visible=0');
+
+  $schema = biblio_schema();
+  db_create_table('biblio_field_type_data', $schema['biblio_field_type_data']);
+  db_create_table('biblio_field_type', $schema['biblio_field_type']);
+  db_create_table('biblio_fields', $schema['biblio_fields']);
+  db_create_table('biblio_contributor_type', $schema['biblio_contributor_type']);
+  db_create_table('biblio_contributor_type_data', $schema['biblio_contributor_type_data']);
+
+  variable_set('biblio_last_ftdid', 100); // reset custom field type id too
+  //_add_db_field_data_XML();
+  _add_db_field_data();
+  _add_custom_field_data();
+}
+
+function _biblio_add_vtabs() {
+  $vtabs = array(
+    array('tab_id' => 1, 'weight' => 1, 'title' => 'Authors', 'description' => ''),
+    array('tab_id' => 2, 'weight' => 2, 'title' => 'Publication', 'description' => ''),
+    array('tab_id' => 3, 'weight' => 3, 'title' => 'Publisher', 'description' => ''),
+    array('tab_id' => 4, 'weight' => 4, 'title' => 'Identifiers', 'description' => ''),
+    array('tab_id' => 5, 'weight' => 5, 'title' => 'Locators', 'description' => 'URL\'s etc'),
+    array('tab_id' => 6, 'weight' => 6, 'title' => 'Keywords', 'description' => ''),
+    array('tab_id' => 7, 'weight' => 7, 'title' => 'Notes', 'description' => ''),
+    array('tab_id' => 8, 'weight' => 8, 'title' => 'Alternate Titles', 'description' => ''),
+    array('tab_id' => 9, 'weight' => 9, 'title' => 'Other', 'description' => ''),
+    );
+
+  foreach ($vtabs as $record) {
+   db_insert('biblio_vtabs')->fields($record)->execute();
+  }
+
+
+}
+
+function _add_publication_types() {
+  $types[] = array(100, 'Book', NULL, 1);
+  $types[] = array(101, 'Book Chapter', NULL, 2);
+  $types[] = array(102, 'Journal Article', NULL, 3);
+  $types[] = array(131, 'Journal', NULL, 3);
+  $types[] = array(103, 'Conference Paper', NULL, 4);
+  $types[] = array(104, 'Conference Proceedings', NULL, 5);
+  $types[] = array(105, 'Newspaper Article', NULL, 6);
+  $types[] = array(106, 'Magazine Article', NULL, 7);
+  $types[] = array(107, 'Web Article', NULL, 8);
+  $types[] = array(132, 'Website', NULL, 8);
+  $types[] = array(133, 'Web service', NULL, 8);
+  $types[] = array(134, 'Web project page', NULL, 8);
+  $types[] = array(108, 'Thesis', NULL, 9);
+  $types[] = array(109, 'Report', NULL, 10);
+  $types[] = array(110, 'Film', NULL, 11);
+  $types[] = array(111, 'Broadcast', NULL, 12);
+  $types[] = array(112, 'Artwork', NULL, 13);
+  $types[] = array(113, 'Software', NULL, 14);
+  $types[] = array(114, 'Audiovisual', NULL, 15);
+  $types[] = array(115, 'Hearing', NULL, 16);
+  $types[] = array(116, 'Case', NULL, 17);
+  $types[] = array(117, 'Bill', NULL, 18);
+  $types[] = array(118, 'Statute', NULL, 19);
+  $types[] = array(119, 'Patent', NULL, 20);
+  $types[] = array(120, 'Personal', NULL, 21);
+  $types[] = array(121, 'Manuscript', NULL, 22);
+  $types[] = array(122, 'Map', NULL, 23);
+  $types[] = array(123, 'Chart', NULL, 24);
+  $types[] = array(124, 'Unpublished', NULL, 25);
+  $types[] = array(125, 'Database', NULL, 26);
+  $types[] = array(126, 'Government Report', NULL, 27);
+  $types[] = array(127, 'Classical'  , NULL, 28);
+  $types[] = array(128, 'Legal Ruling', NULL, 29);
+  $types[] = array(129, 'Miscellaneous', NULL, 30);
+  $types[] = array(130, 'Miscellaneous Section', NULL, 31);
+  $types[] = array(135,'Presentation', NULL, 8);
+
+  foreach ($types as $record) {
+      db_insert('biblio_types')->fields(array(
+          'tid'           => $record[0],
+          'name'          => $record[1],
+          'description'   => $record[2],
+          'weight'        => $record[3],
+        ))->execute();
+
+  }
+ return;
+}
+
+function _add_db_field_data_XML() {
+  $next_ctdid=10; //first contributor_type_data id
+  $schema = biblio_schema();
+  $fieldnames = array_keys($schema['biblio_fields']['fields']);
+  $field_type_fieldnames = array_keys($schema['biblio_field_type']['fields']);
+  $field_type_data_fieldnames = array_keys($schema['biblio_field_type_data']['fields']);
+  db_query("/*!40000 ALTER TABLE {biblio_field_type_data} DISABLE KEYS */;");
+  db_query("/*!40000 ALTER TABLE {biblio_fields} DISABLE KEYS */;");
+  for ($type = 1; $type <= 5; $type++) {
+    for ($biblio_type = 100; $biblio_type <= 130; $biblio_type++) {
+      db_query("INSERT INTO {biblio_contributor_type} (auth_category, biblio_type, auth_type) VALUES (%d, %d, %d)",  $type, $biblio_type, $type);
+    }
+  }
+  _id_by_name(NULL, NULL, NULL, array('tablename' => 'biblio_field_type_data', 'name_column' => 'title', 'id_column' => 'ftdid'));
+
+  $xml_file = drupal_get_path('module', 'biblio') . '/field_data.xml';
+  $xml = simplexml_load_file($xml_file);
+  foreach ($xml->field as $field) {
+    $link_data = array(0, $field['fid'], $field['fid'], $field['fid'], $field->common, $field->autocomplete, $field->required, $field->weight, $field->visible);
+    db_query("INSERT INTO {biblio_field_type} (" . implode(", ", $field_type_fieldnames) . ")
+                  VALUES (%d, %d, %d, %d, %d, %d, %d, %d, %d)", $link_data);
+    for ($t = 100; $t <= 130; $t++) {
+      $values = array($t, $field['fid'], $field['fid'], $field['fid'], $field->common, $field->autocomplete, $field->required, $field->weight, $field->visible);
+      db_query("INSERT INTO {biblio_field_type} (" . implode(", ", $field_type_fieldnames) . ")
+                      VALUES('" . implode("', '", $values) . "')");
+    }
+    $ftd = array($field['fid'], $field->default_name, $field->hint);
+    db_query("INSERT INTO {biblio_field_type_data} (" . implode(", ", $field_type_data_fieldnames) . ")
+                    VALUES('" . implode("', '", $ftd) . "')");
+    $field_data = array($field['fid'], $field->field_name, $field->type, $field->width, $field->maxlength);
+    db_query("INSERT INTO {biblio_fields} (" . implode(", ", $fieldnames) . ")
+                    VALUES('" . implode("', '", $field_data) . "')");
+    foreach ($field->name as $name) {
+      if ($name != "~" ) { //&& $field->type != 'contrib_widget') {
+        $ftd[0] = ($existing_id = _id_by_name('biblio_field_type_data', $name)) ? $existing_id : variable_get('biblio_last_ftdid', 100); // ftdid
+        $ftd[1] = trim($name);                          // title
+        $ftd[2] = "";                                     // hint
+        db_query("UPDATE {biblio_field_type}
+                      SET ftdid = %d, cust_tdid = %d, visible = %d
+                      WHERE tid = %d AND fid = %d ", $ftd[0], $ftd[0], 1, $name['tid'], $field['fid'] );
+        if (!$existing_id) {
+          // if this title doesn't alreay exist, then insert it into the table
+          db_query("INSERT INTO {biblio_field_type_data} (" . implode(", ", $field_type_data_fieldnames) . ")
+                        VALUES (%d, '%s', '%s')", $ftd);
+          _id_by_name('biblio_field_type_data', $name, $ftd[0]);  // cache the new id value for future use
+          variable_set('biblio_last_ftdid', $ftd[0] +1); //increment the field type data id by one.
+        }
+
+      }
+      elseif ($name == "~" ) {
+        // turn the visibility off for this (~) type
+        db_query("UPDATE {biblio_field_type}
+                      SET visible = 0
+                      WHERE tid = %d AND fid = %d ", $name['tid'], $field['fid'] );
+      }
+      if ($field->type == 'contrib_widget' && $name != "~" ) {
+          db_query("UPDATE {biblio_contributor_type} SET auth_type=%d where auth_category=%d and biblio_type=%d", $ftd[0], $field->contrib_type, $name['tid']);
+      }
+    }
+  }
+
+
+
+  db_query("/*!40000 ALTER TABLE {biblio_field_type_data} ENABLE KEYS */;");
+  db_query("/*!40000 ALTER TABLE {biblio_fields} ENABLE KEYS */;");
+
+  return $result;
+}
+
+function _add_db_field_data() {
+  if (db_driver() == 'mysql' or db_driver() == 'mysqli') {
+    db_query("/*!40000 ALTER TABLE {biblio_field_type_data} DISABLE KEYS */;");
+    db_query("/*!40000 ALTER TABLE {biblio_fields} DISABLE KEYS */;");
+  }
+  $csv_file = drupal_get_path('module', 'biblio') . '/misc/biblio.field.link.data.csv';
+
+  if ($handle = fopen($csv_file, "r")) {
+    $header = fgetcsv($handle, 10000, ","); // the first line has the field names
+    while (($row = fgetcsv($handle, 10000, ",")) !== FALSE) {
+      $column = 0;
+      // add link data for default biblio type (0) and all other defined types (100-130)
+      foreach (array_merge(array(0), range(100, 136)) as $t) {
+        db_insert('biblio_field_type')->fields(array(
+          'tid'          => $t,
+          'fid'          => $row[0],
+          'ftdid'        => $row[0],
+          'cust_tdid'    => $row[0],
+          'common'       => $row[3],
+          'autocomplete' => $row[4],
+          'required'     => $row[5],
+          'weight'       => $row[6],
+          'visible'      => $row[7],
+          'vtab'         => $row[12]
+        ))->execute();
+      }
+
+      db_insert('biblio_field_type_data')->fields(array(
+        'ftdid' => $row[0],
+        'title' => $row[1],
+        'hint'  => $row[2]
+      ))->execute();
+
+      db_insert('biblio_fields')->fields(array(
+        'fid'     => $row[0],
+        'name'    => $row[8],
+        'type'    => $row[9],
+        'size'    => $row[10],
+        'maxsize' => $row[11]
+      ))->execute();
+
+      // add contributor type data
+      if ($row[9] == 'contrib_widget') {
+        // use field name without trailing 's' as initial guess for author type
+        $auth_type = (substr($row[1], -1, 1) == 's') ? substr($row[1], 0, -1) : $row[1];
+
+        db_insert('biblio_contributor_type_data')->fields(array(
+          'auth_type' => $row[0],
+          'title'     => $auth_type
+        ))->execute();
+
+        db_insert('biblio_contributor_type')->fields(array(
+          'auth_category' => $row[0],
+          'biblio_type'   => 0,
+          'auth_type'     => $row[0]
+        ))->execute();
+      }
+    }
+    fclose($handle);
+    $result = array('success' => TRUE, 'query' => 'Added field titles and default values');
+
+  }
+  else {
+    $result = array('success' => FALSE, 'query' => 'Could not open ' . $csv_file);
+  }
+
+  if (db_driver() == 'mysql' or db_driver() == 'mysqli') {
+    db_query("/*!40000 ALTER TABLE {biblio_field_type_data} ENABLE KEYS */;");
+    db_query("/*!40000 ALTER TABLE {biblio_fields} ENABLE KEYS */;");
+  }
+  return $result;
+}
+
+function _add_custom_field_data() {
+
+  $next_ctdid=10; //first contributor_type_data id
+  $schema = biblio_schema();
+  $fieldnames = array_keys($schema['biblio_field_type_data']['fields']);
+
+  $query = "SELECT fid, name FROM {biblio_fields} ";
+  $res = db_query($query);
+  foreach ($res as $row) {
+    $fieldmap[$row->name] =  $row->fid;
+  }
+
+  $csv_file = drupal_get_path('module', 'biblio') . '/misc/biblio.field.type.data.csv';
+
+  if ($handle = fopen($csv_file, "r")) {
+    $header = fgetcsv($handle, 10000, ","); // the first line has the field names
+    $generic = fgetcsv($handle, 10000, ","); // the second line has the default titles if none given
+    // build cache lookups
+    _id_by_name(NULL, NULL, NULL, array('tablename' => 'biblio_field_type_data', 'name_column' => 'title', 'id_column' => 'ftdid'));
+    _id_by_name(NULL, NULL, NULL, array('tablename' => 'biblio_contributor_type_data', 'name_column' => 'title', 'id_column' => 'auth_type'));
+    // map contributor field titles to field ids
+    $res = db_query("SELECT fid,name FROM {biblio_fields} WHERE type='contrib_widget'");
+    $contributor_categories = array();
+    foreach ($res as $row ) {
+      $contributor_categories[$row->name] = $row->fid;
+    }
+    // process all rows of the file
+    while (($row = fgetcsv($handle, 10000, ",")) !== FALSE) {
+      $column = 0;
+      if (empty($row[1])) continue;
+
+      foreach ($header as $key => $field_name) {
+        if (!empty($field_name) && $field_name != 'tid') {
+          if (!empty($row[$column]) && $row[$column] != "~" && isset($fieldmap[$field_name])) {
+             $ftd[0] = ($existing_id = _id_by_name('biblio_field_type_data', $row[$column])) ? $existing_id : variable_get('biblio_last_ftdid', 100); // ftdid
+             $ftd[1] = trim($row[$column]);                    // title
+             $ftd[2] = "";                                     // hint
+
+             db_update('biblio_field_type')
+               ->fields(array( 'ftdid' => $ftd[0], 'cust_tdid' => $ftd[0], 'visible'   => 1))
+               ->condition(db_and()->condition('tid', $row[1])->condition('fid', $fieldmap[$field_name]))
+               ->execute();
+
+             if (!$existing_id) {
+               // if this title doesn't alreay exist, then insert it into the table
+              db_insert('biblio_field_type_data')
+              ->fields(array('ftdid' => $ftd[0], 'title' => $ftd[1], 'hint'  => $ftd[2]))
+              ->execute();
+
+               _id_by_name('biblio_field_type_data', $row[$column], $ftd[0]);  // cache the new id value for future use
+              variable_set('biblio_last_ftdid', $ftd[0] +1); //increment the field type data id by one.
+             }
+
+             // also populate biblio_contributor_type tables
+             if ((substr($field_name, -7, 7) == 'authors') && $row[$column] != '~' ) {
+               $type = $contributor_categories[$field_name];
+              $title = trim($row[$column]);
+              $biblio_type = $row[1];
+              $ctdid = ($eid = _id_by_name('biblio_contributor_type_data', $title)) ? $eid :  $next_ctdid;
+              db_update('biblio_contributor_type')
+                ->fields(array(
+                  'auth_type' => $ctdid))
+                ->condition(db_and()->condition('auth_category', $type)->condition('biblio_type', $biblio_type))
+                ->execute();
+
+              if (!$eid) {
+                db_insert('biblio_contributor_type_data')
+                  ->fields(array('auth_type' => $ctdid, 'title' => $title))
+                  ->execute();
+
+                _id_by_name('biblio_contributor_type_data', $title, $ctdid);  // cache the new id value for future use
+                $next_ctdid++;
+              }
+             }
+          }
+          elseif ($row[$column] == "~" && isset($fieldmap[$field_name])) {
+            // turn the visibility off for this (~) type
+
+            db_update('biblio_field_type')
+              ->fields(array('visible' => 0))
+              ->condition(db_and()->condition('tid', $row[1])->condition('fid', $fieldmap[$field_name]))
+              ->execute();
+
+          }
+          elseif (empty($row[$column]) && isset($fieldmap[$field_name])) {
+            // use the default field title when the title is blank
+            db_update('biblio_field_type')
+              ->fields(array('visible' => 1))
+              ->condition(db_and()->condition('tid', $row[1])->condition('fid', $fieldmap[$field_name]))
+              ->execute();
+          }
+        }
+        $column++;
+      }
+    }
+    fclose($handle);
+    $result = array('success' => TRUE, 'query' => 'Added type specific field titles');
+  }
+  else {
+    $result = array('success' => FALSE, 'query' => 'Could not open ' . $csv_file);
+  }
+
+  return $result;
+}
+function _id_by_name($table, $name, $id = NULL, $build = NULL) {
+  static $result = NULL;
+  if (!empty($build)) { //refresh cache from table
+    unset($result[$build['tablename']]);
+    $res = db_query("SELECT " . $build['name_column'] . ", " . $build['id_column'] . " FROM {" . $build['tablename'] . "}", array(), array('fetch' => PDO::FETCH_ASSOC));
+    foreach ($res as $row ) {
+      $result[$build['tablename']][$row[$build['name_column']]] = $row[$build['id_column']];
+    }
+    return;
+  }
+  $name = trim($name);
+  if (isset($result[$table][$name])) return $result[$table][$name];
+  if ($id) $result[$table][$name] = $id;
+  return FALSE;
+}
+/*
+ * Removed updates 1 - 27 since they were from 5.x biblio
+ */
+
+/*
+ * Removed updates 6000 - 6023 only upgrades from  biblio 6.x-1.9 are supported
+ */
+/* add the new field -refereed- on the biblio table
+*/
+function biblio_update_6024() {
+
+  db_add_field('biblio', 'biblio_refereed', array('type' => 'varchar', 'length' => '20'));
+
+  /* add the field data for -refereed- on the biblo_fields table
+   you need to get the last inserted record from biblio_fields and increment it by one
+   so you don't step on customized fields added via the user online interface */
+
+  $sql = 'SELECT fid FROM {biblio_fields} ORDER BY fid DESC';
+  $lastfid = db_query_range($sql, 0, 1)->fetchField();
+  $newfid  = $lastfid + 1;
+
+  db_query("INSERT INTO {biblio_fields} (fid, name, type, size, maxsize) VALUES
+                        ($newfid, 'biblio_refereed', 'select', 0, 125)");
+
+  /*use the same fid and insert an entry in the biblio_field_type_data */
+  db_query("INSERT INTO {biblio_field_type_data}
+       (ftdid, title, hint) VALUES ($newfid, 'Refereed Designation', NULL)");
+
+  /* get a list of unique tids from the biblio_field_type table.  You want to
+   insert a tid,fid using the new fid for every available tid */
+
+  $newsql = "SELECT DISTINCT tid FROM {biblio_field_type} ORDER BY tid DESC";
+
+  $tidlist = db_query($newsql);
+  foreach ($tidlist as $tid) {
+    $newtid = $tid->tid ;
+    db_query('INSERT INTO {biblio_field_type}
+       (tid, fid, ftdid, cust_tdid, common, autocomplete, required, weight, visible)
+        VALUES (%d, %d, %d, %d, %d, %d, %d, %d, %d)',
+    $newtid, $newfid, $newfid, $newfid, 1, 1, 0, 1, 1);
+  }
+}
+
+function biblio_update_6025() {
+  $schema = biblio_schema();
+  db_create_table('biblio_type_maps', $schema['biblio_type_maps']);
+}
+
+function biblio_update_6026() {
+  // move custom block titles stored in variable "biblio_block_title" to the block table if the title has not already been overriden
+  $custom_title = variable_get('biblio_block_title', '');
+  if (!empty($custom_title)) {
+    $db_result = db_query("SELECT bid,title FROM {blocks} b where module='biblio' ");
+    foreach ($db_result as $block) {
+      if (empty ($block->title)) {
+        $block->title = $custom_title;
+        db_query("UPDATE {blocks} SET title='" . $block->title . "' WHERE bid=" . $block->bid);
+      }
+    }
+    variable_del('biblio_block_title');
+  }
+}
+
+function biblio_update_6027() {
+  // renunmber the author rank such that it is zero based accross all categories
+  // this only needs to be done for entries that actually have auth_categories other than 1
+  require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.contributors.inc');
+  $result =  array();
+  $count = 0;
+  $db_result = db_query("SELECT DISTINCT(vid),nid FROM {biblio_contributor} WHERE auth_category IN (2,3,4,5) ");
+  $count_success = db_query("SELECT COUNT(DISTINCT(vid)) FROM {biblio_contributor} WHERE auth_category IN (2,3,4,5) ")->fetchField();
+  foreach ($db_result as $node) {
+    $contributors = biblio_load_contributors($node->vid);
+    _save_contributors($contributors, $node->nid, $node->vid, $update = FALSE) ;
+    $count++;
+  }
+}
+
+function biblio_update_6028() {
+/*
+ *  Caching is not used in 7.x CiteProc
+ *
+  $table = drupal_get_schema_unprocessed('system', 'cache');
+  $table['description'] = 'Cache table for biblio to store pre-built csl objects';
+  $table['fields']['serialized']['default'] = 1;
+*/
+}
+
+function biblio_update_6029() {
+  $spec = array(
+        'type' => 'blob',
+        'not null' => FALSE,
+        'default'  => NULL,
+        'size' => 'big',
+        'description' => 'Stores the mapping between biblio fields and external file formats',
+        );
+  db_add_field('biblio_type_maps', 'export_map', $spec);
+}
+
+function biblio_update_6030() {
+
+  $spec = array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default'  => 0,
+        'unsigned' => TRUE,
+        'description' => 'Determines if the author name is allowed to be reformated by the variaous styles or should be used literally.',
+        );
+  db_add_field('biblio_contributor_data', 'literal', $spec);
+
+}
+
+function biblio_update_6031() {
+  $result = array();
+  $types[] = array(131, 'Journal', NULL, 3);
+  $types[] = array(132, 'Web site', NULL, 8);
+  $types[] = array(133, 'Web service','e.g. Google, Yahoo', 8);
+  $types[] = array(134, 'Web project page', NULL, 8);
+  $types[] = array(135, 'Presentation', NULL, 8);
+  $types[] = array(136, 'Newspaper', NULL, 8);
+
+  foreach ($types as $record) {
+    db_query("INSERT INTO {biblio_types} (tid, name, description, weight) VALUES ('" . implode("', '", $record) . "')");
+  }
+
+  db_query("DELETE FROM {biblio_types} WHERE tid=-1");
+
+ return $result;
+}
+
+function biblio_update_6032() {
+  $spec = array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Full name',
+        );
+  db_change_field('biblio_contributor_data', 'name', 'name', $spec);
+}
+function biblio_update_6033() {
+  $spec = array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '64',
+        'description' => 'A normalized version of the title, used for sorting on titles. (only first 64 characters saved)',
+  );
+  db_add_field('biblio', 'biblio_sort_title', $spec);
+}
+
+function biblio_update_7000() {
+
+  _biblio_helper_modules('install');
+
+}
+/**
+ * Add new column to biblio_contributor_data table
+ */
+function biblio_update_7001() {
+  if (!db_field_exists('biblio_contributor_data', 'literal')) {
+    $spec = array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default'  => 0,
+        'unsigned' => TRUE,
+        'description' => 'Determines if the author name is allowed to be reformated by the variaous styles or should be used literally.',
+        );
+    db_add_field('biblio_contributor_data', 'literal', $spec);
+  }
+}
+/**
+ *
+ * Adds export_map column to biblio_type_maps table
+ */
+function biblio_update_7002() {
+  if (!db_field_exists('biblio_type_maps', 'export_map')) {
+    biblio_update_6029();
+  }
+}
+/**
+ *
+ * Adds some new publication types
+ */
+function biblio_update_7003() {
+  $result = db_query('SELECT tid FROM {biblio_types} WHERE tid = :tid', array(':tid' => 136))->fetchField();
+  if (!$result) {
+    biblio_update_6031();
+  }
+}
+
+function _biblio_update_field_link_data($range, $vtabs = FALSE) {
+  $csv_file = drupal_get_path('module', 'biblio') . '/misc/biblio.field.link.data.csv';
+
+  if ($handle = fopen($csv_file, "r")) {
+    $header = fgetcsv($handle, 10000, ","); // the first line has the field names
+    while (($row = fgetcsv($handle, 10000, ",")) !== FALSE) {
+      if ($vtabs) {
+        // add link data for default biblio type (0) and all other defined types (100-130)
+        foreach (array_merge(array(0), range($range[0], $range[1])) as $t) {
+          db_update('biblio_field_type')
+          ->fields(array(
+                'vtab' => $row[12]
+          ))
+          ->condition(db_and()->condition('tid', $t)->condition('fid', $row[0]))
+          ->execute();
+        }
+      }
+      else {
+        foreach (range($range[0], $range[1]) as $t) {
+          db_insert('biblio_field_type')->fields(array(
+          'tid'          => $t,
+          'fid'          => $row[0],
+          'ftdid'        => $row[0],
+          'cust_tdid'    => $row[0],
+          'common'       => $row[3],
+          'autocomplete' => $row[4],
+          'required'     => $row[5],
+          'weight'       => $row[6],
+          'visible'      => $row[7],
+          'vtab'         => $row[12]
+          ))->execute();
+        }
+      }
+    }
+  }
+
+}
+
+/**
+ * Add information to manage vtabs on input form.
+*/
+function biblio_update_7005() {
+  $spec = array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+        'default' => 0,
+  );
+  db_add_field('biblio_field_type', 'vtab', $spec);
+  _biblio_update_field_link_data(array(100, 130), TRUE);
+  cache_clear_all();
+}
+
+function biblio_update_7006() {
+  $result = db_query('SELECT fid FROM {biblio_field_type} WHERE tid = :tid', array(':tid' => 136))->fetchField();
+  if (!$result) {
+    _biblio_update_field_link_data(array(131, 136));
+    cache_clear_all();
+  }
+}
+/**
+ * Increases the size of the {biblio_contributor_data}.name column to 255 characters
+*/
+function biblio_update_7007() {
+  $spec = array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Full name',
+        );
+  db_change_field('biblio_contributor_data', 'name', 'name', $spec);
+}
+/**
+ * Adds new "biblio_sort_title" column to the biblio table, which is used for title sorting.
+*/
+function biblio_update_7008() {
+  if (!db_field_exists('biblio', 'biblio_sort_title')) {
+    biblio_update_6033();
+  }
+}
+
+/**
+ * Populates the  new "biblio_sort_title" column, which is used for title sorting.
+*/
+function biblio_update_7009(&$sandbox) {
+  $sandbox['#finished'] = 0;
+  module_load_include('inc', 'biblio', '/includes/biblio.util');
+
+  if (!isset($sandbox['max'])) {
+    $sandbox['max'] = db_query('SELECT COUNT(DISTINCT vid) FROM {node} n WHERE n.type = :type', array(':type' => 'biblio'))->fetchField();
+    $sandbox['current_vid'] = 0;
+  }
+
+  $nodes = db_select('node', 'n')
+    ->fields('n', array('vid', 'title'))
+    ->condition('vid', $sandbox['current_vid'], '>')
+    ->condition('type', 'biblio')
+    ->range(0, 20)
+    ->orderBy('vid', 'ASC')
+    ->execute();
+
+  foreach ($nodes as $node) {
+    $node->biblio_sort_title = biblio_normalize_title($node->title);
+    db_update('biblio')
+      ->fields(array('biblio_sort_title' => $node->biblio_sort_title))
+      ->condition('vid', $node->vid)
+      ->execute();
+
+    $sandbox['progress']++;
+    $sandbox['current_vid'] = $node->vid;
+  }
+
+  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : ($sandbox['progress'] / $sandbox['max']);
+}
+/**
+ * Removes "biblio_inlinemode_in_links" variable
+ */
+function biblio_update_7010() {
+  variable_del('biblio_inlinemode_in_links');
+}
+/**
+ * Add a body field instance
+ */
+function biblio_update_7011() {
+  $content_type = node_type_load('biblio');
+  node_add_body_field($content_type, 'Full text');
+}
+/**
+ * Update biblio_field_type table
+ */
+function biblio_update_7012() {
+
+  // there was a problem with update 7006 and it might no have done anything so lets try again.
+  biblio_update_7006();
+}
+
+function biblio_update_7013() {
+  db_add_index('biblio', 'title_sort', array('biblio_sort_title'));
+  db_add_index('biblio', 'date', array('biblio_date'));
+
+}
+
+/**
+ *
+ * Widen the biblio_date column to 64 characters
+ */
+function biblio_update_7014() {
+  $spec =  array(
+        'type' => 'varchar',
+        'not null' => FALSE,
+        'length' => '64',
+        'description' => '',
+  );
+  db_change_field('biblio', 'biblio_date', 'biblio_date', $spec);
+
+}
+/**
+ *
+ * Add biblio_formats column to biblio table to hold the format information for each text area
+ */
+function biblio_update_7015() {
+  if (!db_field_exists('biblio', 'biblio_formats')) {
+    $spec =  array(
+              'type' => 'blob',
+              'not null' => FALSE,
+              'description' => '',
+              'serialize' => TRUE,
+      );
+    db_add_field('biblio', 'biblio_formats', $spec);
+  }
+}
+/**
+ * Convert textarea fields to text_format
+ */
+function biblio_update_7016() {
+    db_update('biblio_fields')
+      ->fields(array('type' => 'text_format'))
+      ->condition('type', 'textarea')
+      ->execute();
+}
+
+/**
+ * Remove views export handlers in sub-modules (if they still exist)
+ */
+function biblio_update_7017() {
+  $dirs = array('bibtexParse', 'endnote', 'RIS', 'rtf');
+  foreach ($dirs as $dir) {
+    $path = drupal_get_path('module', 'biblio') . '/modules/' . $dir . '/views';
+    if (is_dir($path)) {
+      $message = t('You have an inconsistancy in your installation, the directory: @path, should not exist!', array('@path' => $path));
+      drupal_set_message($message, 'error');
+    }
+  }
+  if (module_exists('views')) { // rebuild the data tables
+    views_invalidate_cache();
+  }
+}
+/**
+ *
+ * Widen the biblio_contributor_data.lastname column to 255 characters
+ */
+function biblio_update_7018() {
+  $spec =  array(
+    'type' => 'varchar',
+    'length' => '255',
+    'not null' => TRUE,
+    'default' => '',
+    'description' => 'Author last name',
+  );
+  db_change_field('biblio_contributor_data', 'lastname', 'lastname', $spec);
+
+}
+/**
+ *
+ * Change biblio_contributor_data.cid to a signed int
+ */
+
+function biblio_update_7019() {
+
+}
+
+/**
+ *
+ *  Change the primary key of the biblio_contributor_data table
+ */
+function biblio_update_7020() {
+  $driver = db_driver();
+  if ($driver == 'mysql') {
+    db_query('ALTER TABLE `biblio_contributor_data` DROP PRIMARY KEY , ADD PRIMARY KEY ( `cid` )');
+  }
+  if ($driver == 'pgsql') {
+    db_drop_primary_key('biblio_contributor_data');
+    db_add_primary_key('biblio_contributor_data', array('cid'));
+  }
+}
+/**
+ *
+ *  Add alt_form column to the biblio_contributor_data table
+ */
+function biblio_update_7021() {
+  if (!db_field_exists('biblio_contributor_data', 'alt_form')) {
+    $spec = array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default'  => 0,
+        'unsigned' => TRUE,
+        'description' => 'Alternate form of an author name, this value points to the desired form (cid), this form is kept in the database so  that future imports of the same name will not create a new author.',
+    );
+    db_add_field('biblio_contributor_data', 'alt_form', $spec);
+  }
+}
+/**
+ *
+ *  Add merge_cid column to the biblio_contributor_data table
+ */
+function biblio_update_7022() {
+  if (!db_field_exists('biblio_contributor', 'merge_cid')) {
+    $spec = array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default'  => 0,
+        'unsigned' => TRUE,
+        'description' => '',
+    );
+    db_add_field('biblio_contributor', 'merge_cid', $spec);
+  }
+}
+
+/**
+ *
+ * Re-apply update 7014 in case the install happened after 7014 was implemented.  The main scheme definition was not changed at that time to match the update resulting a schema mismatch.
+ *
+ */
+function biblio_update_7023() {
+  biblio_update_7014();
+}
+/**
+ *
+ * Re-apply update 7022 in case the install happened after 7022 was implemented.  The main scheme definition was not changed at that time to match the update resulting a schema mismatch.
+ *
+ */
+
+function biblio_update_7024() {
+  biblio_update_7022();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/biblio.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,2259 @@
+<?php
+/**
+ *   biblio.module for Drupal
+ *
+ *   Copyright (C) 2006-2011  Ron Jerome
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License along
+ *   with this program; if not, write to the Free Software Foundation, Inc.,
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+define('BIBLIO_VERSION', '7.x-1.x-dev');
+
+function _biblio_get_auth_types($auth_category, $biblio_type) {
+  static $auth_types = array();
+  if (empty($auth_types)) {
+    $db_res = db_query("SELECT * FROM {biblio_contributor_type}");
+    foreach ($db_res as $row) {
+      $auth_types[$row->auth_category][$row->biblio_type][] = $row->auth_type;
+    }
+  }
+  // fall back to defaults, if no author types are defined for this biblio_type
+  $result = isset($auth_types[$auth_category][$biblio_type])?$auth_types[$auth_category][$biblio_type]:$auth_types[$auth_category][0];
+  return $result;
+}
+function _biblio_get_auth_type($auth_category, $biblio_type) {
+  $result = (array)_biblio_get_auth_types($auth_category, $biblio_type);
+  // return first element of the array
+  return empty($result) ? NULL : current($result);
+}
+
+/**
+ * Translate field titles and hints through the interface translation system, if
+ * the i18nstrings module is enabled.
+ */
+function _biblio_localize_fields(&$fields) {
+  if (function_exists('i18n_string')) {
+    foreach ($fields as $key => $row) {
+      $fields[$key]['title'] = i18n_string("biblio:field:{$row['ftdid']}:title", $fields[$key]['title']);
+      $fields[$key]['hint'] = i18n_string("biblio:field:{$row['ftdid']}:hint", $fields[$key]['hint']);
+    }
+  }
+}
+
+/**
+ * Translate a publication type through the interface translation system, if
+ * the i18nstrings module is enabled.
+ *
+ * @param integer $tid
+ *   The biblio publication type identifier.
+ *
+ * @param string $value
+ *   The string to translate.
+ *
+ * @param string $field
+ *   The publication type field to translate (either 'name' or 'description').
+ *
+ * @return
+ *   Translated value.
+ */
+function _biblio_localize_type($tid, $value, $field = 'name') {
+  if (function_exists('i18n_string')) {
+    return i18n_string("biblio:type:$tid:$field", $value);
+  }
+  return $value;
+}
+
+/**
+ * Implementation of hook_locale().
+ */
+function biblio_locale($op = 'groups', $group = NULL) {
+  switch ($op) {
+    case 'groups':
+      return array('biblio' => t('Biblio'));
+
+    case 'refresh':
+      if ($group == 'biblio') {
+        biblio_locale_refresh_fields();
+        biblio_locale_refresh_types();
+      }
+      break;
+  }
+}
+
+/**
+ * Refresh all translatable field strings.
+ *
+ * @param integer $tid
+ *   Biblio publication type id whose field strings are to be refreshed. If not
+ *   specified, strings for all fields will be refreshed.
+ */
+function biblio_locale_refresh_fields($tid = NULL) {
+  if (function_exists('i18n_string')) {
+    if (isset($tid)) {
+      $result = db_query('SELECT d.* FROM {biblio_field_type} b INNER JOIN {biblio_field_type_data} d ON b.ftdid = d.ftdid WHERE tid = :tid', array(':tid' => $tid));
+    }
+    else {
+      $result = db_query('SELECT * FROM {biblio_field_type_data}');
+    }
+    $options = array('translate' => FALSE, 'update' => TRUE);
+    foreach ($result as $row) {
+      i18n_string("biblio:field:{$row->ftdid}:title", $row->title, $options);
+      i18n_string("biblio:field:{$row->ftdid}:hint", $row->hint, $options);
+    }
+  }
+}
+
+/**
+ * Refresh all publication type strings.
+ *
+ * @param integer $tid
+ *   Biblio publication type id whose field strings are to be refreshed. If not
+ *   specified, strings for all fields will be refreshed.
+ */
+function biblio_locale_refresh_types($tid = NULL) {
+  if (function_exists('i18n_string')) {
+    if (isset($tid)) {
+      $result = db_query('SELECT * FROM {biblio_types} WHERE tid = :tid', array(':tid' => $tid));
+    }
+    else {
+      $result = db_query('SELECT * FROM {biblio_types} WHERE tid > 0');
+    }
+    $options = array('translate' => FALSE, 'update' => TRUE);
+    foreach ($result as $row ) {
+      i18n_string("biblio:type:{$row->tid}:name", $row->name, $options);
+      i18n_string("biblio:type:{$row->tid}:description", $row->description, $options);
+    }
+  }
+}
+
+function biblio_init() {
+  global $user, $conf;
+  drupal_add_css(drupal_get_path('module', 'biblio') . '/biblio.css');
+
+  if ($user->uid === 0) { // Prevent caching of biblio pages for anonymous users so session variables work and thus filering works
+    $base = variable_get('biblio_base', 'biblio');
+    if (drupal_match_path($_GET['q'], "$base\n$base/*"))
+      $conf['cache'] = FALSE;
+  }
+}
+
+function biblio_cron() {
+  require_once(drupal_get_path('module', 'biblio') .'/includes/biblio.contributors.inc');
+  require_once(drupal_get_path('module', 'biblio') .'/includes/biblio.keywords.inc');
+
+  $interval = variable_get('biblio_orphan_clean_interval', 24*60*60); //defaults to once per day
+
+  if (time() >= variable_get('biblio_orphan_clean_next_execution', 0)) {
+    biblio_delete_orphan_authors();
+    biblio_delete_orphan_keywords();
+    variable_set('biblio_orphan_clean_next_execution', time() + $interval);
+  }
+}
+
+function biblio_theme($existing, $type, $theme, $path) {
+  $path = drupal_get_path('module', 'biblio');
+  return array(
+    'biblio_alpha_line' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array(
+          'type' => 'author',
+          'current' => NULL,
+          'path'  => NULL),
+    ),
+   'biblio_admin_keyword_edit_form' => array(
+        'file' => '/includes/biblio.admin.inc',
+        'render element' => 'form',
+    ),
+   'biblio_admin_author_types_form' => array(
+        'file' => '/includes/biblio.admin.inc',
+        'render element' => 'form',
+    ),
+    'biblio_admin_type_mapper_form' => array(
+        'file' => '/includes/biblio.admin.inc',
+        'render element' => 'form',
+    ),
+   'biblio_admin_io_mapper_form'=> array(
+        'file' => '/includes/biblio.admin.inc',
+        'render element' => 'form',
+    ),
+   'biblio_admin_io_mapper_add_form'=> array(
+        'file' => '/includes/biblio.admin.inc',
+        'render element' => 'form',
+    ),
+  'biblio_admin_field_mapper_form' => array(
+        'file' => '/includes/biblio.admin.inc',
+        'render element' => 'form',
+    ),
+    'biblio_admin_types_edit_form' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'render element' => 'form',
+        ),
+    'biblio_admin_types_form' => array(
+      'file' => '/includes/biblio_theme.inc',
+      'render element' => 'form',
+    ),
+    'biblio_field_tab' => array(
+      'file' => '/includes/biblio_theme.inc',
+      'render element' => 'form',
+    ),
+    'biblio_admin_author_edit_form' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'render element' => 'form',
+    ),
+    'biblio_admin_author_edit_merge_table' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'render element' => 'form',
+    ),
+    'biblio_openurl' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array('openURL'),
+    ),
+    'biblio_style' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array(
+          'node' => NULL,
+          'style_name' => 'classic',
+         ),
+    ),
+    'biblio_long' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array(
+          'node' => NULL,
+          'base' => 'biblio',
+          'style_name' => 'classic'),
+    ),
+    'biblio_tabular' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array(
+          'node' => NULL,
+          'base' => 'biblio',
+          'teaser' => FALSE),
+    ),
+    'biblio_entry' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array(
+          'node',
+          'style_name' => 'classic',
+         ),
+    ),
+    'biblio_format_authors' => array(
+      'file' => '/includes/biblio_theme.inc',
+      'variables' => array(
+        'contributors' => NULL,
+        'options' => array(),
+        ),
+    ),
+    'biblio_page_number' => array(
+      'file' => '/includes/biblio_theme.inc',
+      'variables' => array(
+        'orig_page_info' => NULL,
+        'page_range_delim' => "-",
+        'single_page_prefix' => '',
+        'page_range_prefix' => '',
+        'total_pages_prefix' => '',
+        'single_page_suffix' => '',
+        'page_range_suffix' => '',
+        'total_pages_suffix' => '',
+        'shorten_page_range_end' => FALSE),
+    ),
+    'biblio_author_link' => array(
+      'file' => '/includes/biblio_theme.inc',
+      'variables' => array(
+        'author'),
+    ),
+    'biblio_filters' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'render element' => 'form',
+    ),
+    'form_filter' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'render element' => 'form',
+    ),
+    'biblio_export_links' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array(
+        	'node' => NULL,
+          'filter' => array()),
+    ),
+    'biblio_download_links' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array('node'),
+    ),
+    'google_scholar_link' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'variables' => array('node'),
+    ),
+    'biblio_contributors' => array(
+        'file' => '/includes/biblio_theme.inc',
+        'render element' => 'form',
+    ),
+    'biblio_sort_tabs' => array(
+        'file' => 'includes/biblio_theme.inc',
+        'variables' => array(),
+    )
+  );
+}
+
+function biblio_autocomplete($field, $string = '') {
+  $matches = array();
+  switch ($field) {
+    case 'contributor':
+    case 'a':
+      $result = db_query_range("SELECT name FROM {biblio_contributor_data} WHERE LOWER(lastname) LIKE LOWER(:name) OR LOWER(firstname) LIKE LOWER(:firstname) ORDER BY lastname ASC ", 0, 10, array(':name' => $string . '%', ':firstname' => $string . '%'));
+      foreach ($result as $data ) {
+        $matches[$data->name] = check_plain($data->name);
+      }
+      break;
+    case 'biblio_keywords':
+    case 'k':
+      $sep = check_plain(variable_get('biblio_keyword_sep', ','));
+      $sep_pos = strrpos($string, $sep); //find the last separator
+      $start   = trim(drupal_substr($string, 0, $sep_pos)); // first part of the string upto the last separator
+      $end_sep = ($sep_pos) ? $sep_pos + 1 :$sep_pos;
+      $end     = trim(drupal_substr($string, $end_sep)) . '%';  // part of the string after the last separator
+      $result = db_query_range("SELECT * FROM {biblio_keyword_data} WHERE LOWER(word) LIKE LOWER(:end) ORDER BY word ASC ", 0, 10,  array(':end' => $end));
+      foreach ($result as $data) {
+        // now glue the word found onto the end of the original string...
+        $keywords = ($sep_pos) ? $start . ', ' . check_plain($data->word) : check_plain($data->word);
+        $matches[$keywords] = $keywords;
+      }
+      break;
+
+    default:
+      $field = drupal_strtolower($field);
+      $string = '%' . drupal_strtolower($string) . '%';
+      $query = db_select('biblio', 'b')
+        ->fields('b', array($field))
+        ->condition($field, $string, 'LIKE')
+        ->orderBy($field, 'ASC')
+        ->range(0, 10);
+      $result = $query->execute();
+
+      foreach ($result as $data) {
+        $matches[$data->$field] = check_plain($data->$field);
+      }
+  }
+  print drupal_json_encode($matches);
+  exit();
+}
+
+function biblio_help_page() {
+  $base = variable_get('biblio_base', 'biblio');
+  $text = "<h3>" . t('General:') . "</h3>";
+  $text .= "<p>" . t('By default, the !url page will list all of the entries in the database sorted by Year in descending order. If you wish to sort by "Title" or "Type",  you may do so by clicking on the appropriate links at the top of the page.  To reverse the sort order, simply click the link a second time.', array(
+    '!url' => l('',
+  $base
+  ))) . "</p>";
+  $text .= "<h3>" . t('Filtering Search Results:') . "</h3>";
+  $text .= "<p>" . t('If you wish to filter the results, click on the "Filter" tab at the top of the page.  To add a filter, click the radio button to the left of the filter type you wish to apply, then select the filter criteria from the drop down list on the right, then click the filter button.') . "</p>";
+  $text .= "<p>" . t('It is possible to create complex filters by returning to the <i>Filter</i> tab and adding additional filters.  Simply follow the steps outlined above and press the "Refine" button.') . "</p>";
+  $text .= "<p>" . t('All filters can be removed by clicking the <i>Clear All Filters</i> link at the top of the result page, or on the <i>Filter</i> tab they can be removed one at a time using the <i>Undo</i> button, or you can remove them all using the <i>Clear All</i> button.') . "</p>";
+  $text .= "<p>" . t('You may also construct URLs which filter.  For example, /biblio/year/2005 will show all of the entries for 2005.  /biblio/year/2005/author/smith will show all of entries from 2005 for smith.') . "</p>";
+  $text .= "<h3>" . t('Exporting Search Results:') . "</h3>";
+  $text .= "<p>" . t('Assuming this option has been enabled by the administrator, you can export search results directly into EndNote.  The link at the top of the result page will export all of the search results, and the links on individual entries will export the information related to that single entry.') . "</p>";
+  $text .= "<p>" . t('The information is exported in EndNote "Tagged" format similar to this...') . "<pre>" . t('
+                  %0  Book
+                  %A  John Smith
+                  %D  1959
+                  %T  The Works of John Smith
+                  ...') . '</pre></p>';
+  $text .= "<p>" . t('Clicking on one of the export links should cause your browser to ask you whether you want to Open, or Save To Disk, the file endnote.enw.  If you choose to open it, Endnote should start and ask you which library you would like store the results in.  Alternatively, you can save the file to disk and manually import it into EndNote.') . "</p>";
+  return ($text);
+}
+/**
+ * Implementation of hook_help().
+ *
+ * Throughout Drupal, hook_help() is used to display help text at the top of
+ * pages. Some other parts of Drupal pages get explanatory text from these hooks
+ * as well. We use it here to provide a description of the module on the
+ * module administration page.
+ */
+
+function biblio_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#biblio' :
+      return biblio_help_page();
+    case 'admin/modules#description' :
+      // This description is shown in the listing at admin/modules.
+      return t('Manages a list of scholarly papers on your site');
+    case 'node/add#biblio' :
+      // This description shows up when users click "create content."
+      return t('This allows you to add a bibliographic entry to the database');
+  }
+}
+
+function biblio_node_info() {
+  return array(
+    'biblio' => array(
+      'name' => t('Biblio'),
+      'base' => 'biblio',
+      'description' => t('Use Biblio for scholarly content, such as journal papers and books.'),
+    )
+  );
+}
+
+function biblio_node_access($node, $op, $account) {
+  if (is_string($node)) {
+    return NODE_ACCESS_IGNORE;
+  }
+
+  if ($node->type != 'biblio') { // we only care about biblio nodes
+    return NODE_ACCESS_IGNORE;
+  }
+  switch ($op) {
+    case 'view':
+      if (((variable_get('biblio_view_only_own', 0)) && $account->uid != $node->uid) ||
+          !user_access('access biblio content')){
+        return NODE_ACCESS_DENY;
+      }
+      break;
+    case 'update':
+    case 'delete':
+      if (user_access('edit by all biblio authors') && isset($node->biblio_contributors) && is_array($node->biblio_contributors)) {
+        foreach ($node->biblio_contributors as $key => $author) {
+          if ((isset($author['drupal_uid']) && $author['drupal_uid'] == $account->uid) ||
+          (isset($account->data['biblio_contributor_id']) && $author['cid'] == $account->data['biblio_contributor_id'])) {
+            return NODE_ACCESS_ALLOW;
+          }
+        }
+      }
+      break;
+    default:
+  }
+  return NODE_ACCESS_IGNORE;
+}
+
+function biblio_access($op, $node = '') {
+  global $user;
+
+  switch ($op) {
+    case 'admin':
+      return user_access('administer biblio');
+    case 'import':
+      return user_access('import from file');
+    case 'export':
+      return user_access('show export links');
+    case 'edit_author':
+        if (user_access('administer biblio') || user_access('edit biblio authors')) return NODE_ACCESS_ALLOW;
+        break;
+    case 'download':
+      if (user_access('show download links') || (user_access('show own download links') && ($user->uid == $node->uid))) return NODE_ACCESS_ALLOW;
+      break;
+    case 'rss':
+      return variable_get('biblio_rss', 0);
+    default:
+  }
+  return NODE_ACCESS_IGNORE;
+}
+/**
+ * Implementation of hook_permission().
+ *
+ * Since we are limiting the ability to create new nodes to certain users,
+ * we need to define what those permissions are here. We also define a permission
+ * to allow users to edit the nodes they created.
+ */
+function biblio_permission() {
+  return array(
+    'administer biblio' => array(
+      'title' => t('Administer Biblio'),
+      'description' => t('Allows full control (create, update, delete) of all Biblio nodes'),
+      ),
+    'access biblio content' => array(
+      'title' => t('Access Biblio content'),
+      'description' => t('Allows the user to view Biblio nodes'),
+      ),
+//    'create biblio' => array(
+//      'title' => t('Create Biblio'),
+//      'description' => t('Allows the user to create new Biblio nodes'),
+//      ),
+//    'edit all biblio entries' => array(
+//      'title' => t('Edit all Biblio entries'),
+//      'description' => t('Allows the user to edit ALL biblio entries regardless of who "owns" them, otherwise they are restricted to on'),
+//      ),
+    'edit by all biblio authors' => array(
+      'title' => t('Edit by all Biblio authors'),
+      'description' => t('Allows any/all of the authors associated with a biblio entry to edit the biblio entry. This requires the Drupal UserID be mapped to a Biblio author ID'),
+      ),
+    'edit biblio authors' => array(
+      'title' => t('Edit Biblio authors'),
+      'description' => t('Allows the user to edit author information'),
+      ),
+    'import from file' => array(
+      'title' => t('Import from file'),
+      'description' => t('Allows the user to import bibliographic data from files such as BibTex, RIS, EndNote'),
+      ),
+    'show export links' => array(
+      'title' => t('Show export links'),
+      'description' => t('Allows users to see links which allow export of bibliographic data for an individual entry or the entire result set'),
+      ),
+    'show download links' => array(
+      'title' => t('Show download links'),
+      'description' => t('Allows users to see links to any attachements associated with the Biblio entry'),
+      ),
+    'show own download links' => array(
+      'title' => t('Show own download links'),
+      'description' => t('Allows user to only see download links on entries for which they are the owner.'),
+      ),
+    'show filter tab' => array(
+      'title' => t('Show filter tab'),
+      'description' => t('This determines if the "Filter" tab on the Biblio list page will be shown to the user'),
+      ),
+    'show sort links' => array(
+      'title' => t('Show sort links'),
+      'description' => t('This determines if the "Sort" links on the Biblio list page will be shown to the user'),
+      ),
+    'view full text' => array(
+      'title' => t('Show full text'),
+      'description' => t('This determines if the user will be able to access the "Full Text" of the article if it is available'),
+      ),
+    );
+}
+
+/**
+ * Implementation of hook_user().
+ */
+function biblio_form_user_profile_form_alter(&$form, &$form_state, $form_id) {
+  if ($form['#user_category'] == 'account') {
+    $account = $form['#user'];
+    include_once drupal_get_path('module', 'biblio') . '/includes/biblio.admin.inc';
+    $show_form = variable_get('biblio_show_user_profile_form', '1')     ||
+                 variable_get('biblio_show_crossref_profile_form', '1') ||
+                 variable_get('biblio_show_openurl_profile_form', '1');
+
+    $admin_show_form = ($account->uid == 1 || (user_access('administer users') && user_access('administer biblio'))) ? TRUE : FALSE;
+    if ($admin_show_form || $show_form) {
+      $form['biblio_fieldset'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Biblio settings'),
+        '#weight' => 5,
+        '#collapsible' => TRUE,
+        '#collapsed' => FALSE,
+      );
+      if ($admin_show_form || variable_get('biblio_show_user_profile_form', '1')) {
+        $form['biblio_fieldset'] += _biblio_get_user_profile_form($account);
+      }
+      else {
+        $form['biblio_fieldset'] += _biblio_drupal_author_user_map($account);
+      }
+      if ($admin_show_form || variable_get('biblio_show_openurl_profile_form', '1')) {
+        $form['biblio_fieldset'] += _biblio_get_user_openurl_form($account);
+      }
+      if ($admin_show_form || variable_get('biblio_show_crossref_profile_form', '1')) {
+        $form['biblio_fieldset'] += _biblio_get_user_doi_form($account);
+      }
+    }
+  }
+}
+
+function biblio_forms() {
+  $forms['biblio_admin_author_types_form_new'] = array(
+    'callback' => 'biblio_admin_author_types_form',
+  );
+  $forms['biblio_admin_author_types_form_edit'] = array(
+    'callback' => 'biblio_admin_author_types_form',
+  );
+  return $forms;
+
+}
+/**
+ * Implementation of hook_menu().
+ *
+ * Here we define some built in links for the biblio module, links exposed are:
+ *
+ *
+ */
+function biblio_menu() {
+  global $user;
+  $items = array();
+  $base = variable_get('biblio_base', 'biblio');
+  $base_title = check_plain(variable_get('biblio_base_title', 'Biblio'));
+  $items["$base"] = array(
+    'title'             => $base_title,
+    'page callback'     => 'biblio_page',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'file'              => '/includes/biblio.pages.inc',
+  );
+  $items["$base/authors"] = array(
+    'title'             => 'Authors',
+    'page callback'     => 'biblio_author_page',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'file'              => '/includes/biblio.pages.inc',
+    'weight'            => 1,
+  );
+  $items["$base/keywords"] = array(
+    'title' => 'Keywords',
+    'page callback' => 'biblio_keyword_page',
+    'access callback' => 'user_access',
+    'access arguments' => array('access biblio content'),
+    'file' => '/includes/biblio.pages.inc',
+//    'type' => MENU_LOCAL_TASK,
+    'weight' => 2,
+  );
+  $items["$base/import"] = array(
+    'title'             => 'Import',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_import_form'),
+    'file'              => '/includes/biblio.import.export.inc',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('import from file'),
+ //   'type'              => MENU_LOCAL_TASK,
+    'weight'            => 10,
+  );
+  $items["$base/user/%"] = array(
+    'title'             => 'My publications',
+    'page callback'     => 'biblio_profile_page',
+    'page arguments'    => array(2),
+    'access callback'   => '_biblio_profile_access',
+    'access arguments'  => array(2, 'menu'),
+    'parent'            => '',
+    'file'              => '/includes/biblio.pages.inc',
+  );
+  /*
+   $items["$base/backup"] = array(
+   'title' => '',
+   'page callback' => 'biblio_backup',
+   'access callback' => 'user_access',
+   'access arguments' => array('access content'),
+   'file' => 'biblio.import.export.inc',
+   'type' => MENU_CALLBACK
+   );
+   */
+  $items["$base/pot"] = array(
+    'title'             => '',
+    'page callback'     => 'biblio_dump_db_data_for_pot',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'type'              => MENU_CALLBACK
+  );
+
+  $wildcard = 2 + (count(explode("/", $base)) - 1);
+
+  $items["$base/authors/%/edit"] = array(
+    'title'             => 'Edit author information',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_author_edit_form', $wildcard),
+    'access callback'   => 'biblio_access',
+    'access arguments'  => array('edit_author'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK
+  );
+  $items["$base/keywords/%/edit"] = array(
+    'title'             => '',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_keyword_edit_form', $wildcard),
+    'access callback'   => 'user_access',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK
+  );
+  $items["$base/keyword/%/delete"] = array(
+    'title'             => 'Delete',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_keyword_delete_confirm', $wildcard),
+    'access callback'   => 'user_access',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'weight'            => 1,
+    'type'              => MENU_CALLBACK
+  );
+  $items["$base/view/%"] = array(
+    'page callback'     => 'biblio_view_node',
+    'page arguments'    => array($wildcard),
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'file'              => '/includes/biblio.pages.inc',
+    'type'              => MENU_CALLBACK
+   );
+
+  $items["user/%user/$base"] = array(
+    'title'             => 'Publications',
+    'page callback'     => 'biblio_profile_page',
+    'page arguments'    => array(1, 'profile', 'no_filters'),
+    'access callback'   => '_biblio_profile_access',
+    'access arguments'  => array(1, 'profile'),
+    'file'              => '/includes/biblio.pages.inc',
+    'type'              => MENU_LOCAL_TASK
+  );
+  // The next two "LOCAL TASKS" are for the admin/config/content/biblio page
+  $items['admin/config/content/biblio'] = array(
+    'title'             => 'Biblio settings',
+    'description'       => 'Configure default behavior of the Biblio module.',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_settings'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+  );
+
+  $items['admin/config/content/biblio/basic'] = array(
+    'title'             => 'Preferences',
+    'description'       => 'Configure default behavior of the Biblio module.',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_settings'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -10
+  );
+  $items['admin/config/content/biblio/import'] = array(
+    'title'             => 'Data import',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_import_form'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.import.export.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => 1
+  );
+  $items['admin/config/content/biblio/export'] = array(
+    'title'             => 'Export',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_export_form'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.import.export.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => 2
+  );
+  $items['admin/config/content/biblio/fields'] = array(
+    'title'             => 'Fields',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_types_edit_form'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -9
+  );
+  $items['admin/config/content/biblio/fields/common'] = array(
+    'title'             => 'Common',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_types_edit_form'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_DEFAULT_LOCAL_TASK,
+    'weight'            => -10
+  );
+  $items['admin/config/content/biblio/iomap'] = array(
+    'title'             => 'Import/Export Mapping',
+    'page callback'     => 'biblio_admin_io_mapper_page',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -1
+  );
+  $items['admin/config/content/biblio/iomap/formats'] = array(
+    'title'             => 'Import/Export Mapping',
+    'page callback'     => 'biblio_admin_io_mapper_page',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_DEFAULT_LOCAL_TASK,
+    'weight'            => -100
+  );
+  $formats = module_invoke_all('biblio_mapper_options');
+  foreach ($formats as $key => $format) {
+  $items['admin/config/content/biblio/iomap/edit/' . $key] = array(
+    'title'             => $format['title'],
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_io_mapper_form', 6),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'tab_parent'						=> 'admin/config/content/biblio/iomap',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -1
+  );
+  }
+  $items['admin/config/content/biblio/iomap/%/%/add'] = array(
+    'title'             => '',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_io_mapper_add_form', 5, 6),
+    'access arguments'  => array('administer biblio'),
+    'tab_parent'						=> 'admin/config/content/biblio/iomap',
+  'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK,
+    'weight'            => -1
+  );
+  $items['admin/config/content/biblio/pubtype'] = array(
+    'title'             => 'Publication types',
+    'page callback'     => 'biblio_admin_types_form',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -9
+  );
+  $items['admin/config/content/biblio/pubtype/list'] = array(
+    'title'             => 'List',
+    'page callback'     => 'biblio_admin_types_form',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_DEFAULT_LOCAL_TASK,
+    'weight'            => -10
+  );
+  $items['admin/config/content/biblio/pubtype/delete/%'] = array(
+    'title'             => '',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_types_delete_form', 6),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK
+  );
+  $items['admin/config/content/biblio/pubtype/new'] = array(
+    'title'             => 'Add New Type',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_types_add_form'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -9
+  );
+  $items['admin/config/content/biblio/pubtype/reset'] = array(
+    'page callback'     => 'biblio_admin_types_reset',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK,
+  );
+  $items['admin/config/content/biblio/fields/reset'] = array(
+    'title'             => 'Reset all types to defaults',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_types_reset_form'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK
+  );
+  $items['admin/config/content/biblio/pubtype/hide'] = array(
+    'title'             => '',
+    'page callback'     => 'biblio_admin_types_hide',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK
+  );
+  $items['admin/config/content/biblio/pubtype/show'] = array(
+    'title'             => '',
+    'page callback'     => 'biblio_admin_types_show',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK
+  );
+  $items['admin/config/content/biblio/author'] = array(
+    'title'             => 'Authors',
+    'page callback'     => 'biblio_author_page',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'file'              => '/includes/biblio.pages.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -7
+  );
+  $items['admin/config/content/biblio/author/list'] = array(
+    'title'             => 'List',
+    'page callback'     => 'biblio_author_page',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'file'              => '/includes/biblio.pages.inc',
+    'type'              => MENU_DEFAULT_LOCAL_TASK,
+    'weight'            => -7
+  );
+  $items['admin/config/content/biblio/author/%/edit'] = array(
+    'title'             => 'Edit author information',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_author_edit_form', 5),
+    'access callback'   => 'biblio_access',
+    'access arguments'  => array('edit_author'),
+    'file'              => '/includes/biblio.admin.inc',
+     'type'              => MENU_CALLBACK,
+    'weight'            => -6
+  );
+  $items['admin/config/content/biblio/author/orphans'] = array(
+    'title'             => 'Orphaned Authors',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_orphans_form'),
+    'access arguments'  => array('administer biblio'),
+    'description'       => 'Delete orphaned biblio authors.',
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -6
+  );
+  $items['admin/config/content/biblio/author/type'] = array(
+    'title'             => 'Author Types',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_author_types_form', 7, 6),
+  'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -5
+  );
+
+  $items['admin/config/content/biblio/author/type/new'] = array(
+    'title'             => 'Add New Author Type',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_author_types_form_new', 'new'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -9
+  );
+  $items['admin/config/content/biblio/author/type/%/edit'] = array(
+    'title'             => 'Edit Author Type',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_author_types_form_edit', 'edit', 6),
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK,
+    'weight'            => -9
+  );
+  $items['admin/config/content/biblio/author/type/%/delete'] = array(
+    'title'             => 'Delete',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_author_type_delete_confirm', 6),
+    'access callback'   => 'user_access',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'weight'            => 1,
+    'type'              => MENU_CALLBACK
+  );
+  $items['admin/config/content/biblio/keywords'] = array(
+    'title'             => 'Keywords',
+    'page callback'     => 'biblio_keyword_page',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'file'              => '/includes/biblio.pages.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -7
+  );
+  $items['admin/config/content/biblio/keywords/list'] = array(
+    'title'             => 'List',
+    'page callback'     => 'biblio_keyword_page',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'file'              => '/includes/biblio.pages.inc',
+    'type'              => MENU_DEFAULT_LOCAL_TASK,
+    'weight'            => -7
+  );
+  $items['admin/config/content/biblio/keywords/%/edit'] = array(
+    'title'             => 'Edit keyword information',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_keyword_edit_form', 5),
+    'access callback'   => 'user_access',
+    'access arguments'  => array('administer biblio'),
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_CALLBACK,
+    'weight'            => -6
+  );
+  $items['admin/config/content/biblio/keywords/orphans'] = array(
+    'title'             => 'Orphaned Keywords',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_keyword_orphans_form'),
+    'access arguments'  => array('administer biblio'),
+    'description'       => 'Delete orphaned biblio keywords.',
+    'file'              => '/includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => -6
+  );
+  /*    $items['admin/config/content/biblio/authors/reset'] = array(
+   'title' => t('Reset all Author types to defaults'),
+   'page callback' => 'drupal_get_form',
+   'page arguments' => array('biblio_admin_author_type_reset_form'),
+   'access arguments' => array('administer biblio'),
+   'file' => '/includes/biblio.admin.inc',
+   'type' => MENU_LOCAL_TASK
+   );
+   */
+  $items['biblio/autocomplete'] = array(
+    'title'             => 'Autocomplete ',
+    'page callback'     => 'biblio_autocomplete',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'type'              => MENU_CALLBACK
+  );
+/*  $items["$base/list"] = array(
+    'title'             => 'List',
+    'type'              => MENU_DEFAULT_LOCAL_TASK,
+    'weight'            => -10
+  );
+  $items["$base/filter"] = array(
+    'title'             => 'Filter',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_form_filter'),
+    'access callback'   => 'user_access',
+    'access arguments'  => array('show filter tab'),
+    'type'              => MENU_LOCAL_TASK,
+    'file'              => '/includes/biblio.pages.inc',
+    'weight'            => -9
+  );
+*/
+  $items["$base/filter/clear"] = array(
+    'title'             => '',
+    'page callback'     => 'biblio_filter_clear',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'type'              => MENU_CALLBACK
+  );
+  $items["$base/help"] = array(
+    'title'             => 'Help',
+    'page callback'     => 'biblio_help_page',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('access biblio content'),
+    'type'              => MENU_CALLBACK
+  );
+  $items["$base/export"] = array(
+    'title'             => '',
+    'page callback'     => 'biblio_export',
+    'access callback'   => 'user_access',
+    'access arguments'  => array('show export links'),
+    'file'              => '/includes/biblio.import.export.inc',
+    'type'              => MENU_CALLBACK
+  );
+  $items["$base/citekey"] = array(
+    'title'             => '',
+    'page callback'     => 'biblio_citekey_view',
+    'access arguments'  => array('access biblio content'),
+    'file'              => '/includes/biblio.pages.inc',
+    'type'              => MENU_CALLBACK
+  );
+  $items["$base/recent/rss.xml"] = array(
+    'title'             => 'RSS feed',
+    'page callback'     => 'biblio_recent_feed',
+    'access callback'   => 'biblio_access',
+    'access arguments'  => array('rss'),
+    'type'              => MENU_CALLBACK
+  );
+  return $items;
+}
+
+function biblio_filter_clear() {
+  $options = array();
+  $_SESSION['biblio_filter'] = array();
+  $base = variable_get('biblio_base', 'biblio');
+  if (isset($_GET['sort'])) {
+    $options['sort'] = $_GET['sort'];
+  }
+  if (isset($_GET['order'])) {
+    $options['order'] = $_GET['order'];
+  }
+  drupal_goto($base, $options);
+}
+
+function biblio_remove_brace($title_string) {
+    //$title_string = utf8_encode($title_string);
+    $matchpattern = '/\{\$(?:(?!\$\}).)*\$\}|(\{[^}]*\})/';
+    $output = preg_replace_callback($matchpattern, 'biblio_remove_brace_callback', $title_string);
+    return $output;
+}
+
+function biblio_remove_brace_callback($match) {
+        if (isset($match[1])) {
+                $braceless = str_replace('{', '', $match[1]);
+                $braceless = str_replace('}', '', $braceless);
+                return $braceless;
+        }
+        return $match[0];
+}
+
+function biblio_node_revision_delete($node) {
+  if ($node->type == 'biblio') {
+    db_delete('biblio')
+      ->condition('vid', $node->vid)
+      ->execute();
+
+    db_delete('biblio_contributor')
+      ->condition(db_and()->condition('nid', $node->nid)->condition('vid', $node->vid))
+      ->execute();
+
+    db_delete('biblio_keyword')
+      ->condition(db_and()->condition('nid', $node->nid)->condition('vid', $node->vid))
+      ->execute();
+  }
+}
+
+function biblio_node_insert($node) {
+  if ($node->type == 'biblio') {
+    if (variable_get('biblio_index', 0)) {
+      _node_index_node($node);
+      search_update_totals();
+    }
+  }
+}
+
+function biblio_node_update($node) {
+  if ($node->type == 'biblio') {
+    if (variable_get('biblio_index', 0)) {
+      // _node_index_node performs a node_load without resetting the node_load cache,
+      // so it would index the old version. We reset the cache here.
+      // Don't assign node_load to $node because node_load resets e.g. the menus mlid etc.
+      $mynode = node_load($node->nid, NULL, TRUE);
+      _node_index_node($mynode);
+      search_update_totals();
+    }
+  }
+}
+
+function biblio_node_view($node, $view_mode) {
+  if ($node->type == 'biblio') {
+    switch ($view_mode) {
+      case 'full':
+        if (variable_get('biblio_hide_bibtex_braces', 0) && !empty($a4)) {
+          drupal_set_title(filter_xss($node->title, biblio_get_allowed_tags()));
+        }
+        //fall through
+      case 'teaser':
+        $show_link = variable_get('biblio_lookup_links', array('google' => TRUE));
+        if (!empty($show_link['google'])) {
+          $node->content['links']['biblio_google_scholar'] = array(
+            '#links' => array(theme('google_scholar_link', array('node' => $node))),
+            '#attributes' => array('class' => array('links', 'inline')),
+          );
+        }
+    }
+  }
+}
+
+function biblio_query_node_access_alter(QueryAlterableInterface $query) {
+  global $user;
+  if (user_access('access biblio content', $user)) return;
+  $tables = $query->getTables();
+  foreach ($tables as $alias => $table_info) {
+    if (!($table_info instanceof SelectQueryInterface)) {
+      if ( $table_info['table'] == 'node') {
+        $query->condition($alias .'.type', 'biblio', '<>');
+        break;
+      }
+    }
+  }
+
+}
+
+function biblio_user_presave(&$edit, $account, $catagory) {
+  $keys = array_keys($edit);
+  foreach ($keys as $key) {
+    if (strpos($key, 'biblio_') !== FALSE && isset($edit[$key])) {
+      if (isset($account->data['biblio_id_change_count']) && $account->data['biblio_id_change_count'] > 2
+          && $key == 'biblio_contributor_id' && $edit[$key] != 0 ) {
+         $edit[$key] = 0;
+      }
+      $edit['data'][$key] = $edit[$key];
+      if ($key == 'biblio_contributor_id' ) {
+        if ($edit[$key] != 0 && $edit[$key] != $account->data[$key]) {
+          $edit['biblio_id_change_count']++;
+        }
+        db_update('biblio_contributor_data')->condition('drupal_uid', $account->uid)->fields(array('drupal_uid' => 0))->execute();
+        db_update('biblio_contributor_data')->condition('cid', $edit['biblio_contributor_id'])->fields(array('drupal_uid' => $account->uid))->execute();
+      }
+    }
+  }
+}
+
+/**
+ * Implementation of hook_form().
+ *
+ * Create the form for collecting the information
+ * specific to this node type. This hook requires us to return some HTML
+ * that will be later placed inside the form.
+ */
+function biblio_form($node, &$form_state) {
+  global $user;
+  $path = drupal_get_path('module', 'biblio');
+  if (variable_get('biblio_button_hide', 1) == 1) {
+    drupal_add_js($path . '/misc/biblio.nodeformbuttonhide.js', 'file');
+  }
+  $fields = array();
+  $form['biblio_tabs'] = $tabs = array();
+
+  $tid = !empty($form_state['biblio_type']) ? $form_state['biblio_type'] :
+          ( isset($node->biblio_type) ? $node->biblio_type : 0);
+
+  $step_two = !empty($tid);
+
+  /* publication type */
+  $param['options'] = array("enctype" => "multipart/form-data");
+  $result = db_query('SELECT t.* FROM {biblio_types} as t WHERE tid > -2 AND visible = 1');
+  foreach ($result as $option) {
+    $results[$option->tid] = $option->name;
+  }
+  asort($results);
+  $options[0] = t('Select Type...');
+  $options += $results;
+  $form['biblio_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Publication Type'),
+    '#default_value' =>  $tid,
+    '#options' => $options,
+    '#description' => NULL,
+    '#weight' => 2,
+    '#attributes' =>  array('onchange' => 'document.getElementById(\'edit-biblio-next\').click()'),
+    '#executes_submit_callback' => TRUE,
+    '#limit_validation_errors' => array(),
+    '#multiple' => FALSE,
+    '#required' => TRUE
+  );
+
+    $form['biblio_next'] = array(
+        '#type'   => 'submit',
+        '#value'  => $step_two ? t('Change Publication Type') : t('Next'),
+        '#limit_validation_errors' => array(),
+        '#weight' => -10,
+        '#submit' => array(),
+    );
+  if (isset($_COOKIE['has_js']) && !$_COOKIE['has_js']) {
+    unset($form['biblio_next']['#attributes']);
+  }
+
+  if ($step_two) {
+    $form['title'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Title'),
+      '#required' => TRUE,
+      '#default_value' => trim((isset($form_state['values']['title'])?$form_state['values']['title']: $node->title)),
+      '#maxlength' => 255,
+      '#size' => 120,
+      '#weight' => 1
+    );
+    // Build the field array used to make the form
+    $result = db_query("SELECT * FROM {biblio_fields} b
+              INNER JOIN {biblio_field_type} bt ON b.fid = bt.fid
+              INNER JOIN {biblio_field_type_data} btd ON btd.ftdid=bt.ftdid
+              WHERE bt.tid=:tid ORDER BY bt.weight ASC", array(':tid' => $tid), array('fetch' => PDO::FETCH_ASSOC));
+
+    foreach ($result as $row) {
+      $fields[$row['name']] = $row;
+    }
+    _biblio_localize_fields($fields);
+
+    $tabs = array(
+      '#type' => 'vertical_tabs',
+      '#weight' => 10,
+    );
+    $tabs += biblio_node_form_vtabs();
+
+    $tabs['biblio_authors'] = array(
+      '#type' => 'fieldset',
+      '#group' => 'biblio_tabs',
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#title' => 'Authors',
+      '#description' => t('Enter a single name per line using a format such as "Smith, John K" or "John K Smith" or "J.K. Smith"'),
+    );
+
+    $tabs['biblio_authors'] += biblio_contributor_widget($node, $form_state);
+
+    $form_state['biblio_fields'] = $fields;
+
+    foreach ($fields as $key => $fld) {
+      $options = '';
+      if ($key == 'biblio_keywords' ) {
+        $sep = check_plain(variable_get('biblio_keyword_sep', ','));
+        // is the kewords are in array form, then implode them into a string.
+        if (isset($form_state['values']['biblio_keywords']) &&
+          is_array($form_state['values']['biblio_keywords'])) {
+          require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.keywords.inc');
+          $form_state['values']['biblio_keywords'] = biblio_implode_keywords($form_state['values']['biblio_keywords']);
+        }
+        if (!empty($node->$key) && is_array($node->$key)) {
+          require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.keywords.inc');
+          $node->$key = biblio_implode_keywords($node->$key);
+        }
+        if (empty($fld['hint'])) {
+          $fld['hint'] = t('Separate keywords using the " @sep " character', array('@sep' => $sep));
+        }
+      }
+
+      $element = array(
+            '#default_value' => (isset($form_state['values'][$key]) ? $form_state['values'][$key] : (isset($node->$key)?$node->$key:'')),
+            '#type' => $fld['type'],
+            '#title' => check_plain($fld['title']),
+            '#size' => $fld['size'],
+            '#rows' => 10,
+//            '#required' => $fld['required'],
+            '#maxlength' => $fld['maxsize'],
+            '#weight' => $fld['weight'] / 10,
+            '#autocomplete_path' => ($fld['autocomplete']) ? 'biblio/autocomplete/' . $fld['name'] : '',
+            '#description' => check_plain($fld['hint']),
+            '#format' => isset($node->biblio_formats[$key]) ? $node->biblio_formats[$key] :  filter_default_format(),
+      );
+
+      if ($key == 'biblio_refereed' ) {
+        $element['#options'] = array(
+              '' => t('None'),
+              'Refereed' => t('Refereed'),
+              'Non-Refereed' => t('Non-Refereed'),
+              'Does Not Apply' => t('Does Not Apply'),
+              'Unknown' => t('Unknown'),
+        );
+        $element['#description'] = t('If you are not sure, set this to Unknown or Does Not Apply');
+      }
+
+      if ( $fld['common']  || $fld['visible'] ) {
+        $tabs[$fld['vtab']][$key] = $element;
+      }
+
+    }
+  }
+  foreach (element_children($tabs) as $key) {
+    $tab_children = element_children($tabs[$key]);
+    if (empty($tab_children) && $key != 'biblio_full_text') {
+      unset($tabs[$key]);
+    }
+  }
+  // $form['format'] = filter_form($node->format, 20);
+ //$biblio_form['#tree']  = TRUE;
+  $form['#validate']= array('biblio_node_form_validate');
+  $form['#cache'] = TRUE;
+  $form['biblio_tabs'] += $tabs;
+
+  return $form;
+}
+
+function biblio_node_form_vtab_info() {
+  return array(
+    array('tab_id' => 1, 'weight' => 10, 'title' => 'Abstract', 'description' => ''),
+    array('tab_id' => 'biblio_full_text', 'weight' => 11, 'title' => 'Full text', 'description' => ''),
+    array('tab_id' => 2, 'weight' => 12, 'title' => 'Publication', 'description' => ''),
+    array('tab_id' => 3, 'weight' => 13, 'title' => 'Publisher', 'description' => ''),
+    array('tab_id' => 4, 'weight' => 14, 'title' => 'Identifiers', 'description' => ''),
+    array('tab_id' => 5, 'weight' => 15, 'title' => 'Locators', 'description' => 'URL\'s etc'),
+    array('tab_id' => 6, 'weight' => 16, 'title' => 'Keywords', 'description' => ''),
+    array('tab_id' => 7, 'weight' => 17, 'title' => 'Notes', 'description' => ''),
+    array('tab_id' => 8, 'weight' => 18, 'title' => 'Alternate Titles', 'description' => ''),
+    array('tab_id' => 9, 'weight' => 19, 'title' => 'Other', 'description' => ''),
+    );
+}
+
+function biblio_node_form_vtabs() {
+  $vtabs = biblio_node_form_vtab_info();
+
+  foreach ($vtabs as $tab) {
+    $form[$tab['tab_id']] = array(
+        '#type' => 'fieldset',
+        '#group' => 'biblio_tabs',
+        '#collapsible' => TRUE,
+        '#collapsed' => FALSE,
+        '#title' => t($tab['title']),
+        '#description' => '',
+        '#weight' => $tab['weight']
+    );
+  }
+  return $form;
+}
+function biblio_contributor_widget($node, &$form_state) {
+  $init_count = variable_get('biblio_init_auth_count', 4);
+  $contributor_count = 0;
+  if (isset($form_state['values']['biblio_contributors'])) {
+    $contributors = $form_state['values']['biblio_contributors'];
+  }
+  elseif (isset($node->biblio_contributors)) {
+    $contributors = $node->biblio_contributors;
+  }
+  else {
+    $contributors = array();
+  }
+
+  $ctypes = db_query('SELECT * FROM {biblio_contributor_type_data}');
+
+  foreach ($ctypes as $ctype ) {
+    $options['roles'][$ctype->auth_type] = $ctype->title;
+  }
+  $options['categories'] = array(
+    1 => t('Primary'),
+    2 => t('Secondary'),
+    3 => t('Tertiary'),
+    4 => t('Subsidiary'),
+    5 => t('Corporate/Institutional')
+  );
+
+  // Container for just the contributors.
+  $wrapper = array();
+  $wrapper['biblio_contributors'] = array(
+    '#tree'   => TRUE,
+    '#theme'  => 'biblio_contributors',
+    '#prefix' => '<div id="biblio-contributors-wrapper">',
+    '#suffix' => '</div>',
+  );
+  foreach ($contributors as $author) {
+    $wrapper['biblio_contributors'][] = biblio_contributor_form($author, $options);
+    $contributor_count++;
+  }
+
+  if (isset($form_state['biblio_contrib_count'])) {
+    $form_count = max(max($init_count, $contributor_count), $form_state['biblio_contrib_count']);
+  }
+  else {
+     $form_count = max($init_count, $contributor_count);
+    $form_state['biblio_contrib_count'] = $form_count;
+  }
+  if ($form_count > $contributor_count) {
+    $author = array();
+    for ($i = 0; $i < ($form_count - $contributor_count); $i++) {
+       $wrapper['biblio_contributors'][] = biblio_contributor_form($author, $options);
+    }
+  }
+  $wrapper['add_more'] = array(
+    '#type'        => 'submit',
+    '#value'       => t('More contributors'),
+    '#description' => t("If there aren't enough boxes above, click here to add more."),
+    '#weight'      => 1,
+    '#submit'      => array('biblio_contributors_add_more'), // If no javascript action.
+    '#limit_validation_errors' => array(),
+    '#ajax'        => array(
+           'callback' => 'biblio_contributors_add_more_callback',
+           'wrapper'  => 'biblio-contributors-wrapper',
+      ),
+    );
+
+  return $wrapper;
+}
+
+function biblio_contributor_form($contributor, $options) {
+    $form = array('#tree' => TRUE);
+
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#maxlength' => 255,
+    '#autocomplete_path' =>  'biblio/autocomplete/contributor',
+    '#default_value' => isset($contributor['name']) ? $contributor['name'] : '',
+  );
+  $form['auth_category'] = array(
+      '#type' => 'select',
+      '#default_value' => isset($contributor['auth_category']) ? $contributor['auth_category'] : '',
+      '#options' => $options['categories'],
+      '#multiple' => FALSE,
+      );
+  $form['auth_type'] = array(
+      '#type' => 'select',
+      '#default_value' => isset($contributor['auth_type']) ? $contributor['auth_type'] : '',
+      '#options' => $options['roles'],
+      '#multiple' => FALSE,
+      );
+  $form['cid'] = array(
+    '#type' => 'hidden',
+    '#default_value' => isset($contributor['cid']) ? $contributor['cid'] : '',
+  );
+  $form['rank'] = array(
+    '#type' => 'textfield',
+    '#size' => 6,
+    '#default_value' => isset($contributor['rank']) ? $contributor['rank'] : '',
+   );
+  return $form;
+}
+
+function biblio_contributors_add_more_callback($form, &$form_state) {
+  return $form['biblio_tabs']['biblio_authors']['biblio_contributors'];
+}
+
+function biblio_contributors_add_more($form, &$form_state) {
+  $form_state['biblio_contrib_count'] += variable_get('biblio_contrib_fields_delta', 2);
+  $form_state['rebuild'] = TRUE;
+}
+
+function biblio_form_node_form_alter(&$form, &$form_state, $form_id) {
+  if ($form_id == 'biblio_node_form') {
+    $form['#pre_render'][] = 'biblio_node_form_pre_render';
+    if (!isset($form['biblio_tabs']['biblio_full_text']) && isset($form['body'])) {
+     unset($form['body']);
+    }
+    if (empty($form_state['biblio_type']) &&
+        empty($form['vid']['#value'])) {
+       foreach (element_children($form) as $form_element) {
+        if (strstr($form_element, 'biblio_')) continue;
+        if (strstr($form_element, 'form_')) continue;
+        if (isset($form[$form_element]['#type']) && $form[$form_element]['#type'] != 'value') {
+          $form[$form_element]['#access'] = FALSE;
+        }
+      }
+     }
+
+  }
+}
+function biblio_node_form_pre_render($form) {
+    if (isset($form['biblio_tabs']['biblio_full_text']) && isset($form['body'])) {
+      $form['biblio_tabs']['biblio_full_text']['body'] = $form['body'];
+      unset($form['body']);
+    }
+  return $form;
+}
+/**
+ * Implementation of hook_validate().
+ *
+ *
+ * Errors should be signaled with form_set_error().
+ */
+function biblio_node_form_validate($form, &$form_state) {
+  if ($form_state['triggering_element']['#value'] == t('Next')
+   || $form_state['triggering_element']['#value'] == t('Change Publication Type')) {
+    $form_state['rebuild'] = TRUE;
+    $form_state['biblio_type'] = $form_state['values']['biblio_type'];
+    if ($form_state['values']['biblio_type'] == 0) {
+      form_set_error('biblio_type', t('Please select a publication type.'));
+    }
+    return;
+  }
+  $format = new stdClass();
+  foreach (_biblio_get_formatted_fields() as $field) {
+    if (isset($form_state['values'][$field]['format'])) {
+      $format->format = $form_state['values'][$field]['format'];
+      if (!filter_access($format)) {
+        form_set_error($field, t('You do not have access to the !format format', array('!format' => $format->format)));
+      }
+    }
+  }
+  if (isset($form_state['values']['biblio_keywords'])) {
+    require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.keywords.inc');
+    if (!is_array($form_state['values']['biblio_keywords'])) {
+      $form_state['values']['biblio_keywords'] = biblio_explode_keywords($form_state['values']['biblio_keywords']);
+    }
+    foreach ($form_state['values']['biblio_keywords'] as $keyword) {
+      if (strlen($keyword) > 255) {
+         form_set_error('biblio_keywords', t('No single keyword can be greater than 255 characters in length, the word: @kw exceeds this length', array('@kw' => $keyword )));
+      }
+    }
+  }
+
+
+  if (isset($form_state['biblio_fields'])) {
+    $vtabs = biblio_node_form_vtab_info();
+    foreach($vtabs as $tab) {
+      $tabs[$tab['tab_id']] = $tab['title'];
+    }
+
+    foreach ($form_state['biblio_fields'] as $key => $fld) {
+      if ($fld['required'] && isset($form_state['values'][$key]) && empty($form_state['values'][$key])) {
+        $tab = $tabs[$fld['vtab']];
+        form_set_error($key, t('The <b><u>@fld</u></b> field (on the <b><i>@tab</i></b> tab) is required', array('@fld' => $fld['title'], '@tab' => $tab)));
+      }
+    }
+  }
+
+}
+
+function _biblio_numeric_year($year) {
+  if (!is_numeric($year)) {
+    if (drupal_strtoupper($year) == drupal_strtoupper(t("In Press")))  return 9998;
+    if (drupal_strtoupper($year) == drupal_strtoupper(t("Submitted"))) return 9999;
+  }
+  else {
+    return $year;
+  }
+}
+
+function _biblio_text_year($year) {
+  if ($year == 9998) return check_plain(variable_get('biblio_inpress_year_text', t('In Press')));
+  if ($year == 9999) return check_plain(variable_get('biblio_no_year_text', t('Submitted')));
+  return $year;
+}
+
+function _biblio_get_formatted_fields() {
+  $fields = &drupal_static(__FUNCTION__);
+  if (!isset($fields)) {
+    $query = db_select('biblio_fields', 'bf');
+    $result =  $query->fields('bf', array('name'))
+    ->condition('type', 'text_format')
+    ->execute();
+    foreach ($result as $field) {
+      $fields[] = $field->name;
+    }
+  }
+  return (array) $fields;
+}
+/**
+ * Prepare a node for submit to database. Contains code common to insert and update.
+ * @param $node
+ * @return none
+ */
+function _biblio_prepare_submit(&$node) {
+  $node->biblio_sort_title = biblio_normalize_title($node->title);
+  if(!isset($node->biblio_year)) $node->biblio_year = 9999;
+  $node->biblio_year = _biblio_numeric_year($node->biblio_year);
+
+  if (variable_get('biblio_auto_citekey', 1) && empty($node->biblio_citekey)) {
+    $node->biblio_citekey = biblio_citekey_generate($node);
+  }
+  foreach (_biblio_get_formatted_fields() as $field) {
+    if (isset($node->$field) && is_array($node->$field)) {
+      $node->biblio_formats[$field] = $node->{$field}['format'];
+      $node->$field = $node->{$field}['value'];
+    }
+    else {
+      $node->biblio_formats[$field] = filter_default_format();
+    }
+  }
+}
+/**
+ * Implementation of hook_insert().
+ *
+ * As a new node is being inserted into the database, we need to do our own
+ * database inserts.
+ */
+function biblio_insert($node) {
+  module_load_include('inc', 'biblio', 'includes/biblio.util');
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  module_load_include('inc', 'biblio', 'includes/biblio.keywords');
+  _biblio_prepare_submit($node);
+  biblio_insert_contributors($node);
+  biblio_insert_keywords($node);
+  $node->biblio_coins = biblio_coins($node);
+  $duplicate = biblio_hash($node);
+  drupal_write_record('biblio', $node);
+  if (isset($duplicate) && $duplicate != $node->nid) { // if this is a potential duplcate, write the nids of the pre-existing and new nodes
+    $dup_map = array('vid' => $duplicate, 'did' => $node->nid);
+    drupal_write_record('biblio_duplicates', $dup_map);
+  }
+
+}
+/**
+ * Implementation of hook_update().
+ *
+ * As an existing node is being updated in the database, we need to do our own
+ * database updates.
+ */
+function biblio_update($node) {
+  module_load_include('inc', 'biblio', 'includes/biblio.util');
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  module_load_include('inc', 'biblio', 'includes/biblio.keywords');
+  _biblio_prepare_submit($node);
+  biblio_update_contributors($node);
+  biblio_update_keywords($node);
+  $node->biblio_coins = biblio_coins($node);
+
+  // Update the node in the database:
+  if (!empty($node->revision)) {
+    drupal_write_record('biblio', $node);
+  }
+  else {
+    drupal_write_record('biblio', $node, 'vid');
+  }
+
+
+}
+/**
+ * Implementation of hook_delete().
+ *
+ * When a node is deleted, we need to clean up related tables.
+ */
+function biblio_delete($node) {
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  module_load_include('inc', 'biblio', 'includes/biblio.keywords');
+    //first remove data from the biblio table
+
+  db_delete('biblio')
+    ->condition('nid', $node->nid)
+    ->execute();
+  //now remove the entries from the contributor linking table
+  biblio_delete_contributors($node);
+  biblio_delete_keywords($node);
+}
+/**
+ * Implementation of hook_load().
+ *
+ * This hook is called
+ * every time a node is loaded, and allows us to do some loading of our own.
+ *
+ */
+function biblio_load($nodes) {
+  module_load_include('inc', 'biblio', 'includes/biblio.util');
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  module_load_include('inc', 'biblio', 'includes/biblio.keywords');
+  $vids = array();
+  foreach ($nodes as $nid => $node) $vids[] = $node->vid;
+
+  $result = db_query('SELECT b.*, bt.name as biblio_type_name
+                      FROM {biblio} b
+                      LEFT JOIN {biblio_types} bt on b.biblio_type = bt.tid
+                      WHERE b.vid IN (:vids)', array(':vids' => $vids), array('fetch' => PDO::FETCH_ASSOC));
+  $contributors = biblio_load_contributors_multiple($vids);
+  $keywords     = biblio_load_keywords_multiple($vids);
+
+  foreach ($result as $record) {
+    if ((isset($record['biblio_url']) || isset($record['biblio_accession_number'])) &&
+         variable_get('biblio_fix_isi_links', 0)) {
+           biblio_fix_isi_links($record);
+    }
+
+    foreach ($record as $key => $value) {
+      $nodes[$record['nid']]->$key = $value;
+    }
+
+    $nodes[$record['nid']]->biblio_year         = _biblio_text_year($record['biblio_year']);
+    $nodes[$record['nid']]->biblio_contributors = isset($contributors[$record['vid']]) ? $contributors[$record['vid']] : array();
+    $nodes[$record['nid']]->biblio_keywords     = isset($keywords[$record['vid']]) ? $keywords[$record['vid']] : array();
+
+    if (empty($record['biblio_coins'])) {
+      $nodes[$record['nid']]->biblio_coins = biblio_coins($nodes[$record['nid']]);
+    }
+    if ($record['biblio_formats'] != NULL) {
+      $nodes[$record['nid']]->biblio_formats = unserialize($record['biblio_formats']);
+    }
+    else {
+      $nodes[$record['nid']]->biblio_formats = array();
+    }
+
+  }
+}
+function biblio_citekey_generate($node) {
+  $php = check_plain(variable_get('biblio_citekey_phpcode', ''));
+  if (empty($php)) {
+    $prefix          = variable_get('biblio_citekey_prefix', '');
+    $primary_field   = variable_get('biblio_citekey_field1', 'nid');
+    $secondary_field = variable_get('biblio_citekey_field2', 'nid');
+    $citekey = (!empty($node->$primary_field)) ? $node->$primary_field : ((!empty($node-> $secondary_field)) ? $node-> $secondary_field : $node->nid);
+    return check_plain($prefix . $citekey);
+  }
+  else {
+    ob_start();
+    $return = eval($php);
+    ob_end_clean();
+    return check_plain(strip_tags((string)$return));
+  }
+}
+
+/**
+ * Implementation of hook_view().
+ *
+ */
+function biblio_view($node, $buildmode = 'full') {
+  global $user;
+  $links = array();
+  $style = biblio_get_style();
+  $base  = variable_get('biblio_base', 'biblio');
+  $base_title = check_plain(variable_get('biblio_base_title', 'Biblio'));
+
+  switch ($buildmode) {
+    case 'full':
+    case 'print':
+      if (variable_get('biblio_hide_bibtex_braces', 0) && !isset($node->view )) {
+        $node->title = biblio_remove_brace($node->title);
+        drupal_set_title(filter_xss($node->title, biblio_get_allowed_tags()));
+      }  // fall through...
+    case 'search_index':
+      switch (variable_get('biblio_node_layout', 'tabular')) {
+        case 'orig' :
+        case 'ft' :
+          $node->content['body']['#markup'] = theme('biblio_long', array('node' => $node, 'base' => $base, 'style_name' => $style));
+          break;
+        case 'cite':
+          $node->content['body']['#markup'] = theme('biblio_style', array('node' => $node, 'base' => $base, 'style_name' => $style));
+          break;
+        case 'tabular' :
+        default :
+          $node->content['body']['#markup'] = theme('biblio_tabular', array('node' => $node, 'base' => $base));
+          break;
+      }
+      break;
+    case 'teaser':
+      $node->content['teaser']['#markup'] = theme('biblio_style', array('node' => $node, 'base' => $base, 'style_name' => $style));
+      break;
+  }
+
+  return $node;
+}
+/**
+ * Implementation of hook_block().
+ *
+ * Generates a block containing the latest poll.
+ */
+function biblio_block_info() {
+  $blocks['recent'] = array(
+    'info' => t('Recent publications'),
+  );
+  return $blocks;
+}
+
+function biblio_block_configure($delta = '') {
+  $form = array();
+  $form['block'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+    '#title' => t('Options'),
+    '#description' => '',
+  );
+  $form['block']['biblio_rowsperblock'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Number of results in the "Recent Publications" block'),
+    '#default_value' => variable_get('biblio_rowsperblock', 4),
+    '#size' => 2,
+    '#maxlength' => 2,
+    '#description' => t('This sets the number of results that will be displayed in the "New Publications" block.')
+  );
+  $form['block']['biblio_block_order'] = array(
+    '#type' => 'radios',
+    '#title' => t('Order by'),
+    '#default_value' => variable_get('biblio_block_order', 'n.created'),
+    '#options' => array(
+      'n.created' => t('Date Created'),
+      'b.biblio_year' => t('Year Published')
+     )
+  );
+  return $form;
+}
+
+function biblio_block_save($delta = '', $edit = array()) {
+  if ($delta == 'recent') {
+    variable_set('biblio_rowsperblock', $edit['biblio_rowsperblock']);
+    variable_set('biblio_block_order', $edit['biblio_block_order']);
+  }
+}
+
+function biblio_block_view($delta = '') {
+  switch ($delta) {
+    case 'recent':
+      $num_in_block = variable_get('biblio_rowsperblock', 4);
+      $block_order = variable_get('biblio_block_order', 'n.created');
+
+      $query = db_select('node', 'n')
+        ->fields('n', array('nid', 'title'))
+        ->condition(db_and()
+        ->condition('n.type', 'biblio')
+        ->condition('n.status', 1))
+        ->orderBy($block_order, 'DESC')
+        ->range(0, $num_in_block);
+      if ($block_order == 'b.biblio_year') {
+        $query->leftJoin('biblio', 'b', 'n.vid=b.vid');
+      }
+      $result = $query->execute();
+
+      $base = variable_get('biblio_base', 'biblio');
+      $block['subject'] = t('Recent Publications');
+      $block['content'] = '<div class="item-list"><ul>';
+      $options['html'] = TRUE;
+
+      foreach ($result as $pub) {
+        $block['content'] .= '<li >' . l(filter_xss($pub->title, biblio_get_allowed_tags()), "node/$pub->nid", $options) . '</li>';
+      }
+      $block['content'] .= '</ul>';
+      if (variable_get('biblio_rss', 0)) {
+        $block['content'] .= theme('feed_icon', array(
+                                  'url'   => url("$base/recent/rss.xml", array('absolute' => TRUE)),
+                                  'title' => t('Recent Publications')));
+      }
+      $block['content'] .= l(t('More...'), $base);
+      $block['content'] .= '</div>';
+
+      return $block;
+      break;
+  }
+}
+
+function biblio_recent_feed() {
+  $numberInFeed = variable_get('biblio_rss_number_of_entries', 10);
+
+  $query = db_select('node', 'n')
+    ->fields('n', array('nid', 'title'))
+    ->condition(db_and()
+      ->condition('n.type', 'biblio')
+      ->condition('n.status', 1))
+    ->orderBy('n.created', 'DESC')
+    ->range(0, $numberInFeed);
+  $result = $query->execute();
+
+  $siteName = variable_get('site_name', 'Drupal');
+  $base = variable_get('biblio_base', 'biblio');
+
+  $channel['title'] = $siteName . ' - ' . t("Recently Added Publications");
+  $channel['link'] = url($base, array('absolute' => TRUE));
+  $channel['description'] = t("This feed lists the %num most recently added publications on %site", array('%num' => $numberInFeed, '%site' => $siteName));
+  $nids = array();
+
+  foreach ($result as $row) {
+    $nids[] = $row->nid;
+  }
+  node_feed($nids, $channel);
+}
+
+function biblio_filter_feed($rss_info, $nids) {
+  $base = variable_get('biblio_base', 'biblio');
+  $channel['title'] = $rss_info['title'];
+  $channel['link'] = url($base . $rss_info['link'], array('absolute' => TRUE));
+  $channel['description'] = $rss_info['description'];
+  node_feed($nids, $channel);
+}
+
+function biblio_get_db_fields() {
+  $fields = array();
+  $fields[] = 'nid';
+  $fields[] = 'vid';
+  $fields[] = 'biblio_type';
+  $result = db_query('SELECT name FROM {biblio_fields} ', array(), array('fetch' => PDO::FETCH_ASSOC));
+  foreach ($result as $field ) {
+    $fields[] = $field['name'];
+  }
+  return $fields;
+}
+
+/*******************************************
+ * Filter
+ * Largely inspired from the footnote module
+ *
+ *******************************************/
+function _biblio_citekey_print($citekey) {
+
+  $nid = db_query("SELECT nid FROM {biblio} WHERE biblio_citekey = :key", array(':key' => $citekey))->fetchField();
+  if ($nid) {
+    $style = biblio_get_style();
+    $base = variable_get('biblio_base', 'biblio');
+    $node = node_load($nid);
+    return theme('biblio_style', array('node' => $node, 'base' => $base, 'style' => $style));
+  }
+  else {
+    return t("Citekey @cite not found", array('@cite' => $citekey));
+  }
+}
+function biblio_filter_info() {
+  $filters['biblio_filter_reference'] = array(
+    'title' => t('Biblio module references &lt;bib&gt; <i>or</i> [bib]'),
+    'description' => t('Use &lt;bib&gt;citekey&lt;/bib&gt; or [bib]citebkey[/bib]to insert automatically numbered references.'),
+    'prepare callback' => '_biblio_filter_reference_prepare',
+    'process callback' => '_biblio_filter_reference_process',
+    'tips callback'    => '_biblio_filter_reference_tips',
+  );
+  $filters['biblio_filter_inline_reference'] = array(
+    'title' => t('Biblio module inline references &lt;ibib&gt; <i>or</i> [ibib]'),
+    'description' => t('Use &lt;bib&gt;citekey&lt;/bib&gt; or [bib]citebkey[/bib]to insert automatically numbered references.'),
+    'prepare callback' => '_biblio_filter_inline_reference_prepare',
+    'process callback' => '_biblio_filter_inline_reference_process',
+    'tips callback'    => '_biblio_filter_inline_reference_tips',
+  );
+  return $filters;
+}
+
+function _biblio_filter_reference_tips($filter, $format, $long = FALSE) {
+  if (!$long) {
+    // This string will be shown in the content add/edit form
+    return t('Use &lt;bib&gt;<i>citekey</i>&lt;/bib&gt; <b><i>or</i></b> [bib]<i>citekey</i>[/bib] to insert automatically numbered references.');
+  }
+  else {
+    return t('You can cite references directly into texts with <code>&lt;bib&gt;<i>citekey</i>&lt;/bib&gt; <b><i>or</i></b> [bib]<i>citekey</i>[/bib]</code>. This will be replaced with a running number (the publication reference) and the publication referenced by the citekey within the &lt;bib&gt; tags will be printed at the bottom of the page (the reference).');
+  }
+}
+
+function _biblio_filter_inline_reference_tips($filter, $format, $long = FALSE) {
+  return t('This creates an in line reference to another publication.');
+}
+
+function _biblio_filter_reference_prepare($text, $filter, $format, $langcode, $cache, $cache_id) {
+  return $text;
+}
+
+function _biblio_filter_inline_reference_prepare($text, $filter, $format, $langcode, $cache, $cache_id) {
+  return $text;
+}
+
+function _biblio_filter_reference_process($text, $filter, $format, $langcode, $cache, $cache_id) {
+  $pattern = array('|\[bib](.*?)\[/bib]|s', '|<bib>(.*?)</bib>|s');
+  if (variable_get('biblio_footnotes_integration', 0) && module_exists('footnotes')) { // this is used with footnote module integration to replace the <bib> tags with <fn> tags
+    $text = preg_replace_callback($pattern, '_biblio_filter_footnote_callback', $text);
+    return $text;
+  }
+  else {
+    $text = preg_replace_callback($pattern, '_biblio_filter_replace_callback', $text);
+    //Replace tag <footnotes> with the list of footnotes.
+    //If tag is not present, by default add the footnotes at the end.
+    //Thanks to acp on drupal.org for this idea. see http://drupal.org/node/87226
+    $footer = '';
+    $footer = _biblio_filter_replace_callback(NULL, 'output footer');
+    if (preg_match('/<bibliography(\/( )?)?>/', $text) > 0) {
+      $text = preg_replace('/<bibliography(\/( )?)?>/', $footer, $text, 1);
+      return $text;
+    }
+    else {
+      return $text . "\n\n" . $footer;
+    }
+  }
+}
+
+function _biblio_filter_inline_reference_process($text, $filter, $format, $langcode, $cache, $cache_id) {
+  $pattern = array('|\[ibib](.*?)\[/ibib]|s', '|<ibib>(.*?)</ibib>|s');
+  $text = preg_replace_callback($pattern, '_biblio_inline_filter_replace_callback', $text);
+  return $text;
+}
+
+function _biblio_inline_filter_replace_callback($matches) {
+    $text =  _biblio_citekey_print($matches[1]) ;
+  return $text;
+}
+
+function _biblio_filter_footnote_callback($matches, $square_brackets = FALSE) {
+  if ($square_brackets)  {
+    $text = '[fn]' . _biblio_citekey_print($matches[1]) . "</fn>";
+  }
+  else {
+    $text = '<fn>' . _biblio_citekey_print($matches[1]) . "</fn>";
+  }
+  return $text;
+}
+/**
+ * Helper function called from preg_replace_callback() above
+ *
+ * Uses static vars to temporarily store footnotes found.
+ * In my understanding, this is not threadsafe?!
+ */
+function _biblio_filter_replace_callback($matches, $op = '') {
+  static $n = 0;
+  static $store_matches = array();
+  $str = '';
+  if ($op == 'output footer') {
+    if ($n > 0) {
+      $str = '<hr /><h3>' . t('References') . '</h3>';
+      $str .= '<div class="references"><ol>';
+      for ($m = 1; $m <= $n; $m++) {
+        $str .= '<li id="reference' . $m . '"><a name="ref' . $m . '">' . _biblio_citekey_print($store_matches[$m -1]) . " </a></li>\n\n";
+      }
+      $str .= '</ol></div>';
+    }
+    $n = 0;
+    $store_matches = array();
+    return $str;
+  }
+  //default op: act as called by preg_replace_callback()
+  $ref = array_search($matches[1], $store_matches);
+  if ($ref === FALSE) {
+    $n++;
+    array_push($store_matches, $matches[1]);    //$stores_matches[$matches[1]] = $n;
+    $ref = $n;
+  }
+  else {
+    $ref++;
+  }
+  $allowed_tags = array();
+  $title = filter_xss($matches[1], biblio_get_allowed_tags());
+  //html attribute cannot contain quotes
+  $title = str_replace('"', "&quot;", $title);
+  //remove newlines. Browsers don't support them anyway and they'll confuse line break converter in filter.module
+  $title = str_replace("\n", " ", $title);
+  $title = str_replace("\r", "", $title);
+  //return '<sup class="see_reference" title="'. $title .'"><a href="#reference'. $n .'">'. $n .'</a></sup>';
+  //$text = '<span><a href="#reference'. $n .'">['. $n .']</a> </span>';
+  //$text = '<span>['. $n .']</span>';
+  //$text .= '<span class="hovertip">'._biblio_citekey_print($title) .'</span>';
+  $text = '<span hovertip="reference' . $ref . '"><a href="#ref' . $ref . '">[' . $ref . ']</a></span>';
+  if (module_exists('hovertip')) {
+    $text = '<span hovertip="reference' . $ref . '"><a href="#ref' . $ref . '">[' . $ref . ']</a></span>';
+    $text .= '<span id="reference' . $ref . '" class="hovertip">' . _biblio_citekey_print($title) . '</span>';
+  }
+  else {
+    $text = '<a href="#ref' . $ref . '" title="Reference ' . $ref . '">[' . $ref . ']</a>';
+
+  }
+  return $text;
+}
+
+function hook_taxonomy_vocabulary_delete($vocabulary) {
+  if ($vocabulary->vid == variable_get('biblio_keyword_vocabulary', FALSE)) {
+    variable_del('biblio_keyword_freetagging');
+    variable_del('biblio_keyword_vocabulary');
+  }
+}
+
+function biblio_term_path($term) {
+  $base = variable_get('biblio_base', 'biblio');
+  if ($term->vid == variable_get('biblio_collection_vocabulary', 0) ) {
+    return ("$base/collection/$term->name");
+  }
+  elseif ($term->vid == variable_get('biblio_keyword_vocabulary', 0) ) {
+    return ("$base/term_id/$term->tid");
+  }
+  else return;
+}
+
+function biblio_hash($node) {
+  static $sums = array();
+  $duplicate = NULL;
+  if (empty($sums)) {
+    $res = db_query("SELECT nid, biblio_md5 FROM {biblio} ");
+    foreach ($res as $md5) {
+      $sums[$md5->biblio_md5] = $md5->nid;
+    }
+  }
+
+  $hash_string = str_replace(' ', '', drupal_strtolower($node->title));
+  if (isset($node->biblio_contributors[0]['lastname'])) {
+    $hash_string .= str_replace(' ', '', drupal_strtolower($node->biblio_contributors[0]['lastname']));
+  }
+  $hash_string .= $node->biblio_year;
+
+  $sum = md5($hash_string);
+
+  if (isset ($sums[$sum])) {
+    $duplicate = $sums[$sum];
+  }
+  else {
+    $sums[$sum] = $node->nid;
+  }
+  $node->biblio_md5 = $sum;
+  return $duplicate; //return the nid of the potential duplicate
+}
+
+function _biblio_profile_access($user, $type = 'profile') {
+  if ($type == 'profile') {
+    $key = 'biblio_show_profile';
+  }
+  elseif ($type == 'menu' && !empty($user) && $user->uid > 0) {
+    $key = 'biblio_my_pubs_menu';
+  }
+  else {
+    return FALSE;
+  }
+  // if user cannot override site settings or user hasn't yet made its selection, we use site default
+  if (!variable_get('biblio_show_user_profile_form', '1') || !isset($user->data[$key])) {
+    return variable_get($key, '0'); // return site default
+  }
+  else {
+    return $user->data[$key]; // return user setting
+  }
+}
+/*
+ * Helper function to get either the user or system style
+ */
+function biblio_get_style() {
+  global $user;
+  if (isset($user->data['biblio_user_style']) && $user->data['biblio_user_style'] != "system") {
+    return $user->data['biblio_user_style'];
+  }
+  return  module_exists('biblio_citeproc') ? variable_get('biblio_citeproc_style', 'ieee.csl') : variable_get('biblio_style', 'cse');
+}
+
+function biblio_get_styles() {
+  $styles = array();
+  if (module_exists('biblio_citeproc')) {
+    $result = db_select('biblio_citeproc_styles', 'csl')
+        ->fields('csl', array('filename', 'title'))
+        ->orderBy('title', 'ASC')
+        ->execute();
+     foreach ($result as $style) {
+       $styles[$style->filename] = $style->title;
+     }
+  }
+  else {
+    $dir = drupal_get_path('module', 'biblio') . '/styles';
+    $files = file_scan_directory($dir, '/biblio_style_..*.inc$/');
+    foreach ($files as $file) {
+      include_once $file->uri;
+      $function = $file->name . '_info';
+      if (function_exists($function)) {
+        $styles = array_merge($styles, call_user_func($function)); //build and array of the short and long names
+      }
+    }
+    ksort($styles);
+  }
+  return $styles;
+}
+
+/**
+ * Implementation of hook_views_api().
+ */
+function biblio_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'biblio') . '/views',
+  );
+}
+
+function biblio_fix_isi_links(&$node) {
+  $isi = check_plain(variable_get('biblio_isi_url', 'http://apps.isiknowledge.com/InboundService.do?Func=Frame&product=WOS&action=retrieve&SrcApp=EndNote&Init=Yes&SrcAuth=ResearchSoft&mode=FullRecord&UT='));
+  if (isset($node['biblio_url']) && preg_match ('/Go\s*to\s*ISI/', $node['biblio_url'])) {
+    $node['biblio_url'] = str_replace('<Go to ISI>://', $isi, $node['biblio_url']);
+  }
+  if (isset($node['biblio_accession_number']) && preg_match ('/^ISI:/', $node['biblio_accession_number'])) {
+    $node['biblio_accession_number'] = str_replace("ISI:", $isi, $node['biblio_accession_number']);
+  }
+}
+
+function biblio_get_allowed_tags() {
+  return array('a', 'b', 'i', 'u', 'sub', 'sup', 'span');
+}
+
+function biblio_get_title_url_info($node) {
+  return array('link' =>  ((variable_get('biblio_link_title_url', 0) && !empty($node->biblio_url)) ? $node->biblio_url : "node/$node->nid"  ),
+               'options' =>
+                  array('attributes' => (variable_get('biblio_links_target_new_window', FALSE)) ? array('target' => '_blank') : array(),
+                        'html' => TRUE),
+                );
+}
+
+
+/**
+ * @param string $type (can be one of "type_names", "type_map" or "field_map")
+ * @param string $format (tagged, ris, endnote_xml8 etc...)
+ * @return array $map
+ */
+function biblio_get_map($type, $format) {
+  $result = db_select('biblio_type_maps', 'btm')
+    ->fields('btm', array($type))
+    ->condition('format', $format)
+    ->execute()
+    ->fetchField();
+
+  $map = unserialize($result);
+
+  if ($type == 'export_map' && empty($map)) {
+    $schema = drupal_get_schema('biblio');
+    $fieldnames = array_keys($schema['fields']);
+    asort($fieldnames);
+    $map = array_fill_keys($fieldnames, 1);
+  }
+
+  drupal_alter('biblio_map', $map, $type, $format);
+  return $map;
+}
+
+function biblio_save_map($maps) {
+    db_insert('biblio_type_maps')
+      ->fields($maps)
+      ->execute();
+}
+/**
+ * @param string $type (can be one of "type_names", "type_map" or "field_map")
+ * @param string $format (tagged, ris, endnote_xml8 etc...)
+ * @param array  $map
+ */
+function biblio_set_map($type, $format, $map) {
+    $map[$type] = serialize($map);
+    $map['format'] = $format;
+    drupal_write_record('biblio_type_maps', $map, 'format');
+}
+
+function biblio_reset_map($type, $format) {
+  module_invoke_all($format . '_map_reset', $type);
+}
+
+function biblio_field_extra_fields() {
+  module_load_include('inc', 'biblio', 'includes/biblio.fields');
+  return  _biblio_field_extra_fields();
+}
+
+//Fixes node export importing issue #826506
+function biblio_node_export_node_alter($node, $original_node) {
+  if ($node->type == 'biblio' && isset($node->biblio_contributors) && is_array($node->biblio_contributors)) {
+    foreach ($node->biblio_contributors as $n => $value) {
+      unset($node->biblio_contributors[$n]['cid']);
+    }
+  }
+}
+
+function biblio_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+  module_load_include('inc', 'biblio', 'includes/biblio.feeds');
+  return  _biblio_feeds_processor_targets_alter($targets, $entity_type, $bundle_name);
+}
+
+function biblio_feeds_importer_default() {
+  module_load_include('inc', 'biblio', 'includes/biblio.feeds');
+  $defaults = array();
+  if (module_exists('feeds_oai_pmh')) {
+    $defaults +=  _biblio_feeds_oai_importer_default();
+  }
+
+  return $defaults;
+  }
+
+function biblio_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "feeds" && $api == "feeds_importer_default") {
+    return array("version" => 1);
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/biblio.tokens.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @return multitype:string NULL
+ */
+function biblio_token_info() {
+  $schema = drupal_get_schema('biblio');
+  $fields = array_diff_key($schema['fields'], array('nid' => '', 'vid' => '', 'biblio_formats' => ''));
+  $node_token['biblio']= array(
+      'name' => t('Biblio'),
+      'description' => t('Tokens related to the Biblio content type.'),
+      'type' => 'biblio'
+  );
+  foreach ($fields as $key => $value) {
+    $name = str_replace('biblio_', '', $key);
+    $name = str_replace('_', ' ', $name);
+    $name = ucwords($name);
+    $biblio_tokens[$key] = array(
+        'name' => t($name),
+        'description' => (isset($value['description'])) ? t("!desc" , array('!desc' => $value['description'])) : '',
+    );
+  }
+
+  $biblio_tokens['biblio_first_author'] = array(
+      'name' => t("Author - First"),
+      'description' => 'First author of the publication',
+  );
+  $biblio_tokens['biblio_type_name'] = array(
+      'name' => t("Type Name"),
+      'description' => t('The name of the publication type (i.e. Journal, Book, etc.'),
+  );
+
+
+  $types['biblio'] = array(
+      'name' => t('Biblio'),
+      'description' => t('Tokens related to Biblio node type.'),
+      'needs-data' => 'node',
+  );
+
+/*
+  $types['biblio-authors'] = array(
+      'name' => t('Biblio Authors'),
+      'description' => t('Tokens related to Biblio node type.'),
+      'needs-data' => 'node',
+  );
+  $types['biblio-keywords'] = array(
+      'name' => t('Biblio Keywords'),
+      'description' => t('Tokens related to Biblio node type.'),
+      'needs-data' => 'node',
+  );
+*/
+
+  return array(
+      'types' => $types,
+      'tokens' => array(
+          'biblio' => $biblio_tokens,
+          'node'   => $node_token),
+      );
+}
+
+/**
+ * @param unknown_type $type
+ * @param unknown_type $tokens
+ * @param unknown_type $data
+ * @param unknown_type $options
+ * @return multitype:NULL
+ */
+function biblio_tokens($type, $tokens, $data = array(), $options = array()) {
+  $replacements = array();
+  if ($type == 'node' && !empty($data['node']) && $data['node']->type == 'biblio') {
+    $sanitize = !empty($options['sanitize']);
+    $node = $data['node'];
+    foreach (token_find_with_prefix($tokens, 'biblio') as $name => $original) {
+      switch ($name) {
+        case 'biblio_first_author':
+          $replacements[$original] = $sanitize ? check_plain($node->biblio_contributors[0]['lastname']) : $node->biblio_contributors[0]['lastname'];
+          break;
+        case 'biblio_type_name':
+          $type = db_query('SELECT name FROM {biblio_types} as t WHERE t.tid = :tid', array(':tid' => $node->biblio_type))->fetchField();
+          $replacements[$original] = $sanitize ? check_plain($type) : $type;
+          break;
+        default:
+          $replacements[$original] = $sanitize ? check_plain($node->$name) : $node->$name;
+      }
+    }
+  }
+
+  return $replacements;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/changelog.html	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,326 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>Biblio Change Log</title>
+</head>
+<body>
+
+<h3>7.x-dev</h3>
+<b>New features...</b>
+<ul>
+<li>Added MARC format export to the Biblio MARC module.</li>
+<li><a href="http://drupal.org/node/1853022">#1853022</a> added option to display file attachments as text or icons.</li>
+<li>Added cron process to Biblio PubMed to periodically check for updates to existing PubMed entries.</li>
+<li>Added edit and upload functions for CSL style files on the "admin/config/content/biblio/citeproc/styles" page.</li>
+<li><a href="http://drupal.org/node/1485856">#1485856</a> Contributor and Keyword orphan cleanup is now done using cron rather than on biblio update.</li>
+<li>Added <a href="http://drupal.org/node/1443250">#1443250</a> Formatted text fields now respect the format setting when rendered in Views</li>
+<li>Added a field mapper GUI for the CiteProc module at admin/config/content/biblio/citeproc/map</li>
+<li>Added a "highlight" feature to the "authors" page which allows privileged users to toggle highlighting of potential duplicate authors</li>
+<li><a href="http://drupal.org/node/1140366">#1140366</a> Patch: PubMed XML Bulk Import</li>
+</ul>
+
+<b>Bugs Fixed...</b>
+<ul>
+<li><a href="http://drupal.org/node/1888776">#1888776</a> Fixed: Warning message when importing a journal article via DOI</li>
+<li><a href="http://drupal.org/node/1889886">#1889886</a> Fixed: property of non-object in biblio_handler_citation->render()</li>
+<li><a href="http://drupal.org/node/1890094">#1890094</a> Fixed: Keyword - Taxonomy integration. Taxonomy term reference were not being created.</li>
+<li><a href="http://drupal.org/node/1815032">#1815032</a> Fixed: Array to string conversion in biblio_token_info() in 7.x-1.0-dev</li>
+<li><a href="http://drupal.org/node/1862788#comment-6865332">#1862788</a> Fixed: Can not add additional authors to link list</li>
+<li><a href="http://drupal.org/node/1806214">#1806214</a> Fixed: Feeds module needs input to be an array or it cuts input to first string $value[0]</li>
+<li><a href="http://drupal.org/node/1802264">#1802264</a> Fixed: Views filter "Biblio: Drupal UserID" does not list any Drupal users</li>
+<li><a href="http://drupal.org/node/1202840">#1202840</a> Fixed: Shouldn't print "p. " when the pages field is left empty (CiteProc module)</li>
+<li><a href="http://drupal.org/node/1798244">#1798244</a> Fixed: Publisher field not rendered in CiteProc</li>
+<li><a href="http://drupal.org/node/1781126">#1781126</a> Fixed: Superfluous quotation marks (CiteProc module)</li>
+<li><a href="http://drupal.org/node/1794636">#1794636</a> Fixed: Missing t() in page title</li>
+<li><a href="http://drupal.org/node/1780414">#1780414</a> Fixed: Enforce RIS permitted character set during RIS import - Remove non-printing characters and other "gremlins"</li>
+<li><a href="http://drupal.org/node/1786014">#1786014</a> Fixed: Undefined index: biblio_notes.</li>
+<li><a href="http://drupal.org/node/1509872">#1509872</a> Fixed: PubMed import fails for long lastnames.</li>
+<li><a href="http://drupal.org/node/1497040">#1497040</a> Fixed: Views "Author lastname" sort handler so you can select the author "rank" (1st, 2nd, 3rd) to sort on.</li>
+<li><a href="http://drupal.org/node/1449612">#1449612</a> Fixed: Class attribute passed to theme not an array</li>
+<li><a href="http://drupal.org/node/741212">#741212</a> Fixed: Wrong node count on author/keyword overview pages, when using revisions</li>
+<li><a href="http://drupal.org/node/1206278">#1206278</a> Fixed: Author order not saved when updating an existing Biblio</li>
+<li><a href="http://drupal.org/node/972312">#972312</a> Fixed: casting issue in biblio_save_node() (implmented node_object_prepare)</li>
+<li><a href="http://drupal.org/node/1138636">#1138636</a> Fixed: Show filefield attachment link in list view</li>
+<li><a href="http://drupal.org/node/1049218">#1049218</a> Fixed: Bad URL for sort by links</li>
+<li><a href="http://drupal.org/node/1177038">#1177038</a> Fixed: Call to undefined function mb_regex_encoding()</li>
+<li><a href="http://drupal.org/node/1166300">#1166300</a> Fixed: Notice: Undefined index: class in _biblio_sort_tab() (line 569</li>
+<li><a href="http://drupal.org/node/1145172">#1145172</a> Fixed: Call to undefined function curl_init()</li>
+<li><a href="http://drupal.org/node/1138636">#1138636</a> Fixed: Show filefield attachment link in list view</li>
+<li><a href="http://drupal.org/node/1140366">#1140366</a> Patch: PubMed XML Bulk Import</li>
+<li><a href="http://drupal.org/node/1139432">#1139432</a> Fixed: Biblio Incompatible With Field-fix Branch of Token Module</li>
+<li><a href="http://drupal.org/node/1135326">#1135326</a> Fixed: Notice: Undefined offset </li>
+<li><a href="http://drupal.org/node/1127514">#1127514</a> Patch removes issue numbers from (non journal) chicago style listings. </li>
+<li><a href="http://drupal.org/node/830770">#830770</a> Fixed: Biblio list output not showing filefield path aliases</li>
+<li><a href="http://drupal.org/node/1104928">#1104928</a> Fixed: PubMed Link Setting</li>
+<li><a href="http://drupal.org/node/1104718">#1104718</a> Fixed: PubMed Import multi-paragraph abstracts</li>
+<li><a href="http://drupal.org/node/1055494">#1055494</a> Fixed: Undefined variable: export_map</li>
+<li><a href="http://drupal.org/node/1037350">#1037350</a> Fixed: Notice re: biblio_contributor_id on user edit page</li>
+<li><a href="http://drupal.org/node/1030254">#1030254</a> Fixed: Undefined index: tagged in biblio_tagged_biblio_export_link()</li>
+<li><a href="http://drupal.org/node/1015100">#1015100</a> Fixed: Small nit about $output in biblio_style_classic()</li>
+<li><a href="/node/999776">#999776</a> Fixed: various errors with endnote (XML) import)</li>
+<li><a href="/node/951124#comment-3780688">#951124</a> Fixed: RIS import / implemented import from node form</li>
+<li><a href="/node/987556">#987556</a> Fixed: CSE citation style no delimiter for first author's initials</li>
+<li><a href="/node/978022">#978022</a> Fixed: Parentheses should be removed from Google Scholar link</li>
+<li><a href="/node/978096">#978096</a> Fixed: Missing Magazine Article in tagged endnote publication type mapping</li>
+<li><a href="/node/946362">#946362</a> Fixed: Encoding issue in author formatter</li>
+<li><a href="/node/946492">#946492</a> Fixed: Subsidiary authors not imported by tagged EndNote parser</li>
+  <li><a href="http://drupal.org/node/288957">#288957</a>RIS parser handles BT tag incorrect for types other than BOOK</li>
+  <li><a href="http://drupal.org/node/734682">#734682</a>Theming error - $base not supplied</li>
+  <li>updated German translation (biblio.de.po) by Niels Hackius</li>
+  <li><a href="http://drupal.org/node/502562#comment-2481200">#502562</a> "CrossRef OpenURL Account ID" descriptive text on user profile page enhanced to avoid confusion between different types of  CrossRef accounts </li>
+  <li><a href="http://drupal.org/node/681730">#681730</a>Rendering biblio as citation style for views omits status</li>
+  <li><a href="http://drupal.org/node/670394">#670394</a>fixed MLA Style issue: missing punctuation for Book Chapter type</li>
+  <li><a href="http://drupal.org/node/616754">#616754</a> style_vancouver warning</li>
+  <li><a href="http://drupal.org/node/614970#comment-2193774">#614970</a> fixed extra "biblio-title-vancouver" spans in Vancouver style</li>
+  <li><a href="http://drupal.org/node/614598">#614598</a> fixed Missing } in biblio.module causes errors using multisite</li>
+</ul>
+
+<h3>6.x-dev</h3>
+<b>New features...</b>
+
+<b>Bugs Fixed...</b>
+<ul>
+  <li># row titles in theme_biblio_tabular() not translated</li> 
+  <li><a href="http://drupal.org/node/146758#comment-2184004">#146758</a> fixed missing initialization of the keyword separator string</li>
+  <li># fixed spans being filtered out of biblio listings</li>
+  <li><a href="http://drupal.org/node/611712">#611712</a> fixed Empty href attributes in OpenURL links </li>
+  <li># fixed "keyword" page so that keywords from "unpublished" nodes are not listed (with the exception of the Admin user UID=1, who will still see them )</li>
+  <li># fixed "authors" page so that authors from "unpublished" nodes are not listed (with the exception of the Admin user UID=1, who will still see them)</li>
+  <li># fixed extra period after title in some styles</li>
+  <li><a href="http://drupal.org/node/146760">#146760</a>proper handling of name suffixes</li>
+  <li># fixed Import: Invalid argument supplied for foreach () in biblio.import.export.inc on line 267</li>
+  <li># fixed falformed paragraph tag</li>
+  <li><a href="http://drupal.org/node/597286">#597286</a>searching bibligraphy adds <em></em> around result</li>
+  <li><a href="http://drupal.org/node/584616">#584616</a>Import: Invalid argument supplied for foreach () in biblio.import.export.inc</li>
+  <li><a href="http://drupal.org/node/592750">#592750</a>Error when Block Settings is ordered by Year Published following upgrade from 6.x-1.6 to 6.x-1.7</li>
+</ul>
+
+<h3>6.x-1.7</h3>
+<b>New features...</b>
+<ul>
+  <li>New settings available in "Styling" to allow admin to change the text that is displayed when there is no year of publication available (9999) or the "In Press" text (9998)</li>
+  <li>Reworked the SQL query used for the list display to improve speed at which the list display is sorted.  This is especially noticable on large datasets.</li>
+  <li>Reworked export functions such that the data is streamed to the client node by node thus reducing the memory footprint required to export large datasets.</li>
+  <li>Thanks to <a href="http://drupal.org/user/106698">Filipe Rocha</a> for the Portuguese translation file (biblio.pt-pt.po)</li>
+  <li>Added links to file attachments in the Tagged, bibtex and EndNote 8 export file formats</li>
+  <li>Thanks to Turóczi Attil for the Hungarian translation file (biblio.hu.po)</li>
+</ul>
+<b>Bugs Fixed...</b>
+<ul>
+  <li>fixed potential XSS vulnerability</li>
+  <li><a href="http://drupal.org/node/585332">#585332</a> fixed Can't use the print module in the biblio list page</li>
+  <li> disabled default views so they do not over ride some of the built in paths</li>
+  <li><a href="http://drupal.org/node/570640">#570640</a> fixed author ordering problem when "More Authors" are added on the input form</li>
+  <li><a href="http://drupal.org/node/561722">#561722</a> fixed Order Vocabularies by Weight on Import Screen(s)</li>
+  <li><a href="http://drupal.org/node/561800">#561800</a> fixed Incorrectly placed curly bracket } around table name in db_query</li>
+  <li><a href="http://drupal.org/node/551362">#551362</a> fixed problem with author and keyword edit links when base url has more than one level</li>
+  <li><a href="http://drupal.org/node/502140">#502140</a> fixed typo which prevented removal of BibTex braces in the title with Views display</li>
+  <li><a href="http://drupal.org/node/536062">#536062</a> fixed bug which would overwrite page title if the page had a "View" containing a biblio node</li>
+  <li>fixed bug which prevented the "Alpha" line from being displayed on the "Authors" page when there were no authors to display</li>
+</ul>
+<hr />
+<h3>6.x-1.6</h3>
+<b>New features...</b>
+<ul>
+  <li>Added configurable "type" mapping <a href="http://drupal.org/node/520828">#520828</a>.  This feature allows mapping between various input file format publication types and Biblio publication types.  </li>
+  <li>Added a per-user setting for OpenURL information <a href="http://drupal.org/node/528930">#528930</a></li>
+  <li>EndNote XML files are now formated in the latest XML format by default, good for versions 8 and newer of EndNote. </li>
+  <li>Added new setting in the OpenURL section to set the Site ID (sid) of the OpenURL link </li>
+</ul>
+<b>Bugs Fixed...</b>
+<ul>
+  <li>fixed potential XSS vulnerability</li>
+  <li><a href="http://drupal.org/node/514882">#514882</a> fixed MLA style looks for incorrect year field</li>
+  <li>#------ fixed incorrect link in keyword edit page</li>
+  <li><a href="http://drupal.org/node/513930">#513930</a>fixed Missing '&lt;/ul&gt;' tag in biblio_theme.inc, and also refactored the entire link building process so that the links on the "node" display are built by the same code as the links on the "bibliographic" display</li>
+  <li><a href="http://drupal.org/node/504702">#504702</a>fixed The first [bib] causes a line break with hovertips enabled</li>
+  <li><a href="http://drupal.org/node/501932#comment-1748502">#501932</a>fixed warning generated when new "type" is created and no fields are set "visible", also change the default for new types so that ALL fields will be visible rather than invisible.</li>
+  <li><a href="http://drupal.org/node/497594">#497594</a>removed the manditory requirement for the year of publication to be supplied</li>
+  <li><a href="http://drupal.org/node/502140">#502140</a>fixed Views citation handler does not remove BibTeX brackets</li>
+  <li><a href="http://drupal.org/node/501932">#501932</a>fixed Biblio Search returns error</li>
+  <li><a href="http://drupal.org/node/477438">#477438</a>fixed issue with CrossRef XML parser where it would truncate data with embedded HTML tags, also added the retention of font style (bold, italic, underline, subscript, superscript) information.</li>
+  <li><a href="http://drupal.org/node/477438#comment-1715136">#477438</a>fixed issue with EndNote XML parser where it would truncate data with embedded styles, also added the retention of font style information.</li>
+  <li>#------ fixed issue with author formatting which could cause extra periods before and after initials </li>
+  <li>#------ removed some debug code which was left in the Crossref xml parser by mistake </li>
+  <li><a href="http://drupal.org/node/492214">#492214</a>by scottrigby: biblio: authors views field sql error</li>
+  <li><a href="http://drupal.org/node/486462">#486462</a> Fixed: Arrow images not showing when Drupal is not installed at DocumentRoot</li>
+  <li><a href="http://drupal.org/node/486790">#486790</a> "Edit" links on admin/settings/biblio/author/list are broken  </li>
+  <li><a href="http://drupal.org/node/488214">#488214</a> theme_biblio_long makes bad author links  </li>
+  <li><a href="http://drupal.org/node/486312">#486312</a> User cannot edit biblio entries unless it has 'administer nodes' permission  </li>
+  <li><a href="http://drupal.org/node/477878#comment-1671356">#477878</a> Fixed Views biblio_year field with "In Press" and "Submitted" values </li>
+  <li><a href="http://drupal.org/node/483650#comment-1672390">#483650</a> Google Scholar links not shown in "node" view </li>
+  <li><a href="http://drupal.org/node/467928#comment-1671984">#467928</a> Wrong tool tip on Google Scholar link </li>
+</ul>
+<hr />
+<h3>6.x-1.5</h3>
+<b>New features...</b>
+<ul>
+  <li>Added Views handlers for sorting, filtering and arguments on most fields.</li>
+  <li>Added new settings in the ISI Web of Knowledge section on the admin/settings/biblio page.  Turning this on automatically converts EndNote "Go to ISI" links to valid ISI search links. (ISI subscription required)</li>
+  <li>Added new settings in the links section on the admin/settings/biblio page.  You choose to carry "inline" mode through to all subsequent links.  Inline mode is used primarily by people accessing biblio data from custom code, so the average user will not need this.</li>
+  <li>Added new settings in the links section on the admin/settings/biblio page.  You can now toggle the export links on/off individually as well as the Google Scholar link</li>
+  <li>Added links from each entry to Google Scholar.  Following the link does a Google Scholar search using the title and first authors name.</li>
+  <li>Added a new feature (and setting to turn it on/off) which will allow you to retain BibTex protected capitalization braces in title strings, they will be stripped out on display, but will still be in place when exported in BibTex format. </li>
+  <li>Added a <b><em>new permission</em></b> called "access biblio content" which will allow you to restrict access to any of the biblio pages (biblio, biblio/authors, biblio/keywords etc.) <b>A user <u>MUST</u> have this permission to see anything from the biblio module!</b></li>
+  <li>Added a section to the user profile page to allow entry of CrossRef login information used for DOI lookup</li>
+  <li>Added a new option when selecting taxonomy terms from a vocabulary, you can now choose to copy them to the biblio keyword database or not.  There is a check box on the input and import forms and there is also a new check box in the "Keywords" section of the admin/settings page which sets the default for this option.</li>
+  <li>Added a setting in the links section to toggle the hyperlinks on the author names.</li>
+</ul>
+<b>Bugs Fixed...</b>
+<ul>
+  <li><a href="http://drupal.org/node/150002#comment-1659312">#150002</a> Go to ISI Link </li>
+  <li><a href="http://drupal.org/node/477502">#477502</a> Unescape XML Entities in import from crossref </li>
+  <li><a href="http://drupal.org/node/477432">#477432</a> crossref_unix_parser pulls in extra dois </li>
+  <li><a href="http://drupal.org/node/477448">#477448</a> crossref_unix_parser on multiple isbns </li>
+  <li><a href="http://drupal.org/node/282996">#282996</a> FileField support for Biblio? </li>
+  <li><a href="http://drupal.org/node/469502">#469502</a> problem with viewinline </li>
+  <li><a href="http://drupal.org/node/465834">#465834</a> issn and section fields too small for patent type </li>
+  <li><a href="http://drupal.org/node/472062">#472062</a> Biblio and i18n - Problem with assigned language when importing nodes </li>
+  <li><a href="http://drupal.org/node/471436">#471436</a> Problem with Taxonomy and Biblio Keywords </li>
+  <li><a href="http://drupal.org/node/469328">#469328</a> What to do if Author is an Organization (CSE and APA styles only) </li>
+  <li><a href="http://drupal.org/node/464572">#464572</a> Undefined function taxonomy_vocabulary_load()-installation error </li>
+  <li><a href="http://drupal.org/node/461474">#461474</a> BibTex - ISSN field </li>
+  <li><a href="http://drupal.org/node/461464">#461464</a> BibTex - Inproceedings and inbook - booktitle replaced by series</li>  
+  <li><a href="http://drupal.org/node/461426">#461426</a> BibTex - @incollection interpreted as @book</li>  
+  <li><a href="http://drupal.org/node/461422">#461422</a> BibTex - export - no doi</li>
+  <li><a href="http://drupal.org/node/456750">#456750</a> Content Access Permissions are ignored</li>  
+  <li><a href="http://drupal.org/node/459374">#459374</a> Use of $form_state['storage'] to hold a string/integer (as opposed to an array)</li>
+  <li><a href="http://drupal.org/node/459684">#459684</a> DOI import fails, CrossRef registration required now</li>
+  <li><a href="http://drupal.org/node/455216">#455216</a> Compilation failed: POSIX named classes.. in biblio_theme.inc</li>
+  <li><a href="http://drupal.org/node/456360">#456360</a> Export and Import in Bibtext format changes the citekey</li>
+  <li><a href="http://drupal.org/node/455402">#455402</a> Changes to Biblio Filter</li>
+  <li><a href="http://drupal.org/node/455022">#455022</a> Extend admin pages to set the 'biblio_author_links' variable</li>
+  <li>fixed problem with missing sort arrow images when filtering</li>
+  <li><a href="http://drupal.org/node/460240">#460240</a>fixed keyword export in BibTex and EndNote Tagged formats</li>
+  <li><a href="http://drupal.org/node/453708">#453708</a> Duplicate bibtex export</li>
+  <li><a href="http://drupal.org/node/453298">#453298</a> "Number of items in the RSS feed" not working...</li>
+  <li><a href="http://drupal.org/node/450522">#450522</a> Limit on author initials is not respected in Vancouver style</li>
+  <li><a href="http://drupal.org/node/450030">#450030</a> Minor error on edit authors</li>
+</ul>
+<hr />
+<h3>6.x-1.4</h3>
+<b>Bugs Fixed...</b>
+<ul>
+  <li><a href="http://drupal.org/node/448732">#448732</a> can't save any biblio: "Call to undefined function biblio_explode_keywords()"</li>
+  <li><a href="http://drupal.org/node/448306">#448306</a> preg_replace() error</li>
+</ul>
+<hr />
+<h3>6.x-1.3</h3>
+<b>New features...</b>
+<ul>
+  <li>Added "DOI Lookup" option on the input form. Entering a valid DOI name (number) here will query crossref.org and poplulate the input form with all the data it gets.  You are then presented with the populated form to make further additions/changes prior to saving it to the database.</li>
+  <li>Added "BibTex cut and paste" option to the input form.  Pasting a valid bibTex string into the box will populate the input form with the data and similar to the DOI lookup above, allows you to preview and make changes prior to saving it in the database.</li>
+  <li>Added a new user permission called "edit biblio authors" which allows the user to edit biblio author information but not other biblio settings, unlike "administer biblio" which gives them the right to edit all biblio settings.</li>
+  <li>Changed "Views" integration such that Blblio is no longer a "Base" type of view.  You should now use the "Node" view type to create a view containing biblio information.</li>
+  <li>Added an option to toggle sort links between text and tab type display.</li>
+  <li>Changed Keyword/Taxonomy freetag handling...  The Taxonomy freetag input box is no longer displayed on the input form. All keywords/taxonomy freetags should be entered into the biblio Keywords input box and (if required) the taxonomy freetags will be updated when the keywords are saved.  This keeps the keywords and freetags in sync and avoids the confustion of having two input boxes (one for keywords and one for freetags).</li>   
+</ul>
+<b>Bugs Fixed...</b>
+<ul>
+  <li><a href="http://drupal.org/node/444428">#444428</a> simple mispelled words</li>
+  <li><a href="http://drupal.org/node/437440">#437440</a> Citation Key cannot be longer than 16 </li>
+  <li><a href="http://drupal.org/node/435058">#435058</a> Keywords field length exceeded</li>
+  <li><a href="http://drupal.org/node/439152">#439152</a> Export by keyword</li>
+  <li><a href="http://drupal.org/node/356322">#356322</a> Biblio nodes not XHTML-compliant</li>
+  <li><a href="http://drupal.org/node/355572">#355572</a> Filtering by author should be more lenient / "smart"</li>
+  <li><a href="http://drupal.org/node/340570">#340570</a> inline biblio_db_search layout is broken</li>
+  <li><a href="http://drupal.org/node/442916">#442916</a> Shortening forenames does not use betweenInitialsDelim option</li>
+  <li><a href="http://drupal.org/node/440248">#440248</a> Typo in HTML in _biblio_filter_replace_callback()</li>
+  <li><a href="http://drupal.org/node/438930">#438930</a> edit_authors permission</li>
+  <li><a href="http://drupal.org/node/441104">#441104</a> schema module reports a mismatch</li>
+  <li><a href="http://drupal.org/node/439086">#439086</a> Biblio Keywords and Biblio free tags</li>
+  <li><a href="http://drupal.org/node/435058">#435058</a> Keywords field length exceeded</li>
+  <li><a href="http://drupal.org/node/433198">#433198</a> Shortening forename of authors containing UTF-8 special characters does not work</li>
+  <li><a href="http://drupal.org/node/431688">#431688</a> Interaction between url filter and standard sorting filters</li>
+  <li><a href="http://drupal.org/node/425852">#425852</a> Biblio page title setting ignored</li>
+  <li><a href="http://drupal.org/node/429226">#429226</a> Quotes around title in Vancouver style</li>
+  <li><a href="http://drupal.org/node/421546">#421546</a> Keywords vanish when previewing</li>
+</ul>
+<hr />
+<h3>6.x-1.2</h3>
+<b>New features...</b>
+<ul>
+  <li>Added option to automatically delete authors "orphaned" by the update or deletion of an entry</li>
+  <li>User selectable bibliographic styles, authorized users can choose a style other than the system default on their "edit user" page</li>
+  <li>Author "Link" allows 2 or more authors to be linked together (intended to deal with name changes due to marriage, but could be used for other purposes)</li>
+  </ul>
+<b>Bugs Fixed...</b>
+<ul>
+  <li><a href="http://drupal.org/node/376808">#376808</a> Delete orphaned authors automatically?</li>
+  <li><a href="http://drupal.org/node/415478">#415478</a> Sorting by type without bars</li>
+  <li><a href="http://drupal.org/node/414870">#414870</a> "more" link in the Block for new publications</li>
+  <li><a href="http://drupal.org/node/414380">#414380</a> Only one keyword is shown</li>
+  <li><a href="http://drupal.org/node/412720">#412720</a> Broken download links when filtering with clean URLs (e.g. /biblio/year/2009)</li>
+  <li><a href="http://drupal.org/node/410610">#410610</a> "Hyperlink titles using supplied URL if available" feature does not seem to work.</li>
+  <li><a href="http://drupal.org/node/409952">#409952</a> All Fields appear (even when unchecked) after upgrade from Biblio 5x to 6x</li>
+  <li><a href="http://drupal.org/node/376802">#376802</a> Search index not updated when editing a node </li>
+  <li><a href="http://drupal.org/node/404842">#404842</a> Tabs and styling</li>
+  <li><a href="http://drupal.org/node/404522">#404522</a> Redirection after batch import</li>
+  <li><a href="http://drupal.org/node/397104">#397104</a> Search function sucks :-)</li>
+  <li><a href="http://drupal.org/node/403484">#403484</a> Slightly malformed RIS files are not imported</li>
+  <li><a href="http://drupal.org/node/404080">#404080</a> Typo in hook_menu prevents author type editing</li>
+  <li><a href="http://drupal.org/node/402468">#402468</a> Filter by author, sort both first and secondary authors </li>
+  <li><a href="http://drupal.org/node/401938">#401938</a> First name / Last name order switched</li>
+</ul>
+<hr />
+<h3>6.x-1.1</h3>
+<b>New features...</b>
+<ul>
+  <li>MARC format file import</li>
+  <li>New bibliographic output sytles (AMA, Chicago, MLA, Vancouver)</li>
+  <li>Authors page (biblio/authors) which displays all authors in the database linked to publication lists filtered by that author. ("edit" links are provided for privileged users)</li>
+  <li>Author edit/merge form (merge allows you to merge all instances of the same author which have been entered slightly
+differently. i.e. Smith, J and John Smith are the same person so you merge the two entries into one.)</li>
+  <li>Orphaned author page(admin/settings/biblio/author/orphans), allows you to remove authors who are not associated with any publications from the database</li>
+  <li>Keywords page (biblio/keywords) which displays all keywords in the database linked to publication list filtered by that keyword. ("edit" links are provided for privileged users)</li>
+  <li>Orphaned keyword page (admin/settings/biblio/keyword/orphans) allows you to find and remove orphaned keywords (keywords which are no longer associated with any publications)</li>
+  <li>added 'tabledrag' to admin/settings/biblio/defaults and admin/settings/biblio/types/edit/xxx which allows you to change the order of the fields on the input form by just dragging them to the desired location</li>
+  <li>input your own PHP code to generate cite keys</li>
+</ul>
+<b>Bugs Fixed...</b>
+<ul>
+  <li><a href="http://drupal.org/node/398472">#398472</a> Drupal UserID-Author Mapping problems</li>
+  <li><a href="http://drupal.org/node/396654">#396654</a> Export single reference fails - SQL error</li>
+  <li><a href="http://drupal.org/node/398226">#398226</a> Fatal error: Cannot break/continue 1 level in biblio.module on line 277</li>
+  <li><a href="http://drupal.org/node/396096">#396096</a> Caching problem: no filters for anonymous users</li>
+</ul>
+<hr />
+<h3>6.x-1.0</h3>
+<b>Bugs Fixed...</b>
+<ul>
+  <li>[#141602]</li>
+  <li>[#381190]</li>
+  <li>[#385830]</li>
+  <li>[#387788]</li>
+  <li>[#388722]</li>
+  <li>[#183517]</li>
+  <li>[#376852]</li>
+  <li>[#372820]</li>
+  <li>[#381070]</li>
+  <li>[#376852]</li>
+  <li>[#372038]</li>
+  <li>[#375085]</li>
+  <li>innumerable D5 -&gt; D6 upgrade fixes provided by Robert Haschke (http://drupal.org/user/409889)</li>
+  <li>[#371867]</li>
+  <li>[#372770]</li>
+  <li>[#373107]</li>
+  <li>[#373129]</li>
+  <li>[#372915]</li>
+  <li>[#372238]</li>
+  <li>[#372024]</li>
+  <li>[#354676] fixed inconsistency between page title and breadcrumb</li>
+  <li>[#355480] fixed issue with setting user id on import by none admin users</li>
+  <li>[#357298] fixed another userID related issue</li>
+  <li>[#336344] fixed problem with taxonomy tags not being added to imported entries</li>
+  <li>[#356322] added danep's patch to correct XHTML validation warnings</li>
+  <li>[#355621] fixed PHP4 compatibility problem</li>
+  <li>[#275410] fixed issue where "My Publications" tab on profile pages could not be turned off</li>
+  <li>[#359752] fixed issue related to profile and inline modes</li>
+  <li>[#360391] fixed problem creating database on install with aliased</li>
+  <li>[#365425] fixed Importing bibtex omits Conference title</li>
+  <li>[#365435] fixed URL search doesn't show search keywords</li>
+  <li>[#362696] RIS Import omits Journal Abbreviation field (JA)</li>
+</ul>
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/Name.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Does cutting and matching stuff with a name string.
+ * Note that the string has to be UTF8-encoded.
+ *
+ */
+class HumanNameParser_Name {
+  private $str;
+
+  function __construct($str)
+  {
+    $this->setStr($str);
+  }
+
+  /**
+   * Checks encoding, normalizes whitespace/punctuation, and sets the name string.
+   *
+   * @param String $str a utf8-encoding string.
+   * @return Bool True on success
+   */
+  public function setStr($str)
+  {
+    if (!drupal_validate_utf8($str)){
+      throw new Exception("Name is not encoded in UTF-8");
+    }
+    $this->str = $str;
+    $this->norm();
+    return true;
+  }
+
+  public function getStr()
+  {
+    return $this->str;
+  }
+
+
+  /**
+   * Uses a regex to chop off and return part of the namestring
+   * There are two parts: first, it returns the matched substring,
+   * and then it removes that substring from $this->str and normalizes.
+   *
+   * @param string $regex matches the part of the namestring to chop off
+   * @param integer $submatchIndex	which of the parenthesized submatches to use
+   * @param string	$regexFlags	optional regex flags
+   * @return string	the part of the namestring that got chopped off
+   */
+  public function chopWithRegex($regex, $submatchIndex = 0, $regexFlags = '')
+  {
+    $regex = $regex . "ui" . $regexFlags; // unicode + case-insensitive
+    preg_match($regex, $this->str, $m);
+    $subset = (isset($m[$submatchIndex])) ? $m[$submatchIndex] : '';
+
+    if ($subset){
+      $this->str = preg_replace($regex, ' ', $this->str, -1, $numReplacements);
+      if ($numReplacements > 1){
+        throw new Exception("The regex being used to find the name: '$this->str' has multiple matches.");
+      }
+      $this->norm();
+      return $subset;
+    }
+    else {
+      return '';
+    }
+  }
+
+  /*
+   * Flips the front and back parts of a name with one another.
+  * Front and back are determined by a specified character somewhere in the
+  * middle of the string.
+  *
+  * @param	String $flipAroundChar	the character(s) demarcating the two halves you want to flip.
+  * @return Bool True on success.
+  */
+  public function flip($flipAroundChar)
+  {
+    $substrings = preg_split("/$flipAroundChar/u", $this->str);
+    if (count($substrings) == 2){
+      $this->str = $substrings[1] . " " . $substrings[0];
+      $this->norm();
+    }
+    else if (count($substrings) > 2) {
+      throw new Exception("Can't flip around multiple '$flipAroundChar' characters in: '$this->str'.");
+    }
+    return true; // if there's 1 or 0 $flipAroundChar found
+  }
+
+  /**
+   * Removes extra whitespace and punctuation from $this->str
+   * Strips whitespace chars from ends, strips redundant whitespace, converts whitespace chars to " ".
+   *
+   * @return Bool True on success
+   */
+  private function norm()
+  {
+    $this->str = preg_replace( "#^\s*#u", "", $this->str );
+    $this->str = preg_replace( "#\s*$#u", "", $this->str );
+    $this->str = preg_replace( "#\s+#u", " ", $this->str );
+    $this->str = preg_replace( "#,$#u", " ", $this->str );
+    return true;
+  }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/Parser.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,214 @@
+<?php
+/**
+ * Works with a Name object to parse out the parts of a name.
+ *
+ * Example usage:
+ *		$parser = new Parser("John Q. Smith");
+ *		echo  $parser->getLast() . ", " . $parser->getFirst();
+ *		//returns "Smith, John"
+ *
+ *
+ */
+class HumanNameParser_Parser {
+  private $name;
+  private $nameParts = array();
+  private $leadingInit;
+  private $first;
+  private $nicknames;
+  private $middle;
+  private $last;
+  private $suffix;
+  private $category;
+  private $type;
+  private $literal;
+
+  private $suffixes;
+  private $prefixes;
+
+  /*
+   * Constructor
+  *
+  * @param	mixed $name	Either a name as a string or as a Name object.
+  */
+  public function __construct($name = NULL)
+  {
+    $this->suffixes = array('esq','esquire','jr','sr','2','ii','iii','iv');
+    $this->prefixes = array('bar','ben','bin','da','dal','de la', 'de', 'del','der','di',
+        'ibn','la','le','san','st','ste','van', 'van der', 'van den', 'vel','von');
+    $this->setName($name);
+  }
+
+  public function parseName($name = NULL, $category = NULL) {
+    $this->literal = 0;
+    $this->category = 1;
+    $this->type = 1;
+    if (is_array($name) && isset($name['name'])) {
+      if (isset($name['auth_category']) && !empty($name['auth_category']) && empty($category)) {
+        $this->category = $name['auth_category'];
+      }
+      elseif (!empty($category)) {
+        $this->category = $category;
+      }
+      if (isset($name['auth_type']) && !empty($name['auth_type'])) {
+        $this->type = $name['auth_type'];
+      }
+      $this->nameParts = $name;
+      $this->setName($name['name'], $category);
+    }
+    else {
+      $this->nameParts['name'] = $name;
+      $this->setName($name, $category);
+    }
+
+    return $this->getArray();
+  }
+  /**
+   * Sets name string and parses it.
+   * Takes Name object or a simple string (converts the string into a Name obj),
+   * parses and loads its constituant parts.
+   *
+   * @param	mixed $name	Either a name as a string or as a Name object.
+   */
+  public function setName($name = NULL, $category = NULL){
+    if ($name) {
+      $this->category == $category;
+
+      if (is_object($name) && get_class($name) == "HumanNameParser_Name") { // this is mostly for testing
+        $this->name = $name;
+      }
+      elseif (is_array($name) && isset($name['name'])) {
+        $this->name = new HumanNameParser_Name($name['name']);
+        $this->nameParts = $name;
+      }
+      else {
+        $this->name = new HumanNameParser_Name($name);
+      }
+
+      $this->leadingInit = "";
+      $this->first = "";
+      $this->nicknames = "";
+      $this->middle = "";
+      $this->last = "";
+      $this->suffix = "";
+
+      if ($this->category == 5 || $this->type == 5) {
+        $this->last = $name;
+        $this->literal = TRUE;
+      }
+      else {
+        $this->parse();
+      }
+
+    }
+  }
+
+  public function getleadingInit() {
+    return $this->leadingInit;
+  }
+  public function getFirst() {
+    return $this->first;
+  }
+  public function getNicknames() {
+    return $this->nicknames;
+  }
+
+  public function getMiddle() {
+    return $this->middle;
+  }
+
+  public function getLast() {
+    return $this->last;
+  }
+
+  public function getSuffix() {
+    return $this->suffix;
+  }
+  public function getName(){
+    return $this->name;
+  }
+
+  /**
+   * returns all the parts of the name as an array
+   *
+   * @param String $arrType pass 'int' to get an integer-indexed array (default is associative)
+   * @return array An array of the name-parts
+   */
+  public function getArray($arrType = 'assoc') {
+    $arr = array();
+    $arr['prefix']    = $this->leadingInit;
+    $arr['firstname'] = $this->first;
+    $arr['nicknames'] = $this->nicknames;
+    $arr['initials']  = substr($this->middle, 0, 10);
+    $arr['lastname']  = $this->last;
+    $arr['suffix']    = $this->suffix;
+    $arr['md5']       = md5(json_encode($arr));
+    $arr['literal']   = $this->literal;
+
+    if ($arrType == 'assoc') {
+      return array_merge($this->nameParts, $arr);
+    }
+    else if ($arrType == 'int'){
+      return array_values($arr);
+    }
+    else {
+      throw new Exception("Array must be associative ('assoc') or numeric ('num').");
+    }
+  }
+
+  /*
+   * Parse the name into its constituent parts.
+  *
+  * Sequentially captures each name-part, working in from the ends and
+  * trimming the namestring as it goes.
+  *
+  * @return boolean	true on success
+  */
+  private function parse()
+  {
+    $suffixes = implode("\.*|", $this->suffixes) . "\.*"; // each suffix gets a "\.*" behind it.
+    $prefixes = implode(" |", $this->prefixes) . " "; // each prefix gets a " " behind it.
+
+    // The regex use is a bit tricky.  *Everything* matched by the regex will be replaced,
+    //	but you can select a particular parenthesized submatch to be returned.
+    //	Also, note that each regex requres that the preceding ones have been run, and matches chopped out.
+    $nicknamesRegex =		"/ ('|\"|\(\"*'*)(.+?)('|\"|\"*'*\)) /"; // names that starts or end w/ an apostrophe break this
+    $suffixRegex =			"/,* *($suffixes)$/";
+    $lastRegex =				"/(?!^)\b([^ ]+ y |$prefixes)*[^ ]+$/";
+    $leadingInitRegex =	"/^(.\.*)(?= \p{L}{2})/"; // note the lookahead, which isn't returned or replaced
+    $firstRegex =			"/^[^ ]+/"; //
+
+    // get nickname, if there is one
+    $this->nicknames = $this->name->chopWithRegex($nicknamesRegex, 2);
+
+    // get suffix, if there is one
+    $this->suffix = $this->name->chopWithRegex($suffixRegex, 1);
+
+    // flip the before-comma and after-comma parts of the name
+    $this->name->flip(",");
+
+    // get the last name
+    $this->last = $this->name->chopWithRegex($lastRegex, 0);
+    if (!$this->last){
+      throw new Exception("Couldn't find a last name in '{$this->name->getStr()}'.");
+    }
+
+    // get the first initial, if there is one
+    $this->leadingInit = $this->name->chopWithRegex($leadingInitRegex, 1);
+
+    // get the first name
+    $this->first = $this->name->chopWithRegex($firstRegex, 0);
+    if (!$this->first && $this->category != 5){
+      throw new Exception("Couldn't find a first name in '{$this->name->getStr()}'");
+    }
+
+    // if anything's left, that's the middle name
+    $this->middle = $this->name->getStr();
+    return true;
+  }
+
+
+
+
+
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,2925 @@
+<?php
+/**
+ * @file
+ *   biblio.admin.inc
+ *
+ *   Handles administrative forms and tasks
+ *
+ */
+/**
+* Implementation of hook_settings().
+*/
+function biblio_admin_settings() {
+  $version = '$Name$ $Date$';
+  $version = str_replace('$', '', $version);
+
+
+  $form['biblio_settings'] = array(
+      '#type' => 'vertical_tabs',
+      '#weight' => 0,
+    );
+
+  $form['general'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('General'),
+    '#group' => 'biblio_settings',
+    '#weight' => 0,
+    '#description' => ''
+  );
+
+  $form['general']['biblio_rev'] = array(
+    '#markup' => $version,
+
+  );
+
+  $form['general']['biblio_base'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Base URL'),
+    '#size' => 20,
+    '#default_value' => variable_get('biblio_base', 'biblio'),
+    '#description' => t('This sets the base URL used to access the biblio module (e.g. /biblio ).')
+  );
+  $form['#biblio_base'] = $form['general']['biblio_base']['#default_value'];
+  $form['general']['biblio_base_title'] = array(
+   '#type' => 'textfield',
+    '#title' => t('Biblio page title'),
+    '#size' => 20,
+    '#default_value' => variable_get('biblio_base_title', 'Biblio'),
+    '#description' => t('The page title shown on the base URL.')
+  );
+
+  $form['general']['biblio_rowsperpage'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Number of results per page'),
+    '#default_value' => variable_get('biblio_rowsperpage', 25),
+    '#size' => 6,
+    '#maxlength' => 6,
+    '#description' => t('This sets the number of results that will be displayed per page.')
+  );
+  $form['general']['biblio_view_only_own'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Restrict users such that they can only view their own biblio entries'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_view_only_own', 0),
+    '#description' => t('This option restricts the users capability to view biblio entries.  They will only be able to see the entries which they have created and own.')
+  );
+  $form['general']['biblio_button_hide'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Hide next button in node form'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_button_hide', 1),
+    '#description' => t('If checkbox is set a javascript adds the accesible system class "element-invisible" to the next button in node form. The next button is not needed if javascript is available and listening on changes.')
+  );
+  $form['authors'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Authors'),
+    '#group' => 'biblio_settings',
+    '#weight' => 10,
+    '#description' => ''
+  );
+  $form['authors']['biblio_auto_orphaned_author_delete'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Automatically delete orphaned authors'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_auto_orphaned_author_delete', 0),
+    '#description' => t('Orphaned authors are those which are no longer linked to any entries as the result of a biblio update or delete. This requires a functioning "cron" process.')
+  );
+  $form['authors']['biblio_orphan_clean_interval'] = array(
+    '#type' => 'radios',
+    '#title' => t('Orphaned author cleaning frequency'),
+    '#default_value' => variable_get('biblio_orphan_clean_interval', 24 * 60 * 60),
+    '#options' => array(
+      0 => t('Every CRON run'),
+      3600 => t('Hourly'),
+      86400 => t('Daily'),
+      604800 => t('Weeekly'),
+    ),
+    '#description' => t('How frequently should we check for and delete orphans.'),
+    '#states' => array(
+      'invisible' => array(
+          'input[name="biblio_auto_orphaned_author_delete"]' => array('checked' => FALSE),
+       ),
+    ),
+  );
+  $form['authors']['biblio_init_auth_count'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Number of contributor fields to initially display on the input form'),
+    '#size' => 2,
+    '#maxlength' => 2,
+    '#default_value' => variable_get('biblio_init_auth_count', 4),
+    '#description' => t('Increasing this value will increase the number of input fields displayed in the contributors section of the input form')
+  );
+  $form['authors']['biblio_contrib_fields_delta'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Number of fields added by the "Add more" button on the contributor input form'),
+    '#size' => 2,
+    '#maxlength' => 2,
+    '#default_value' => variable_get('biblio_contrib_fields_delta', 2),
+    '#description' => t('This number of blank fields will be added to the contributors section of the input form each time the "Add more" button is pressed.')
+  );
+  $form['bibtex'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('BibTex settings'),
+    '#group' => 'biblio_settings',
+    '#weight' => 20,
+    '#description' => ''
+  );
+  $form['bibtex']['biblio_hide_bibtex_braces'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Retain bibtex\'s {Protected} capitalization in the title string, but hide the braces on display'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_hide_bibtex_braces', 0),
+    '#description' => ''
+  );
+
+  $result = db_query("SELECT b.name, bftd.title FROM {biblio_fields} b
+                      INNER JOIN {biblio_field_type} bt ON bt.fid=b.fid
+                      INNER JOIN {biblio_field_type_data} bftd ON bftd.ftdid=bt.ftdid
+                      WHERE bt.tid=0 ORDER by bftd.title ASC ");
+  $schema = drupal_get_schema('biblio');
+  $keys = array_keys($schema['fields']);
+  $options = array();
+  $options['nid'] =  t('Node ID');
+  foreach ($result as $row) {
+    $options[$row->name] = $row->title;
+  }
+  $form['citekey'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Citekey'),
+    '#description' => t('You can alter citekey related settings here.'),
+    '#group' => 'biblio_settings',
+    '#weight' => 30,
+
+  );
+  $form['citekey']['biblio_display_citation_key'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Show citation key in results'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_display_citation_key', 0),
+    '#description' => t('This will output the citekey as the first item in the citation string')
+  );
+  $form['citekey']['biblio_auto_citekey'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Auto generate citekeys if not given'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_auto_citekey', 1),
+    '#description' => t('This option will cause "citekey" entries to be automatically generated if a value is not provided.')
+  );
+  $form['citekey']['biblio_citekey_prefix'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Citekey prefix'),
+    '#default_value' => variable_get('biblio_citekey_prefix', ''),
+    '#size' => 10,
+    '#maxlength' => 10,
+    '#description' => t('This text will be combined with the field choosen below to form the auto generated citekey.')
+  );
+  $form['citekey']['biblio_citekey_field1'] = array(
+    '#type' => 'select',
+    '#title' => t('Primary Citekey  field'),
+    '#default_value' => variable_get('biblio_citekey_field1', 'nid'),
+    '#options' => $options,
+    '#description' => t('Select the field to be used when generating citekeys.')
+  );
+  $form['citekey']['biblio_citekey_field2'] = array(
+    '#type' => 'select',
+    '#title' => t('Secondary Citekey field'),
+    '#default_value' => variable_get('biblio_citekey_field2', 'nid'),
+    '#options' => $options,
+    '#description' => t('If the field above has no value this field will be used.')
+  );
+  // Allow only users to modify PHP code which have PHP block visibility permissions
+  if (user_access('use PHP for block visibility')) {
+    $form['citekey']['biblio_citekey_phpcode'] = array(
+       '#type' => 'textarea',
+       '#title' => t('PHP code for citekey generation'),
+       '#default_value' => variable_get('biblio_citekey_phpcode', ''),
+       '#description' => t('Advanced usage only: PHP code that returns the citekey. Should not include &lt;?php ?&gt; delimiters.')
+    );
+  }
+
+  $form['biblio_crossref'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' =>  TRUE,
+    '#title' => t('CrossRef Login Information'),
+    '#group' => 'biblio_settings',
+    '#weight' => 40,
+  );
+  $link_attrs = array('attributes' => array('target' => '_blank'),
+                      'absolue' => TRUE);
+  $form['biblio_crossref']['biblio_show_crossref_profile_form'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Allow users to override these settings on their "My account" page') ,
+    '#return_value' => 1,
+    '#description' =>  t('If this is selected, a form similar to this section will be available to the user when they edit their own account information.  This will allow them to override the global preferences set here.') ,
+    '#default_value' => variable_get('biblio_show_crossref_profile_form', '1')
+  );
+  $form['biblio_crossref']['biblio_crossref_pid'] = array(
+    '#type' => 'textfield',
+    '#title' => t('CrossRef OpenURL Account ID'),
+    '#default_value' => variable_get('biblio_crossref_pid', ''),
+    '#description' => t('Enter your complimentary CrossRef OpenURL account ID which you can obtain here !url, OR enter your full CrossRef (colon separated) account:password combination.', array('!url' => l(t('OpenURL Account Request Form'), 'http://www.crossref.org/requestaccount/', $link_attrs)))
+  );
+
+  $form['footnotes'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Footnotes'),
+    '#description' => t('You can integrate with the !url module here.', array('!url' => l('footnotes', url("http://www.drupal.org/project/footnotes", array('query' => NULL, 'fragment' => NULL, 'absolute' => TRUE))))),
+    '#group' => 'biblio_settings',
+    '#weight' => 50,
+  );
+  if (!module_exists('footnotes')) {
+    $additional_text = '<div class="admin-dependencies">' . t('Depends on') . ': ' . t('Footnotes') . ' (<span class="admin-disabled">' . t('disabled') . '</span>)</div>';
+    $disabled = TRUE;
+    variable_set('biblio_footnotes_integration', 0);
+  }
+  else {
+    $additional_text = '<div class="admin-dependencies">' . t('Depends on') . ': ' . t('Footnotes') . ' (<span class="admin-enabled">' . t('enabled') . '</span>)</div>';
+    $disabled = FALSE;
+  }
+  $form['footnotes']['biblio_footnotes_integration'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Integration with the footnotes module') . $additional_text,
+    '#disabled' => $disabled,
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_footnotes_integration', 0),
+    '#description' => t('This will convert &lt;bib&gt; tags into &lt;fn&gt; tags.  This will cause intermingled &lt;bib&gt; and &lt;fn&gt; tags to be sequentially numbered.  For this to work, you must put the &lt;bib&gt; filter ahead of the &lt;fn&gt; filter in the filter chain.  If this option is not set, &lt;bib&gt; and &lt;fn&gt; tags will be handled separately.')
+  );
+  $form['isi_wok'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('ISI Web of Knowledge'),
+    '#description' => '',
+    '#group' => 'biblio_settings',
+    '#weight' => 60,
+  );
+  $form['isi_wok']['biblio_fix_isi_links'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Automatically replace "Go to ISI" links with the  URL below'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_fix_isi_links', 0),
+    '#description' => t('This option automatically replaces any fake "Go to ISI" links with the supplied URL to ISI Web of Knowledge.  Note a subscription with ISI is required for these links to function.')
+  );
+  $form['isi_wok']['biblio_isi_url'] = array(
+    '#type' => 'textfield',
+    '#title' => t('ISI Web of Knowledge URL'),
+    '#size' => 128,
+    '#maxlength' => 512,
+    '#default_value' => variable_get('biblio_isi_url', 'http://apps.isiknowledge.com/InboundService.do?Func=Frame&product=WOS&action=retrieve&SrcApp=EndNote&Init=Yes&SrcAuth=ResearchSoft&mode=FullRecord&UT='),
+    '#description' => t('Enter the URL which will replace the "Go to ISI" fake links imported from EndNote')
+  );
+  $form['keywords'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Keywords'),
+    '#description' => '',
+    '#group' => 'biblio_settings',
+    '#weight' => 70,
+  );
+  $form['keywords']['biblio_keyword_sep'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Keyword separator'),
+    '#size' => 2,
+    '#default_value' => variable_get('biblio_keyword_sep', ','),
+    '#description' => t('Enter the character which will be used to separate multiple keywords in the keyword field')
+  );
+  $form['keywords']['biblio_keyword_orphan_autoclean'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Automatically remove orphaned keywords'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_keyword_orphan_autoclean', 1),
+    '#description' => t('This option automatically deletes keywords which are no longer associated with any publications (primarily due to the due to the removal of a publication or editing a keyword).')
+  );
+  $taxo_mesg = '<div class="admin-dependencies">' . t('Depends on') . ': ' . t('Taxonomy') . ' (<span class="admin-disabled">' . t('disabled') . '</span>)</div>';
+  $form['keywords']['biblio_copy_taxo_terms_to_keywords'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Copy any selected taxonomy terms to the biblio keyword database'),
+    '#return_value' => 1,
+    '#default_value' =>  module_exists('taxonomy') ? variable_get('biblio_copy_taxo_terms_to_keywords', 0) : 0,
+    '#disabled' => (!module_exists('taxonomy')),
+    '#description' => module_exists('taxonomy') ? t('If this option is selected, the selected taxonomy terms will be copied to the @base_title keyword database and be displayed as keywords (as well as taxonomy terms) for this entry.', array('@base_title', variable_get('biblio_base_title', 'Biblio'))) : $taxo_mesg
+   );
+  $form['keywords']['biblio_keyword_freetagging'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Use keywords from biblio entries as taxonomy "free tags"'),
+    '#return_value' => 1,
+    '#default_value' => module_exists('taxonomy') ? variable_get('biblio_keyword_freetagging', 0) : 0,
+    '#disabled' => (!module_exists('taxonomy')),
+    '#description' => module_exists('taxonomy') ? t('This option allows user to add keywords (free tags) to describe their documents. These keywords will be registered as taxonomy.') : $taxo_mesg
+  );
+  $vocabularies = module_invoke('taxonomy', 'get_vocabularies');
+  // ... and print a form to select the terms in each of them
+  $taxo_options = array();
+  $taxo_options[0]= '<' . t('none') . '>';
+  if (count($vocabularies)) {
+    foreach ($vocabularies as $voc) {
+      $taxo_options[$voc->vid] =  $voc->name;
+    }
+    $form['keywords']['biblio_keyword_vocabulary'] = array(
+      '#type' => 'select',
+      '#title' => t('Vocabulary'),
+      '#default_value' => variable_get('biblio_keyword_vocabulary', 0),
+      '#options' => $taxo_options,
+      '#description' => t('Select vocabulary (category) to use for free tags.'),
+      '#multiple' => FALSE,
+  //    '#disabled' => (!variable_get('biblio_keyword_freetagging', 0)),
+  //    '#size' => $multiple ? min(9, count($taxo_options)) : 0,
+      '#weight' => 15,
+      '#states' => array(
+        'invisible' => array(
+           'input[name="biblio_keyword_freetagging"]' => array('checked' =>FALSE),
+         ),
+        ),
+    );
+  }
+
+  $form['links'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Links'),
+    '#group' => 'biblio_settings',
+    '#weight' => 80,
+  );
+  $form['links']['export'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#title' => t('Export Links')
+  );
+  $options = array();
+  $export_defaults = array();
+  $options = module_invoke_all('biblio_export_options');
+  if (!empty($options)) {
+    $export_defaults = array_combine(array_keys($options), array_keys($options));
+  }
+  $form['links']['export']['biblio_export_links'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Show export links'),
+    '#default_value' => array_merge($export_defaults, variable_get('biblio_export_links', $export_defaults)),
+    '#options' => $options,
+    '#description' => t('You can select which export links to display here.')
+  );
+  $form['links']['file_attachments'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#title' => t('File Attachments')
+  );
+  $form['links']['file_attachments']['biblio_file_link_type'] = array(
+    '#type' => 'radios',
+    '#title' => t('File attachment display'),
+    '#default_value' => variable_get('biblio_file_link_type', 'text'),
+    '#options' => array(
+      'text' => t('Text'),
+      'icon' => t('Icon'),
+    ),
+    '#description' => t('Display file attachments as either the file name or an icon')
+  );
+
+  $form['links']['google'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#title' => t('Lookup Links')
+  );
+
+  $options = module_invoke_all('biblio_lookup_link_settings');
+  $options +=  array('google' => 'Google Scholar');
+  $lookup_defaults = array_combine(array_keys($options), array_keys($options));
+
+  $form['links']['google']['biblio_lookup_links'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Show lookup links'),
+    '#default_value' => array_merge($lookup_defaults, variable_get('biblio_lookup_links', $lookup_defaults)),
+    '#options' => $options,
+  '#description' => t('You can select which lookup links to display here.')
+  );
+
+  $form['links']['biblio_download_links_to_node'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Download links in "List" view link to "Node" view'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_download_links_to_node', 0),
+    '#description' => t('If selected, the download links in the "List" view will link to the full "Node" view rather than the file itself, the file can then be downloaded from the node view')
+  );
+  $form['links']['biblio_links_target_new_window'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Links open in new browser'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_links_target_new_window', 0),
+    '#description' => t('This causes related URLs to open in a new browser window')
+  );
+
+  $form['links']['biblio_link_title_url'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Hyperlink titles using supplied URL if available'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_link_title_url', 0),
+    '#description' => t('Selecting this links the titles to the supplied URL (if available) rather than the "node" view.')
+  );
+  $form['links']['author'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#title' => t('Author Links')
+  );
+  $form['links']['author']['biblio_author_links'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Hyperlink author names'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_author_links', 1),
+    '#description' => t('This creates a hyperlink on author names which, when clicked, will select entries which contain that author')
+  );
+  $form['links']['author']['biblio_author_link_profile'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Hyperlink author names to author profile page'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_author_link_profile', 0),
+    '#description' => t('This creates a hyperlink on author names which, when clicked, will take the user to the authors profile page')
+  );
+  $form['links']['author']['biblio_author_link_profile_path'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Path to profile page'),
+    '#default_value' => variable_get('biblio_author_link_profile_path', 'user/[user:uid]'),
+    '#description' => t('Do not include a leading "/"')
+  );
+
+  $form['links']['author']['token_tree'] = array(
+      '#theme' => 'token_tree',
+      '#token_types' => array('user'),
+  );
+
+  $form['openurl'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('OpenURL'),
+    '#description' => t('You can set an <a href="http://en.wikipedia.org/wiki/OpenURL">openurl</a> link here'),
+    '#group' => 'biblio_settings',
+    '#weight' => 90,
+  );
+  $form['openurl']['biblio_show_openurl_profile_form'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Allow users to override these settings on their "My account" page') ,
+    '#return_value' => 1,
+    '#description' =>  t('If this is selected, a form similar to this section will be available to the user when they edit their own account information.  This will allow them to override the global preferences set here.') ,
+    '#default_value' => variable_get('biblio_show_openurl_profile_form', '1')
+  );
+
+  $form['openurl']['biblio_baseopenurl'] = array(
+    '#type' => 'textfield',
+    '#title' => t('OpenURL Base URL'),
+    '#size' => 95,
+    '#default_value' => variable_get('biblio_baseopenurl', ''),
+    '#description' => t('This sets your institution\'s base <a href="http://en.wikipedia.org/wiki/OpenURL">OpenURL</a> gateway, which is used to generate OpenURL links. To implement a "Universal" OpenURL system, try using OCLC\'s <a href="http://www.oclc.org/productworks/urlresolver.htm">OpenURL Resolver Registry</a> gateway: <a href="http://worldcatlibraries.org/registry/gateway">http://worldcatlibraries.org/registry/gateway</a>')
+  );
+  $sid = "Biblio:" . variable_get('site_name', 'Drupal');
+  $form['openurl']['biblio_openurl_sid'] = array(
+    '#type' => 'textfield',
+    '#title' => t('OpenURL Site ID'),
+    '#size' => 95,
+    '#default_value' => variable_get('biblio_openurl_sid', $sid),
+    '#description' => t('This sets your institution\'s site name, some link resolvers will require a specific Site ID in order to process your requests.')
+  );
+  $form['openurl']['biblio_openurlimage'] = array(
+    '#type' => 'textfield',
+    '#title' => t('OpenURL Image'),
+    '#size' => 95,
+    '#default_value' => variable_get('biblio_openurlimage', ''),
+    '#description' => t('Enter a path to your image here, this image will be used as button which when clicked will find the entry via the OpenURL link')
+  );
+  // Add profile page settings... this is done in a fucntion so it can be reused elsewhere
+  $form['biblio_profile'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' =>  TRUE,
+    '#title' =>  t('Profile pages'),
+    '#group' => 'biblio_settings',
+    '#weight' => 100,
+  );
+  $form['biblio_profile'] += _biblio_get_user_profile_form();
+  //
+  if (!module_exists('search')) {
+    $search_text = '<div class="admin-dependencies">' . t('Depends on') . ': ' . t('Search') . ' (<span class="admin-disabled">' . t('disabled') . '</span>)</div>';
+    $search_disabled = TRUE;
+    variable_set('biblio_footnotes_integration', 0);
+  }
+  else {
+    $search_text = '<div class="admin-dependencies">' . t('Depends on') . ': ' . t('Search') . ' (<span class="admin-enabled">' . t('enabled') . '</span>)</div>';
+    $search_disabled = FALSE;
+  }
+  $form['search'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#description' => $search_text,
+    '#title' => t('Search'),
+    '#group' => 'biblio_settings',
+    '#weight' => 110,
+  );
+  $form['search']['biblio_search'] = array(
+    '#type' => 'checkbox',
+    '#disabled' => $search_disabled,
+    '#title' => t('Enable a search box on the biblio page.'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_search', 0),
+    '#description' => t('Shows a search box on the biblio page that returns drupal search results in the biblio style.')
+  );
+  $form['search']['biblio_search_button_text'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Search button text'),
+    '#disabled' => $search_disabled,
+    '#size' => 95,
+    '#default_value' => variable_get('biblio_search_button_text', t('Biblio search')),
+    '#description' => t('This allows you to customize the text on the search button, it defaults to "Biblio search".')
+  );
+  $form['search']['biblio_index'] = array(
+    '#type' => 'checkbox',
+    '#disabled' => $search_disabled,
+    '#title' => t('Re-/Index a biblio node when creating or updating.'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_index', 0),
+    '#description' => t('A biblio node must be indexed for the drupal search to know its content. You need to check this option if you want to search for a biblio node that you just created or updated. Otherwise you must wait for the cron job to reindex nodes.')
+  );
+  $form['sort'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Sorting'),
+    '#description' => t('You can set the default sorting and ordering for the /biblio page here.'),
+    '#group' => 'biblio_settings',
+    '#weight' => 120,
+  );
+  $form['sort']['biblio_sort'] = array(
+    '#type' => 'select',
+    '#title' => t('Sort by'),
+    '#default_value' => variable_get('biblio_sort', 'year'),
+    '#options' => array(
+      'author'  => t('Author'),
+      'keyword' => t('Keyword'),
+      'title'   => t('Title'),
+      'type'    => t('Type'),
+      'year'    => t('Year')
+    ),
+   '#description' => t('This is the initial default sort.'),
+  );
+  $stop_words = 'a,an,is,on,the';
+  $form['sort']['biblio_stop_words'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Words to remove from the beginning of titles prior to sorting'),
+    '#size' => 60,
+    '#default_value' => variable_get('biblio_stop_words', $stop_words),
+    '#description' => t('A comma separated list of (case insensitive) words to strip from the title for sorting purposes.  NOTE: quotation and punctuation are stripped automatically.')
+  );
+
+  $form['sort']['biblio_sort_tabs'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Show sort links'),
+    '#default_value' => variable_get('biblio_sort_tabs', array('author', 'title', 'type', 'year')),
+    '#options' => array(
+      'author'  => t('Author'),
+      'keyword' => t('Keyword  (<i>Warning: sorting by keyword may produce many duplicates due to the fact that an entry is listed for each keyword attached to it.</i>)'),
+      'title'   => t('Title'),
+      'type'    => t('Type'),
+      'year'    => t('Year')
+    ),
+    '#description' => t('You turn the sorting links at the top of the /biblio page here.')
+  );
+  $form['sort']['biblio_sort_tabs_style'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Show sort links as "tabs"'),
+    '#default_value' => variable_get('biblio_sort_tabs_style', 0),
+    '#return_value' => 1,
+    '#description' => t('This changes the sort links from text links to tabs')
+  );
+  $form['sort']['biblio_order'] = array(
+    '#type' => 'radios',
+    '#title' => t('Order'),
+    '#default_value' => variable_get('biblio_order', 'DESC'),
+    '#options' => array(
+      'DESC' => t('Descending'),
+      'ASC' => t('Ascending')
+    )
+  );
+  $form['style'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Styling'),
+    '#description' => t('You can set the default style for the /biblio page here.'),
+    '#group' => 'biblio_settings',
+    '#weight' => 130,
+  );
+  $form['style']['biblio_no_year_text'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Text to display if no year of publication is available'),
+    '#size' => 95,
+    '#default_value' => variable_get('biblio_no_year_text', t('Submitted')),
+    '#description' => t('The text that is displayed when no date of publication is given or it is deliberately set to <b>9999</b>, it defaults to "Submitted".')
+  );
+  $form['style']['biblio_inpress_year_text'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Text to display if year of publication is set to 9998'),
+    '#size' => 95,
+    '#default_value' => variable_get('biblio_inpress_year_text', t('In Press')),
+    '#description' => t('The text that is displayed when the date of publication is deliberately set to <b>9998</b>, it defaults to "In Press".')
+  );
+  if (module_exists('biblio_citeproc')) {
+    $form['style']['biblio_citeproc_style'] = array(
+      '#type' => 'select',
+      '#title' => t('Style'),
+      '#default_value' =>  variable_get('biblio_citeproc_style', 'ieee.csl'),
+      '#options' => biblio_get_styles(),
+      '#description' => t('Set the bibliographic style of the "list" view.')
+    );
+  }
+  else {
+    $form['style']['biblio_style'] = array(
+      '#type' => 'select',
+      '#title' => t('Style'),
+      '#default_value' => variable_get('biblio_style', 'cse'),
+      '#options' => biblio_get_styles(),
+      '#description' => t('Set the bibliographic style of the "list" view.')
+    );
+  }
+  $form['style']['biblio_node_layout'] = array(
+    '#type' => 'radios',
+    '#title' => t('Node Layout'),
+    '#default_value' => variable_get('biblio_node_layout', 'tabular'),
+    '#options' => array(
+      'orig'    => t('Original'),
+      'ft'      => t('Only Fulltext if available'),
+      'tabular' => t('Tabular'),
+      'cite'    => t('Bibliographic style choosen above')
+    ),
+    '#description' => t('This alters the layout of the "node" (full) view.')
+  );
+  $form['style']['biblio_annotations'] = array(
+    '#type' => 'select',
+    '#title' => t('Annotations'),
+    '#default_value' => variable_get('biblio_annotations', 'none'),
+    '#options' => array(
+      'none'           => t('none'),
+      'biblio_notes'   => t('notes'),
+      'biblio_custom1' => t('custom1'),
+      'biblio_custom2' => t('custom2'),
+      'biblio_custom3' => t('custom3'),
+      'biblio_custom4' => t('custom4'),
+      'biblio_custom5' => t('custom5'),
+      'biblio_custom6' => t('custom6'),
+      'biblio_custom7' => t('custom7')
+    ),
+    '#description' => t('Select a field from which an annotation will be displayed below biblo entry in "short" listings'),
+    '#multiple' => FALSE,
+    '#size' => 0
+  );
+  $form['syndication'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('Syndication'),
+    '#description' => t('You can set the RSS defaults here.'),
+    '#group' => 'biblio_settings',
+    '#weight' => 140,
+  );
+  $form['syndication']['biblio_rss'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Allow RSS feeds of new biblio entries'),
+    '#return_value' => 1,
+    '#default_value' => variable_get('biblio_rss', 0),
+    '#description' => t('This will create an rss feed of the 10 most recent biblio entries. It will be available at /biblio/rss.xml')
+  );
+  $form['syndication']['biblio_rss_number_of_entries'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Number of items in the RSS feed.'),
+    '#default_value' => variable_get('biblio_rss_number_of_entries', 10),
+    '#size' => 6,
+    '#maxlength' => 6,
+    '#description' => t('Limits the number of items in the /biblio/rss.xml feed to this number.')
+  );
+
+  $form = system_settings_form($form);
+  $form['#submit'][] = 'biblio_admin_settings_form_submit';
+  // our submit handler is added after the call to system settings form so that it gets
+  // called after system_settings_form_submit, and thus the variables have been stored already
+  // and the menu will be rebuilt correctly.
+  return ($form);
+}
+/**
+ * Form handler for biblio_admin_settings
+ *
+ */
+function biblio_admin_settings_form_submit($form, &$form_state) {
+//  if ($form_state['values']['biblio_keyword_freetagging'] && $form_state['values']['biblio_keyword_vocabulary']) {
+//    if ($vocabulary = taxonomy_vocabulary_load(variable_get('biblio_keyword_vocabulary', 0))) {
+//      $vocabulary = (array) $vocabulary;
+//      $vocabulary['nodes']['biblio'] = 1;
+//      taxonomy_save_vocabulary($vocabulary);
+//    }
+//  }
+
+  if (($form['#biblio_base'] != $form_state['values']['biblio_base']) ||
+      ($form['biblio_profile']['#biblio_show_profile'] != $form_state['values']['biblio_show_profile']) ||
+      ($form['biblio_profile']['#biblio_my_pubs_menu'] != $form_state['values']['biblio_my_pubs_menu']) )
+  {
+    menu_rebuild();
+  }
+}
+/**
+ * Form constructor for the Publication type edit form.
+ *
+ * @param int $tid
+ *   The publication type.
+ * @return array $form
+ */
+function biblio_admin_types_edit_form($form, &$form_state, $tid = 0) {
+ // $form['#theme'] = 'biblio_admin_types_edit_form';
+ // $form['#tree'] = TRUE;
+  $form['#cache'] = TRUE;
+  $tid = (isset($form_state['pub_type']) ? $form_state['pub_type'] : (int)$tid);
+  $msg = '<div>' . t('On this page you can set type specific "Titles" and "Hints" which will display on the input form.');
+  if ($tid) {
+    $msg .= ' ' . t('Checking the "Visible" box will add the field to the input form, checking "Required" will force the user to supply a value for this field and the weight value changes the order which it is rendered on the form with smaller values floating to the top of the form.
+    <p> Fields which are grayed out on this page have been set to "common" on the !linktobiblioadmin page.</p>', array('!linktobiblioadmin' => l("admin/config/content/biblio/fields", "admin/config/content/biblio/fields")));
+
+  }
+  else {
+    $msg .= ' ' . t('Checking the "Common" box will add the field to all the different publication types. Checking "Required" will force the user to supply a value for the field, checking "Autocomplete" will enable AJAX type auto complete look up for the field when the user is entering data and the weight value changes the order which it is rendered on the form with smaller values floating to the top of the form.');
+  }
+  $msg .= t('Finally, for each author field you can choose a set of author roles. Assigning different roles to authors within the same field, e.g. primary and secondary authors within the authors field, allows to theme them differently.');
+  $msg .= '</div>';
+
+  $form['#redirect'] = 'admin/config/content/biblio/fields';
+  $form['help'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Help'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE
+  );
+  $form['help']['message'] = array(
+    '#markup' => $msg
+  );
+  // get author types
+  $result = db_query("SELECT * FROM {biblio_contributor_type_data} b");
+  $contrib_options = array();
+  foreach ($result as $contrib_type) {
+      $contrib_options[$contrib_type->auth_type] = $contrib_type->title;
+      $contrib_hints[$contrib_type->auth_type] = $contrib_type->hint;
+  }
+
+  // first get all of the field info
+  if ($tid) {
+    $result = db_query("SELECT bf.*, bftd.*,  bft.vtab, bft.common, bft.visible, bft.autocomplete, bft.weight, bft.required, bt.name AS type_name
+                        FROM {biblio_fields} AS bf
+                        INNER JOIN {biblio_field_type} AS bft ON bft.fid=bf.fid
+                        INNER JOIN {biblio_field_type_data} AS bftd ON bftd.ftdid=bft.ftdid
+                        INNER JOIN {biblio_types} AS bt ON bt.tid=bft.tid
+                        WHERE bft.tid=:tid", array(':tid' => $tid), array('fetch' => PDO::FETCH_ASSOC));
+  }
+  else {
+    $result = db_query("SELECT bf.*, bftd.*, bft.vtab, bft.common, bft.visible, bft.autocomplete, bft.weight, bft.required
+                        FROM {biblio_fields} AS bf
+                        INNER JOIN {biblio_field_type} AS bft ON bft.fid=bf.fid
+                        INNER JOIN {biblio_field_type_data} AS bftd ON bftd.ftdid=bft.ftdid
+                        WHERE bft.tid=:tid", array(':tid' => $tid), array('fetch' => PDO::FETCH_ASSOC));
+  }
+
+  foreach ($result as $row) {
+    $fields[$row['fid']] = $row;
+  }
+
+  $types = db_query("SELECT * from {biblio_types} WHERE visible=1 ORDER BY name ASC");
+  $types_options[0] = t('Common');
+  foreach ($types as $type) {
+    $types_options[$type->tid] = $type->name;
+  }
+
+  $form['pub_type'] = array(
+    '#title' => t('Publication type'),
+    '#type' => 'select',
+    '#options' => $types_options,
+    '#attributes' =>  array('onchange' => 'document.getElementById(\'edit-change-type\').click()'),
+    '#default_value' => $tid,
+  );
+
+  $no_js = (!isset($_COOKIE['has_js']) || empty($_COOKIE['has_js']));
+
+  $form['change_type'] = array(
+    '#type'   => 'submit',
+    '#value'  =>  t('Change Publication Type'),
+    '#weight' => -10,
+    '#prefix' => $no_js ? '' :  '<div style="display:none;">',
+    '#suffix' => $no_js ? '' :  '</div>',
+  );
+
+  $form['biblio_tabs'] = array(
+      '#type' => 'vertical_tabs',
+      '#weight' => 0,
+  );
+
+  $form['biblio_tabs'] += biblio_node_form_vtabs();
+
+  // $form['configured_flds'] = array('#tree' => 1);
+  if ($tid) { // show an existing type
+    $typename = $fields[1]['type_name'];
+    $form['type_name'] = array(
+      '#title' => t('Publication type name'),
+      '#type' => 'textfield',
+      '#maxlength' => 64,
+      '#default_value' => $typename,
+      '#required' => TRUE,
+    );
+    $form['top_message'] = array(
+      '#value' => t('Field settings related to @type publications', array('@type' => $typename))
+    );
+    $form['type_id'] = array(
+      '#type' => 'value',
+      '#title' => 'tid',
+      '#value' => $tid
+    );
+  }
+  else {
+    $form['top_message'] = array(
+      '#value' => t('Field settings common to all publication types')
+    );
+
+  }
+  uasort($fields, "biblio_form_sort"); // resort the fields since the weight may have changed
+  $vis_comm = $tid ? 'visible' : 'common';
+  $options["$vis_comm"] = '';
+  $options['required'] = '';
+  if ($tid == 0) {
+     $options['autocomplete'] = '';
+  }
+  foreach ($fields as $key => $fld) {
+    if ($fld['type'] == 'contrib_widget') {
+      continue;
+    }
+    $def_values[$fld['name']] = array();
+    if ($tid) {
+      if ($fld['visible'] ) {
+        array_push($def_values[$fld['name']], 'visible');
+      }
+      if ($fld['required']) {
+        array_push($def_values[$fld['name']], 'required');
+      }
+    }
+    else {
+      if ($fld['common']) {
+        array_push($def_values[$fld['name']], 'common');
+      }
+      if ($fld['required']) {
+        array_push($def_values[$fld['name']], 'required');
+      }
+      if ($fld['autocomplete']) {
+        array_push($def_values[$fld['name']], 'autocomplete');
+      }
+    }
+    $disabled = $tid ? ($fld['common'] ? 1 : 0) : 0;
+    $form_state['tab_defaults'][$key]['common'] = $disabled;
+
+    $tab_data[$fld['vtab']][$key]['#parents'] = array('biblio_tabs', $key);
+    $tab_data[$fld['vtab']][$key]['name'] = array(
+      '#type' => 'markup',
+      '#markup' => check_plain($fld['name']),
+      '#weight' => $fld['weight']
+    );
+    $tab_data[$fld['vtab']][$key]['title'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $fld['title'],
+      '#size' => 15,
+      '#weight' => $fld['weight'],
+      '#disabled' => $disabled
+    );
+    $form_state['tab_defaults'][$key]['title']['default'] = $fld['title']; //we need store the default to see if it's changed later
+    $form_state['tab_defaults'][$key]['title']['disabled'] = $disabled;
+
+    $tab_data[$fld['vtab']][$key]['hint'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $fld['hint'],
+      '#size' => 20,
+      '#weight' => $fld['weight'],
+      '#disabled' => $disabled
+    );
+    $form_state['tab_defaults'][$key]['hint']['default'] = $fld['hint'];
+    $form_state['tab_defaults'][$key]['hint']['disabled'] = $disabled;
+
+    $tab_data[$fld['vtab']][$key]['weight'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $fld['weight'],
+      '#size' => 2,
+      '#weight' => $fld['weight'],
+      //'#disabled' => $disabled
+    );
+    $tab_data[$fld['vtab']][$key]['checkboxes'] = array(
+      '#type' => 'checkboxes',
+      '#options' => $options,
+      '#default_value' => $def_values[$fld['name']],
+      '#weight' => $fld['weight'],
+      //'#disabled' => $disabled
+    );
+    $tab_data[$fld['vtab']][$key]['ftdid'] = array(
+      '#type' => 'value',
+      '#value' => $fld['ftdid']
+    );
+
+  }
+  if ($tid) {
+    $header = array('', t('Field Name'), t('Title'), t('Hint'), t('Visible'), t('Required'), '');
+  }
+  else {
+    $header = array('', t('Field Name'), t('Default Title'), t('Hint'),  t('Common'), t('Required'), t('Autocomplete'), '');
+  }
+
+  foreach ($tab_data as $key => $rows) {
+    $form['biblio_tabs'][$key][] = array(
+      '#theme' => 'biblio_field_tab',
+      '#header' => $header,
+      'rows' => $rows,
+    );
+  }
+
+  $form['biblio_tabs']['#tree']  = TRUE;
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save')
+  );
+
+  return $form;
+}
+
+/**
+ * Form handler for biblio_admin_types_edit_form
+ */
+function biblio_admin_types_edit_form_submit($form, &$form_state) {
+  if ($form_state['triggering_element']['#value'] == t('Change Publication Type')) {
+    $form_state['rebuild'] = TRUE;
+    $form_state['pub_type'] = $form_state['values']['pub_type'];
+    $form_state['input'] = array();
+    return;
+  }
+  $tid = isset($form_state['values']['type_id']) ? $form_state['values']['type_id'] : 0;
+
+  if ($tid) {
+    // save publication type name
+    $type_name_record = array(
+      'tid' => $tid,
+      'name' => $form_state['values']['type_name'],
+    );
+
+    db_update('biblio_types')
+      ->fields($type_name_record)
+      ->condition('tid', $tid)
+      ->execute();
+    biblio_locale_refresh_types($tid);
+  }
+
+  $hide_other_fields = isset($form_state['values']['hide_other_fields']) ? $form_state['values']['hide_other_fields'] : 0;
+  variable_set('biblio_hide_other_fields', $hide_other_fields);
+
+  // save other field data
+  foreach ($form_state['values']['biblio_tabs'] as $fid => $values) {
+    $update = FALSE;
+    $val = array();
+    $link = array();
+    if (is_int($fid)) {
+      $common = $form_state['tab_defaults'][$fid]['common'];
+      $link['fid'] = $fid;
+      $link['tid'] = $tid;
+      foreach ($values as $name => $value) {
+        $disabled = !empty($form_state['tab_defaults'][$fid][$name]['disabled']) ? TRUE : FALSE;
+        if (!$disabled) {
+          $default_value = isset($form_state['tab_defaults'][$fid][$name]['default']) ? $form_state['tab_defaults'][$fid][$name]['default'] : '';
+          if ($name == 'checkboxes') {
+            $link['visible']      = (!empty($value['visible'])) ? 1 : 0;
+            $link['required']     = (!empty($value['required'])) ? 1 : 0;
+            if ($tid == 0) {
+              $link['common']       = (!empty($value['common'])) ? 1 : 0;
+              $link['autocomplete'] = (!empty($value['autocomplete'])) ? 1 : 0;
+            }
+          }
+          elseif ($name == 'weight') {
+            $link['weight'] = $value;
+          }
+          else {
+            $val[$name] = $common ? $default_value : $value;
+            if (!$update) {
+              $update = ($default_value != $val[$name]) ? $form_state['values']['biblio_tabs'][$fid]['ftdid'] : FALSE;
+            }
+          }
+        }
+      }
+      if ($update == $fid && $link['tid']) { // we just changed a default value, so create a new entry in biblio_field_type_data
+        $new_ftdid = variable_get('biblio_last_ftdid', 100);
+        variable_set('biblio_last_ftdid', $new_ftdid + 1);
+        $val['ftdid'] = $new_ftdid;
+        $link['ftdid'] = $new_ftdid;
+        $link['cust_tdid'] = $new_ftdid;
+        drupal_write_record('biblio_field_type_data', $val);
+
+      }
+      elseif ($update >= 100 && $link['tid']) { // we are updating an existing entry
+        $val['ftdid'] = $form_state['values']['biblio_tabs'][$fid]['ftdid'];
+        drupal_write_record('biblio_field_type_data', $val, 'ftdid');
+
+      }
+      elseif ($update == $fid) { // changing the defaults
+        $val['ftdid'] = $fid;
+        drupal_write_record('biblio_field_type_data', $val, 'ftdid');
+      }
+
+      drupal_write_record('biblio_field_type', $link, array('fid', 'tid'));
+
+      if ($tid == 0) {
+        if ($link['common']) {
+          //        $query = "UPDATE {biblio_field_type} SET ftdid = %d, common = %d, visible = %d WHERE fid = %d";
+          //        db_query($query, array($fid, 1, 1, $fid));
+          db_update('biblio_field_type')
+          ->fields(array('ftdid' => $fid, 'common' => 1, 'visible' => 1))
+          ->condition('fid', $fid)
+          ->execute();
+        }
+        else { // not common, so change pointer back to customizations if available
+          $query = "UPDATE {biblio_field_type} SET ftdid = cust_tdid, common = :comm WHERE fid = :fid";
+          db_query($query, array(':comm' => 0, ':fid' => $fid));
+          //        db_update('biblio_field_type')
+          //          ->fields(array('ftdid' => $fid, 'common' => 0, 'visible' => 1))
+          //          ->condition('fid', $fid)
+          //          ->execute();
+        }
+        // set the autocomplete bit on this field for all the types
+        //      $query = "UPDATE {biblio_field_type} SET autocomplete = %d WHERE fid = %d";
+        //      db_query($query, array($link['autocomplete'], $fid));
+        db_update('biblio_field_type')
+        ->fields(array('autocomplete' => $link['autocomplete']))
+        ->condition('fid', $fid)
+        ->execute();
+      }
+    }
+  }
+  drupal_set_message(t("The changes have been saved."));
+
+  // Clear the cached pages and menus:
+  //menu_rebuild();
+
+  // Refresh translatable field strings.
+  biblio_locale_refresh_fields($tid);
+}
+
+/**
+ * Outputs a page containing "edit" links for each enabled import/export module.
+ *
+ *   Each link goes to a page allowing the user to modifiy the field mapping for
+ *   each of the import/export formats.
+ */
+function biblio_admin_io_mapper_page() {
+  $formats = module_invoke_all('biblio_mapper_options');
+  asort($formats);
+
+  foreach ($formats as $key => $value) {
+    $rows[] = array(
+      $value['title'],
+      l(t('edit'), 'admin/config/content/biblio/iomap/edit/' . $key),
+    );
+  }
+
+  if (count($rows) == 0) {
+    drupal_set_message(t('There are no import/export modules enabled. Please go to the !l page and enable at least one.',
+        array('!l' => l(t('modules'), "admin/modules"))));
+  }
+
+  $header = array(t('Format'), t('Action'));
+  return theme('table', array('header' => $header, 'rows' => $rows));
+}
+
+/**
+ * @param unknown_type $format
+ * @param unknown_type $exportable
+ * @return Ambigous <multitype:string multitype:string  NULL , multitype:number multitype:string  multitype:string Ambigous <> Ambigous <string, unknown>  , multitype:string >
+ */
+function biblio_admin_io_mapper_form($form, $form_state, $format, $exportable = TRUE) {
+  $formats = module_invoke_all('biblio_mapper_options');
+  $form = array();
+  if (isset($formats[$format])) {
+    $form['title'] = array(
+      '#prefix' => '<h3>',
+      '#markup' => check_plain($formats[$format]['title']) . ' ' . t('file format mapping'),
+      '#suffix' => '</h3>',
+    );
+    $form['fileformat_title'] = array(
+      '#type' => 'hidden',
+      '#value' => $formats[$format]['title'],
+    );
+
+  }
+  $form['fileformat'] = array(
+    '#type' => 'hidden',
+    '#value' => $format,
+  );
+  $form['fileformat_export'] = array(
+    '#type' => 'hidden',
+    '#value' => isset($formats[$format]['export']) ? $formats[$format]['export'] : $exportable,
+  );
+
+  $form['typemap'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Publication types'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE
+  );
+  $form['typemap']['#theme'] = 'biblio_admin_type_mapper_form';
+  $form['typemap']['#tree'] = TRUE;
+  $form['typemap'] += biblio_admin_type_mapper_form($format);
+
+  $form['fieldmap'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Data fields'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE
+  );
+  $form['fieldmap']['#theme'] = 'biblio_admin_field_mapper_form';
+  $form['fieldmap']['#tree'] = TRUE;
+  $form['fieldmap'] += biblio_admin_field_mapper_form($format, $exportable);
+
+  return $form;
+}
+/**
+ * @param unknown_type $variables
+ * @return unknown
+ */
+function theme_biblio_admin_io_mapper_form($variables) {
+  $form = $variables['form'];
+  $header = $rows = array();
+  $output = drupal_render($form['title']);
+  $rows[] = array('data' => array(
+                  array('data' => drupal_render($form['typemap']), 'style' => 'vertical-align:top'),
+                  array('data' => drupal_render($form['fieldmap']), 'style' => 'vertical-align:top'),
+                )
+             );
+  $output .= theme('table', array('header' => $header, 'rows' => $rows));
+  $output .= drupal_render_children($form);
+
+  return $output;
+}
+
+/**
+ * @param unknown_type $format
+ * @param unknown_type $type
+ * @return multitype:string NULL multitype:string
+ */
+function biblio_admin_io_mapper_add_form($form, &$form_state, $format, $type) {
+  $formats = module_invoke_all('biblio_mapper_options');
+
+  if ($type == 'pubtype') {
+    $title = 'Publication Type';
+    $desc = t('This is the name of the type identifier, exactly as it appears in the file');
+    $submit = array('biblio_admin_io_mapper_add_form_pubtype_submit');
+  }
+  if ($type == 'field') {
+    $title = 'Field name';
+    $desc = t('This is the name of the field identifier, exactly as it appears in the file');
+    $submit = array('biblio_admin_io_mapper_add_form_field_submit');
+  }
+  $form['fileformat'] = array(
+    '#type' => 'hidden',
+    '#value' => $format,
+  );
+  $form['fileformat_title'] = array(
+    '#type' => 'hidden',
+    '#value' => $formats[$format]['title'],
+  );
+  $form['type_name'] = array(
+      '#type' => 'textfield',
+      '#title' => 'Publication Type',
+      '#required' => TRUE,
+      '#description' => t('This is the name of the type identifier, exactly as it appears in the file'),
+  );
+  $form['type_desc'] = array(
+      '#type' => 'textfield',
+      '#title' => 'Description'
+      );
+  $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Add'),
+      '#submit' => $submit,
+      );
+
+  return $form;
+}
+
+/**
+ * @param unknown_type $variables
+ * @return unknown
+ */
+function theme_biblio_admin_io_mapper_add_form($variables) {
+  $output = '';
+  $form = $variables['form'];
+  $title = $form['fileformat_title']['#value'];
+  drupal_set_title(t('Add new publication type to %title file type', array('%title' => $title)));
+  $output .= drupal_render($form['type_name']);
+  $output .= drupal_render($form['type_desc']);
+  $output .= drupal_render($form['submit']);
+  $output .= drupal_render_children($form);
+  return $output;
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_io_mapper_add_form_pubtype_submit($form, &$form_state) {
+  $names = biblio_get_map('type_names', $form_state['values']['fileformat']);
+  $names[$form_state['values']['type_name']] = $form_state['values']['type_desc'];
+  biblio_set_map('type_names', $form_state['values']['fileformat'], $names);
+  $form_state['redirect'] = 'admin/config/content/biblio/iomap/edit/' . $form_state['values']['fileformat'];
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_io_mapper_add_form_field_submit($form, &$form_state) {
+  $names = biblio_get_map('field_map', $form_state['values']['fileformat']);
+  $names[$form_state['values']['type_name']] = '';
+  biblio_set_map('field_map', $form_state['values']['fileformat'], $names);
+}
+
+/**
+ * @param unknown_type $format
+ * @return Ambigous <multitype:string multitype:string  NULL , multitype:multitype:string  multitype:string unknown number  >
+ */
+function biblio_admin_type_mapper_form($format) {
+  $formats = module_invoke_all('biblio_mapper_options');
+  $form['#file_format_title'] = isset($formats[$format]) ? $formats[$format]['title'] : '';
+  $form['#file_format'] = $format;
+  $names = biblio_get_map('type_names', $format);
+  $map   = biblio_get_map('type_map', $format);
+  ksort($names);
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save publication type mapping'),
+    '#submit' => array('biblio_admin_type_mapper_form_submit'),
+  );
+  $form['reset'] = array(
+    '#type' => 'submit',
+    '#value' => t('Reset publication type mapping to default'),
+    '#submit' => array('biblio_admin_type_mapper_form_reset_submit'),
+  );
+
+  $result = db_query('SELECT t.* FROM {biblio_types} as t WHERE t.tid > 0');
+
+  foreach ($result as $type) {
+    $biblio_type_options[$type->tid] =  $type->name;
+  }
+
+  $biblio_type_options[0] = t('-none-');
+  asort($biblio_type_options);
+
+  $biblio_type_select = array(
+      '#type' => 'select',
+      '#options' => $biblio_type_options,
+  );
+  foreach ($names as $key => $value) {
+    $biblio_type_select['#default_value'] = (isset($map[$key]) ? $map[$key] : 0);
+    $form['type'][$key] = array(
+      'format' => array('#markup' => "<b>" . check_plain($key) . "</b> (<i>" . check_plain($value) . "</i>)"),
+      'biblio' => $biblio_type_select,
+    );
+
+  }
+  return $form;
+}
+
+/**
+ * @param unknown_type $variables
+ * @return unknown
+ */
+function theme_biblio_admin_type_mapper_form($variables) {
+  $form = $variables['form'];
+  $title = $form['#file_format_title'];
+
+   foreach (element_children($form['type']) as $key ) {
+    $rows[] = array(
+    drupal_render($form['type'][$key]['format']),
+    drupal_render($form['type'][$key])
+    );
+  }
+    $rows[] = array(
+    l('[' . t('Add New') . " $title " . t('Publication Type') . ']', 'admin/config/content/biblio/iomap/' . $form['#file_format'] . '/pubtype/add') ,
+    l('[' . t('Add New Biblio Publication Type') . ']', 'admin/config/content/biblio/pubtype/new')
+    );
+  $header = array(
+  $title . ' ' . t('Publication Types'),
+  t('Biblio Publication Type')
+  );
+  $output = theme('table', array('header' => $header, 'rows' => $rows));
+
+  $output .= drupal_render($form['submit']);
+  $output .= drupal_render($form['reset']);
+
+  $output .= drupal_render_children($form);
+  return $output;
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_type_mapper_form_submit($form, $form_state) {
+    foreach ($form_state['values']['typemap']['type'] as $key => $value) {
+      if (is_array($value)) {
+        $map[$key]=$value['biblio'];
+      }
+    }
+    biblio_set_map('type_map', $form_state['values']['fileformat'], $map);
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_type_mapper_form_reset_submit($form, $form_state) {
+    biblio_reset_map('type_map', $form_state['values']['fileformat']);
+    biblio_reset_map('type_names', $form_state['values']['fileformat']);
+}
+
+/**
+ * @param unknown_type $format
+ * @param unknown_type $exportable
+ * @return Ambigous <multitype:string multitype:string  NULL , multitype:number multitype:string  multitype:string Ambigous <> Ambigous <string, unknown>  , multitype:string >
+ */
+function biblio_admin_field_mapper_form($format, $exportable = TRUE) {
+  $formats = module_invoke_all('biblio_mapper_options');
+  $form['#file_format_title'] = isset($formats[$format]) ? $formats[$format]['title'] : '';
+  $form['#file_format'] = $format;
+  $exportable = isset($formats[$format]['export']) ? $formats[$format]['export'] : $exportable;
+  $form['#file_format_export'] = $exportable;
+  $map = biblio_get_map('field_map', $format);
+  $export_map = biblio_get_map('export_map', $format);
+  ksort($map);
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save field mapping'),
+    '#submit' => array('biblio_admin_field_mapper_form_submit'),
+  );
+  $form['reset'] = array(
+    '#type' => 'submit',
+    '#value' => t('Reset field mapping to default'),
+    '#submit' => array('biblio_admin_field_mapper_form_reset_submit'),
+  );
+
+  $schema = drupal_get_schema('biblio');
+  $fieldnames = array_keys($schema['fields']);
+  asort($fieldnames);
+  $biblio_field_options[''] =  t('-none-');
+  $biblio_field_options['title'] =  'title';
+  foreach ($fieldnames as $field) {
+    $biblio_field_options[$field] =  $field;
+  }
+
+  $biblio_field_select = array(
+    '#type' => 'select',
+    '#options' => $biblio_field_options,
+  );
+
+  foreach ($map as $key => $value) {
+    $biblio_field_select['#default_value'] = $map[$key];
+    $form['type'][$key] = array(
+      'format' => array('#markup' => "<b>" . $key . "</b>"),
+      'biblio' => $biblio_field_select,
+      '#tree' => 1,
+    );
+    if ($exportable) {
+      $form['type'][$key]['export'] = array(
+          '#type' => 'checkbox',
+          '#default_value' => isset($export_map[$value]) ? $export_map[$value] : ''
+      );
+    }
+
+  }
+  return $form;
+}
+
+/**
+ * @param unknown_type $variables
+ * @return unknown
+ */
+function theme_biblio_admin_field_mapper_form($variables) {
+  $form = $variables['form'];
+  $title = $form['#file_format_title'];
+
+  foreach (element_children($form['type']) as $key ) {
+    $row = array();
+    $row[] = drupal_render($form['type'][$key]['format']);
+    $row[] = drupal_render($form['type'][$key]['biblio']);
+    if ($form['#file_format_export']) {
+      $row[] = drupal_render($form['type'][$key]);
+    }
+    $rows[] = $row;
+  }
+  $header = array(
+    $title . ' ' . t('field identifier'),
+    t('Biblio schema field'),
+  );
+  if ($form['#file_format_export']) {
+    $header[] = t('Export');
+  }
+  $output = theme('table', array('header'  => $header, 'rows' => $rows));
+  //$output .= l('[' . t('Add New') . " $title " . t('Publication Type') . ']','admin/config/content/biblio/fields/typemap/' . $form['#file_format'] . '/add') . ' ';
+  //$output .= l('[' . t('Add New Biblio Publication Type') . ']','admin/config/content/biblio/fields/type/new') . '<br />';
+  $output .= drupal_render_children($form);
+
+  return $output;
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_field_mapper_form_submit($form, $form_state) {
+  foreach ($form_state['values']['fieldmap']['type'] as $key => $value) {
+    if (is_array($value)) {
+      $map[$key] = $value['biblio'];
+      if ($form_state['values']['fileformat_export']) {
+        $export_map[$value['biblio']] = $value['export'];
+      }
+    }
+  }
+  biblio_set_map('field_map', $form_state['values']['fileformat'], $map);
+  if ($form_state['values']['fileformat_export']) {
+    biblio_set_map('export_map', $form_state['values']['fileformat'], $export_map);
+  }
+
+  //  elseif ($form_state['values']['op'] == t('Add')) {
+  //    $names = biblio_get_map('type_names', $form_state['values']['fileformat']);
+  //    $names[$form_state['values']['type_name']] = $form_state['values']['type_desc'];
+  //    variable_set('biblio_'.$form_state['values']['fileformat'] .'_type_names', $names);
+  //  }
+
+}
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_field_mapper_form_reset_submit($form, $form_state) {
+  biblio_reset_map('field_map', $form_state['values']['fileformat']);
+  biblio_reset_map('export_map', $form_state['values']['fileformat']);
+}
+
+/**
+ * @return unknown
+ */
+function biblio_admin_types_form() {
+  $output = '';
+  $result = db_query('SELECT t.* FROM {biblio_types} as t WHERE t.tid > 0 ORDER BY name ASC');
+  //$rows[] = array('',t('Fields Common To All Types'),l('edit', 'admin/config/content/biblio/types/edit'),'');
+  foreach ($result as $row ) {
+    if ($row->tid < 999) {
+      $rows[] = array(
+        $row->tid,
+        check_plain($row->name),
+        ($row->visible) ? l(t('edit'), 'admin/config/content/biblio/fields/' . $row->tid) : '', ($row->visible) ? l(t('hide'), 'admin/config/content/biblio/pubtype/hide/' . $row->tid) : l(t('show'), 'admin/config/content/biblio/pubtype/show/' . $row->tid)
+      );
+    }
+    else {
+      $rows[] = array(
+        $row->tid,
+        check_plain($row->name),
+        l(t('edit'), 'admin/config/content/biblio/fields/' . $row->tid), l(t('delete'), 'admin/config/content/biblio/pubtype/delete/' . $row->tid)
+      );
+    }
+  }
+  $header = array(
+    t('Type Id'),
+    t('Type Name'), array(
+      'data' => t('Operations'),
+      'colspan' => '2'
+    )
+  );
+  $output .= theme('table', array('header' => $header, 'rows' => $rows));
+  $output .= l(t('Reset to defaults'), 'admin/config/content/biblio/pubtype/reset');
+  return $output;
+}
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @return multitype:string number NULL
+ */
+function biblio_admin_types_add_form($form, &$form_state) {
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Type Name'),
+    '#size' => 20,
+    '#weight' => 1,
+    '#required' => TRUE,
+    '#maxlength' => 64
+  );
+  $form['description'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Description'),
+    '#size' => 60,
+    '#weight' => 2,
+    '#maxlength' => 255
+  );
+  $form['type_button'] = array(
+    '#type' => 'submit',
+    '#value' => t('Create New Type'),
+    '#weight' => 3
+  );
+
+
+  return $form;
+}
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_types_add_form_submit($form, &$form_state) {
+  $values['name'] = $form_state['values']['name'];
+  $values['description'] = $form_state['values']['description'];
+  $values['tid'] = variable_get('biblio_max_user_tid', '999') + 1;
+
+  db_insert('biblio_types')
+    ->fields($values)
+    ->execute();
+
+  variable_set('biblio_max_user_tid', $values['tid']);
+  $result = db_query('SELECT * FROM {biblio_field_type} WHERE tid=0', array(), array('fetch' => PDO::FETCH_ASSOC));
+  foreach ($result as $row) {
+    $row['tid'] = $values['tid'];
+    $row['visible'] = 1;
+    db_insert('biblio_field_type')
+      ->fields($row)
+      ->execute();
+  }
+  // Fill contributor types. Use the first 4 defaults.
+  for ($type = 1; $type <= 4; $type++) {
+    $ct_vals = array(
+      'auth_category' => $type,
+      'biblio_type' => $values['tid'],
+      'auth_type' => $type,
+      );
+
+    db_insert('biblio_contributor_type')
+      ->fields($ct_vals)
+      ->execute();
+  }
+
+  // Refresh publication type string for translation.
+  biblio_locale_refresh_types($values['tid']);
+  $form_state['redirect'] = 'admin/config/content/biblio/pubtype';
+
+}
+
+function biblio_admin_types_reset() {
+  module_load_include('install', 'biblio');
+
+  db_delete('biblio_types')
+      ->execute();
+  _add_publication_types();
+  drupal_goto('admin/config/content/biblio/pubtype');
+}
+/**
+ *
+ */
+function biblio_admin_types_hide() {
+  $args = func_get_args();
+  if ($args[0] > 0 && is_numeric($args[0])) {
+    db_update('biblio_types')
+      ->fields(array(
+        'visible' => 0))
+      ->condition('tid', $args[0])
+      ->execute();
+  }
+  drupal_goto('admin/config/content/biblio/pubtype');
+}
+/**
+ *
+ */
+function biblio_admin_types_show() {
+  $args = func_get_args();
+  if ($args[0] > 0 && is_numeric($args[0])) {
+    db_update('biblio_types')
+      ->fields(array(
+        'visible' => 1))
+      ->condition('tid', $args[0])
+      ->execute();
+  }
+  drupal_goto('admin/config/content/biblio/pubtype');
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @param unknown_type $tid
+ * @return unknown
+ */
+function biblio_admin_types_delete_form($form, &$form_state, $tid) {
+  $existing_msg = '';
+  if (isset($tid) && is_numeric($tid)) {
+    $row = db_query('SELECT t.* FROM {biblio_types} as t WHERE t.tid = :tid ', array(':tid'=> $tid))->fetchObject();
+    $num_rows = db_query('SELECT COUNT(*) FROM {biblio} as b WHERE b.biblio_type = :btype', array(':btype' => $row->tid))->fetchField();
+    if ($num_rows) {
+      $existing_msg = t('There are @count biblio entries of this type, you should change the type of these entries before proceeding otherwise they will be deleted', array(
+        '@count' => $num_rows
+      ));
+    }
+    $form['tid'] = array(
+      '#type' => 'value',
+      '#value' => $row->tid
+    );
+    $output = confirm_form($form, t('Are you sure you want to delete the custom biblio type:  %title ?', array(
+      '%title' => $row->name
+    )) . $existing_msg, isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/content/biblio/pubtype', t('This action cannot be undone.'), t('Delete'), t('Cancel'));
+    return $output;
+  }
+  else {
+    drupal_goto('admin/config/content/biblio/pubtype');
+  }
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_types_delete_form_submit($form, &$form_state) {
+  $query = db_select('biblio_field_type', 'bft');
+  $result = $query->fields('bft', array('ftdid'))
+                  ->condition('tid', $form_state['values']['tid'])
+                  ->condition('ftdid', 100, '>')
+                  ->execute();
+  foreach ($result as $field) {
+    $ftdids[] = $field->ftdid;
+  }
+
+  db_delete('biblio_field_type_data')
+    ->condition('ftdid', $ftdids, 'IN')
+    ->execute();
+
+  db_delete('biblio_types')
+    ->condition('tid', $form_state['values']['tid'])
+    ->execute();
+
+  db_delete('biblio_field_type')
+    ->condition('tid', $form_state['values']['tid'])
+    ->execute();
+
+  $form_state['redirect'] = 'admin/config/content/biblio/pubtype';
+}
+
+/**
+ * @return unknown
+ */
+function biblio_admin_types_reset_form() {
+  $form['reset'] = array(
+    '#type' => 'value',
+    '#value' => 'reset'
+  );
+  $output = confirm_form($form, t('Are you sure you want to reset ALL the field definitions to the defaults?'), isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/content/biblio/fields', t('By doing this, you will loose all customizations you have made to the field titles, <b><u>this action cannot be undone</u></b>!'), t('Reset!'), t('Cancel'));
+  return $output;
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_types_reset_form_submit($form, & $form_state) {
+  module_load_include('install', 'biblio');
+  biblio_reset_types();
+  $form_state['redirect'] = 'admin/config/content/biblio/fields';
+}
+/*
+ * This functin is used by both the admin/config/content/biblio page and user profile page
+ *   - if $user is set, then it is being called from the user profile page
+ */
+function _biblio_get_user_profile_form($profile_user = FALSE) {
+  $form = array();
+  $allow_edit = variable_get('biblio_show_user_profile_form', '1');
+  $allow_edit = $allow_edit || user_access('administer biblio');
+
+  if (!$profile_user) {
+    $form['biblio_show_user_profile_form'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Allow users to override these settings on their "My account" page') ,
+      '#return_value' => 1,
+      '#description' =>  t('If this is selected, a form similar to this section will be available to the user when they edit their own account information.  This will allow them to override the global preferences set here.') ,
+      '#default_value' => variable_get('biblio_show_user_profile_form', '1')
+    );
+  }
+  $form['biblio_show_profile'] = array(
+    '#type' => 'checkbox',
+    '#title' => ($profile_user) ? t('Show my publications on my profile page') : t('Show publications on users profile pages'),
+    '#return_value' => 1,
+    '#disabled' => !$allow_edit,
+    '#description' => ($profile_user) ? t('Selecting this will create a listing of your publications on your profile page') : t('This sets the site wide default, users may change this in their profile')
+  );
+  if ($profile_user) {
+    $form['biblio_show_profile']['#default_value'] = (isset($profile_user->data['biblio_show_profile'])) ? $profile_user->data['biblio_show_profile'] : variable_get('biblio_show_profile', '0');
+  }
+  else {
+    $form['biblio_show_profile']['#default_value'] = variable_get('biblio_show_profile', '0');
+  }
+  $form['#biblio_show_profile'] = $form['biblio_show_profile']['#default_value'];
+  $form['biblio_my_pubs_menu'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Show "My publications" item in the navigation menu'),
+    '#disabled' => !$allow_edit,
+    '#return_value' => 1,
+    '#description' => ''
+  );
+  if ($profile_user) {
+    $form['biblio_my_pubs_menu']['#default_value'] = ((isset($profile_user->data['biblio_my_pubs_menu'])) ? $profile_user->data['biblio_my_pubs_menu'] : variable_get('biblio_my_pubs_menu', '0'));
+  }
+  else {
+    $form['biblio_my_pubs_menu']['#default_value'] = variable_get('biblio_my_pubs_menu', '0');
+  }
+  $form['#biblio_my_pubs_menu'] =  $form['biblio_my_pubs_menu']['#default_value'];
+
+  if ($profile_user) {
+    $form += _biblio_drupal_author_user_map($profile_user, $allow_edit);
+  }
+
+  $options = array();
+  $options['system'] = t('System default');
+  $options = array_merge($options, biblio_get_styles() );
+  $form['biblio_user_style'] = array(
+      '#type' => 'select',
+      '#title' => t('Style'),
+      '#default_value' => (isset($profile_user->data['biblio_user_style']) ? $profile_user->data['biblio_user_style'] : 'system'),
+      '#options' => $options,
+      '#description' => t('Set the bibliographic style of the "list" view.')
+  );
+
+  return $form;
+}
+
+function _biblio_drupal_author_user_map($profile_user, $allow_edit = TRUE) {
+  global $user;
+
+  $db_result = db_query("SELECT cd.lastname, cd.firstname, cd.initials, cd.cid FROM {biblio_contributor_data} cd
+      ORDER by cd.lastname ASC ");
+  $options = array();
+  $options[0] = t('(None)');
+
+  foreach ($db_result as $row) {
+    $options[$row->cid] =  "$row->lastname, $row->firstname $row->initials ";
+  }
+  if (isset($profile_user->data['biblio_id_change_count']) && $profile_user->data['biblio_id_change_count'] > 2) {
+    $allow_edit = 0;
+    $msg = t('This control has been disabled because the author mapping has been changed more than 3 times, please see your system administrator to have it reset.');
+  }
+  else {
+    $msg = t('This will link your profile to the selected author from the biblio database, then all publications containing this author to be displayed on your "Publications" tab.');
+  }
+  $form['biblio_contributor_id'] = array(
+      '#type' => 'select',
+      '#title' => t('Link My Profile with this Author from the Biblio database:'),
+      '#default_value' => isset($profile_user->data['biblio_contributor_id']) ? $profile_user->data['biblio_contributor_id'] : 0,
+      '#disabled' => ($user->uid == 1 || user_access('administer biblio')) ? FALSE : !$allow_edit,
+      '#options' => $options,
+      '#description' => $msg,
+  );
+  $form['biblio_id_change_count'] = array(
+      '#type' => 'textfield',
+      '#size' => 2,
+      '#title' => t('Drupal UserID to Biblio AuthorID mapping change count:'),
+      '#default_value' => isset($profile_user->data['biblio_id_change_count']) ?  $profile_user->data['biblio_id_change_count'] : 0,
+      '#disabled' => ($user->uid == 1 || user_access('administer biblio')) ? FALSE : TRUE,
+      '#description' => 'When this value is >= 3, you will no longer be able to change your author id mapping.  Contact your system administrator to reset this value.',
+  );
+
+  return $form;
+}
+/**
+ * @param unknown_type $user
+ * @return multitype:string number NULL
+ */
+function _biblio_get_user_doi_form($user) {
+  $form['biblio_doi'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' =>  TRUE,
+    '#title' => t('CrossRef Login Information')
+  );
+  $link_attrs = array('attributes' => array('target' => '_blank'),
+                      'absolue' => TRUE);
+  $form['biblio_doi']['biblio_crossref_pid'] = array(
+    '#type' => 'textfield',
+    '#title' => t('CrossRef OpenURL Account ID'),
+    '#default_value' => isset($user->data['biblio_crossref_pid']) ? $user->data['biblio_crossref_pid'] : '',
+    '#return_value' => 1,
+    '#description' => t('Enter your complimentary CrossRef OpenURL account ID which you can obtain here !url, OR enter your full CrossRef (colon separated) account:password combination.', array('!url' => l(t('OpenURL Account Request Form'), 'http://www.crossref.org/requestaccount/', $link_attrs)))
+  );
+  return $form;
+}
+/**
+ * @param unknown_type $user
+ * @return multitype:string number NULL
+ */
+function _biblio_get_user_openurl_form($user) {
+  $form['openurl'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('OpenURL'),
+    '#description' => t('You can set an <a href="http://en.wikipedia.org/wiki/OpenURL">openurl</a> link here')
+  );
+  $form['openurl']['biblio_baseopenurl'] = array(
+    '#type' => 'textfield',
+    '#title' => t('OpenURL Base URL'),
+    '#size' => 95,
+    '#default_value' => !empty($user->data['biblio_baseopenurl']) ? $user->data['biblio_baseopenurl'] :  '',
+    '#description' => t('This sets your base <a href="http://en.wikipedia.org/wiki/OpenURL">OpenURL</a> gateway, which is used to generate OpenURL links. To implement a "Universal" OpenURL system, try using OCLC\'s <a href="http://www.oclc.org/productworks/urlresolver.htm">OpenURL Resolver Registry</a> gateway: <a href="http://worldcatlibraries.org/registry/gateway">http://worldcatlibraries.org/registry/gateway</a>')
+  );
+  $sid = "Biblio:" . variable_get('site_name', 'Drupal');
+  $form['openurl']['biblio_openurl_sid'] = array(
+    '#type' => 'textfield',
+    '#title' => t('OpenURL Site ID'),
+    '#size' => 95,
+    '#default_value' => !empty($user->data['biblio_openurl_sid']) ? $user->data['biblio_openurl_sid'] : '',
+    '#description' => t('This sets your site name, some link resolvers will require a specific Site ID in order to process your requests.')
+  );
+  return $form;
+}
+/*  This function parses the module directory for 'style' files, loads them and
+ *  calls the info fuction to get some basic information like the short and long
+ *  names of the style
+*/
+function biblio_form_sort($a, $b) {
+  $a_weight = (is_array($a) && isset($a['weight'])) ? $a['weight'] : 0;
+  $b_weight = (is_array($b) && isset($b['weight'])) ? $b['weight'] : 0;
+  if ($a_weight == $b_weight) {
+    return 0;
+  }
+  return ($a_weight < $b_weight) ? -1 : 1;
+}
+/**
+ * @param unknown_type $name
+ * @return string
+ */
+function biblio_admin_get_query($name) {
+  switch ($name) {
+    case "author_dup" :
+      return ('SELECT lastname, firstname, initials, COUNT(lastname) as cnt  FROM {biblio_contributor_data} GROUP BY lastname, firstname, initials HAVING COUNT(*)>1 ORDER BY lastname ASC, firstname ASC, initials ASC ');
+      break;
+    case "author_by_name" :
+      return ("SELECT lastname, cid FROM {biblio_contributor_data} where lastname LIKE '%s'");
+      break;
+    case 'author_pub_count' :
+//      return ('SELECT bd.lastname, b.cid,COUNT(*) AS cnt FROM {biblio_contributor} b, {biblio_contributor_data} bd WHERE bd.cid=b.cid GROUP BY b.cid HAVING cnt > 0 ORDER BY lastname ASC');
+      return ('SELECT bd.lastname, b.cid,COUNT(*) AS cnt FROM {biblio_contributor} b, {biblio_contributor_data} bd WHERE bd.cid=b.cid GROUP BY b.cid, bd.lastname HAVING COUNT(*) > 0 ORDER BY lastname ASC');
+      break;
+  }
+}
+
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @param unknown_type $op
+ * @param unknown_type $id
+ * @return void|multitype:string multitype:string number NULL  multitype:string number multitype:string  NULL  multitype:string number boolean NULL  NULL
+ */
+function biblio_admin_author_types_form($form, &$form_state, $op = NULL, $id = NULL) {
+
+  switch ($op) {
+    case 'edit':
+      $type = db_query("SELECT * FROM {biblio_contributor_type_data} WHERE auth_type=:atype", array(':atype' => $id))->fetchObject();
+      $form['auth_type'] = array(
+        '#type' => 'hidden',
+        '#value' => $type->auth_type);
+        //fall through and use the same form used for a new entry
+    case 'new':
+      $form['title'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Type Name'),
+        '#size' => 20,
+        '#weight' => 1,
+        '#default_value' => ($op == 'new' ? '' : $type->title),
+        '#required' => TRUE,
+        '#maxlength' => 64
+      );
+      $form['hint'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Description'),
+        '#size' => 60,
+        '#weight' => 2,
+        '#default_value' => ($op == 'new' ? '' : $type->hint),
+        '#maxlength' => 255
+      );
+      $form['type_button'] = array(
+        '#type' => 'submit',
+        '#value' => ($op == 'new')? t('Create New Type') : t('Save'),
+        '#weight' => 3,
+        '#submit' => array('biblio_admin_author_types_form_submit')
+      );
+      $form['cancel_button'] = array(
+        '#type' => 'submit',
+        '#value' => t('Cancel'),
+        '#weight' => 4,
+      );
+      $form['#theme'] = '';
+      return $form;
+      break;
+    case 'hide':
+      break;
+    default:
+      return;
+  }
+}
+
+/**
+ * @param unknown_type $variables
+ * @return string
+ */
+function theme_biblio_admin_author_types_form($variables) {
+  $form = $variables['form'];
+  // We need this complex query to realize author_types which are not in use (cid is NULL)
+  $query = db_select('biblio_contributor_type_data', 'ctd');
+  $query->fields('ctd', array('auth_type', 'title', 'hint'))
+    ->leftJoin('biblio_contributor', 'bc', 'ctd.auth_type = bc.auth_type');
+  $db_result = $query->groupBy('ctd.auth_type')
+                  ->groupBy('ctd.title')
+                  ->groupBy('ctd.hint')
+                  ->orderBy('ctd.auth_type')
+                  ->execute();
+
+  foreach  ($db_result as $row) {
+    $ops = l(t('edit'), 'admin/config/content/biblio/author/type/' . $row->auth_type . '/edit' );
+    if (!isset($row->cid) && $row->auth_type >= 10) { // allow delete only if type not in use
+      $ops .= '&nbsp;&nbsp;';
+      $ops .= l(t('delete'), 'admin/config/content/biblio/author/type/' . $row->auth_type . '/delete/');
+    }
+    $rows[] = array(
+      $row->auth_type,
+      check_plain($row->title),
+      check_plain($row->hint),
+      $ops,
+    );
+  }
+  $header = array(
+    t('Type Id'),
+    t('Contributor Type'),
+    t('Description'),
+    array('data' => t('Operations'), 'colspan' => '2')
+  );
+  $output = '<p>[ ' . l(t('Add New Type'), 'admin/config/content/biblio/author/type/new') . ' ]';
+  $output .= theme('table', array('header' => $header, 'rows' => $rows));
+  $output .= '<p>[ ' . l(t('Add New Type'), 'admin/config/content/biblio/author/type/new') . ' ]';
+ // $output .= ' [ ' . l(t('Reset all types to defaults'), 'admin/config/content/biblio/authors/reset') . ' ]';
+
+  return $output;
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_author_types_form_submit($form, &$form_state) {
+
+  if ($form_state['triggering_element']['#value'] == t('Save') || $form_state['triggering_element']['#value'] == t('Create New Type')) {
+    $record->title = $form_state['values']['title'];
+    $record->hint = $form_state['values']['hint'];
+    switch ($form['#id']) {
+      case 'biblio-admin-author-types-form-new':
+        $record->title = $form_state['values']['title'];
+        $record->hint = $form_state['values']['hint'];
+        drupal_write_record('biblio_contributor_type_data', $record);
+        break;
+      case 'biblio-admin-author-types-form-edit':
+        $record->auth_type = $form_state['values']['auth_type'];
+        drupal_write_record('biblio_contributor_type_data', $record, 'auth_type');
+        break;
+    }
+  }
+  $form_state['redirect'] = 'admin/config/content/biblio/author/type';
+
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @param unknown_type $type_id
+ */
+function biblio_admin_author_type_delete_confirm($form, &$form_state, $type_id) {
+  $base = variable_get('biblio_base', 'biblio');
+  $type_data = db_query('SELECT * FROM {biblio_contributor_type_data} bctd WHERE bctd.auth_type = :tid ', array(':tid' => $type_id))->fetchObject();
+  $form['auth_type'] = array(
+    '#type' => 'value',
+    '#value' => $type_data->auth_type,
+  );
+
+  return confirm_form($form,
+    t('Are you sure you want to delete the author type: %title ?', array('%title' => $type_data->title)),
+    isset($_GET['destination']) ? $_GET['destination'] : 'admin/config/content/biblio/author/type',
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+
+}
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_author_type_delete_confirm_submit($form, &$form_state) {
+
+  db_delete('biblio_contributor_type_data')
+    ->condition('auth_type', $form_state['values']['auth_type'])
+    ->execute();
+
+  db_delete('biblio_contributor_type')
+    ->condition('auth_type', $form_state['values']['auth_type'])
+    ->execute();
+
+  $form_state['redirect'] = 'admin/config/content/biblio/author/type';
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @param unknown_type $author_id
+ * @return void|multitype:string NULL
+ */
+function biblio_admin_author_edit_form($form, &$form_state, $author_id) {
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  $merge_options = $linked = array();
+  if (!isset($form_state['biblio_add_merge_author'])) {
+    $form_state['biblio_add_merge_author'] = array();
+  }
+  $base = variable_get('biblio_base', 'biblio');
+
+  $author = db_query('SELECT * FROM {biblio_contributor_data} b WHERE b.cid = :aid ', array(':aid' => $author_id))->fetchObject();
+  if (!$author) {
+    drupal_not_found();
+    return;
+  }
+  $base = variable_get('biblio_base', 'biblio');
+  $menu = menu_get_active_title();
+  $path = (strpos($_GET['q'], 'config'))? 'admin/config/content/biblio/author/' : $base . '/authors/';
+
+ // $form['#tree'] = TRUE;
+  $form['cid'] = array(
+      '#type' => 'value',
+      '#value' => $author_id,
+  );
+  $users = db_query('SELECT uid,name FROM {users} WHERE uid>0 ORDER BY name');
+  $options[0] = t('(None)');
+  foreach ($users as $user) {
+    $options[$user->uid] = $user->name;
+  }
+  $form['drupal_uid'] = array(
+      '#type' => 'select',
+      '#title' => t('Drupal User ID'),
+      '#options' => $options,
+      '#default_value' => $author->drupal_uid,
+      '#weight' => 12,
+      '#required' => FALSE,
+      '#description' => t('If this author has a an account (Drupal User ID) on this web site, you may select it here.  This will help to link the authors publications with other content.')
+  );
+  $form['name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Complete Name'),
+      '#default_value' => $author->name,
+      '#size' => 100,
+      '#weight' => 1,
+      '#required' => TRUE,
+      '#disabled' => TRUE,
+      '#maxlength' => 255,
+      '#description' => t('The value in this box will be constructed from the individual name parts fields above.')
+  );
+  $form_state['current_name'] = $author->name;
+
+  $form['literal'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Do not reformat'),
+      '#default_value' => $author->literal,
+      '#weight' => 1.5,
+      '#required' => FALSE,
+      '#description' => t('Selecting this will prevent the styles from trying to reformat the contributor name.  The text in the "Complete Name" field will be used as is.')
+  );
+  $form['prefix'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Prefix'),
+      '#default_value' => $author->prefix,
+      '#size' => 20,
+      '#weight' => 2,
+      '#required' => FALSE,
+      '#maxlength' => 128
+  );
+  $form['firstname'] = array(
+      '#type' => 'textfield',
+      '#title' => t('First Name'),
+      '#default_value' => $author->firstname,
+      '#size' => 20,
+      '#weight' => 3,
+      '#required' => FALSE,
+      '#maxlength' => 128
+  );
+  $form['initials'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Initials'),
+      '#default_value' => $author->initials,
+      '#size' => 20,
+      '#weight' => 4,
+      '#required' => FALSE,
+      '#maxlength' => 10
+  );
+  $form['lastname'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Last Name'),
+      '#default_value' => $author->lastname,
+      '#size' => 20,
+      '#weight' => 5,
+      '#required' => FALSE,
+      '#maxlength' => 255
+  );
+  $form['suffix'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Suffix'),
+      '#default_value' => $author->suffix,
+      '#size' => 20,
+      '#weight' => 6,
+      '#required' => FALSE,
+      '#maxlength' => 128
+  );
+  $form['affiliation'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Affiliation'),
+      '#default_value' => $author->affiliation,
+      '#size' => 100,
+      '#weight' => 7,
+      '#required' => FALSE,
+      '#maxlength' => 256,
+      '#description' => t('University, Company or Organization that the author is affiliated with.')
+  );
+
+  $query = db_select('biblio_contributor_data', 'bcd');
+  $authors = $query->fields('bcd')
+                   ->condition('cid', $author_id, '<>')
+                   ->orderBy('lastname')
+                   ->execute();
+
+  $query = db_select('biblio_contributor', 'bc');
+  $merged_authors = $query->fields('bc')
+                      ->condition('merge_cid', 0, '>')
+                      ->execute();
+  foreach ($merged_authors as $auth) {
+    $merged[$auth->merge_cid] = $auth->cid;
+  }
+
+  $linked = biblio_get_linked_contributors($author->cid);
+
+  $radio_options = array('link' => '', 'merge' => '');
+  $candidate = FALSE;
+  $candidates = array();
+
+  $this_soundx = soundex($author->lastname);
+
+  foreach ($authors as $other_author) {
+    $merge_def = $link_def = 0;
+    $link_disable = $merge_disable = $retain_disable = FALSE;
+
+    if ((soundex($other_author->lastname) == $this_soundx) ||
+        (isset($merged[$other_author->cid]) && $merged[$other_author->cid] == $author->cid) ||
+        in_array($other_author->cid, $form_state['biblio_add_merge_author']))  {
+      $candidate = TRUE;
+      $merge_def = ($other_author->alt_form && $other_author->aka) ? $author->cid : FALSE;
+      $retain_def = $other_author->alt_form ? $author->cid : FALSE;
+      $retain_disable = $other_author->alt_form ? TRUE : FALSE;
+    }
+
+    if (in_array($other_author->cid, $linked)) {
+      $candidate = TRUE;
+      $link_def = $author->cid;
+      $retain_def =  0;
+    }
+
+    if ($candidate) {
+      $candidate = FALSE;
+      $form_state['biblio_add_merge_author'][$other_author->cid] = $other_author->cid;
+
+      $candidates[$other_author->cid]['name'] = array(
+          '#markup' => l($other_author->lastname . ($other_author->firstname ? ', ' . $other_author->firstname : ($other_author->initials?', ' . $other_author->initials:'')), $path . $other_author->cid . '/edit/'),
+          '#markup' => l($other_author->name , $path . $other_author->cid . '/edit/'),
+      );
+      $candidates[$other_author->cid]['link'] = array(
+          '#type' => 'checkbox',
+          '#return_value' => $author->cid,
+          '#default_value' => $link_def,
+          '#disabled' => $link_disable,
+          '#parents' => array('candidates', $other_author->cid, 'link'),
+          '#states' => array(
+              'disabled' => array(
+                  ':input[name="candidates[' . $other_author->cid . '][merge]"]' => array('checked' => true),
+              ),
+          ),
+      );
+      $candidates[$other_author->cid]['merge'] = array(
+          '#type' => 'checkbox',
+          '#return_value' => $author->cid,
+          '#default_value' => $merge_def,
+          '#disabled' => $merge_disable,
+          '#parents' => array('candidates', $other_author->cid, 'merge'),
+          '#states' => array(
+              'disabled' => array(
+                  ':input[name="candidates[' . $other_author->cid . '][link]"]' => array('checked' => true),
+              ),
+          ),
+      );
+      $candidates[$other_author->cid]['retain'] = array(
+          '#type' => 'checkbox',
+          '#return_value' => $author->cid,
+          '#default_value' => $retain_def,
+          '#disabled' => $retain_disable,
+          '#parents' => array('candidates', $other_author->cid, 'retain'),
+          '#states' => array(
+              'enabled' => array(
+                  ':input[name="candidates[' . $other_author->cid . '][merge]"]' => array('checked' => true),
+              ),
+              'unchecked' => array(
+                  ':input[name="candidates[' . $other_author->cid . '][merge]"]' => array('unchecked' => true),
+              ),
+          ),
+      );
+    }
+  }
+
+  $form['merge'] = array(
+      '#type' => 'fieldset',
+      '#theme' => 'biblio_admin_author_edit_merge_table',
+      '#title' => t('Author Link / Merge'),
+      '#description' => t('Select other author names which will be linked or merged.  Merging removes all the selected authors, then replaces any references to these authors with the author being edited above.  You should only do this if you are sure the other authors represent the same author as the one being edited. <b>IF you do not select "Retain as alternate form" then THIS CANNOT BE UNDONE!</b>'),
+      '#weight' => 5,
+      '#collapsible' => TRUE,
+      '#collapsed' => !count($candidates),
+      '#header' => array(t('Author name'), t('Link'), t('Merge'), t('Retain as "alternate form"')),
+      'candidates' => $candidates,
+      '#prefix' => '<div id="biblio-author-edit-merge-table">',
+      '#suffix' => '</div>',
+
+  );
+  $form['merge']['more_authors_search'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Other authors which could be linked to this author'),
+      '#autocomplete_path' => 'biblio/autocomplete/contributor',
+      '#weight' => 12,
+      '#required' => FALSE,
+  );
+  $form['merge']['more_authors_add'] = array(
+      '#type'     => 'submit',
+      '#value'    => t('Add author'),
+      '#weight' => 15,
+      '#submit'   => array('biblio_admin_author_edit_add_candidate'),
+      '#ajax'   => array(
+          'callback' => 'biblio_admin_author_edit_add_candidate_callback',
+          'wrapper'  => 'biblio-author-edit-merge-table',
+      ),
+
+  );
+
+  $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save')
+  );
+  $form['cancel'] = array(
+      '#type' => 'submit',
+      '#value' => t('Cancel')
+  );
+
+  return $form;
+}
+
+function biblio_admin_author_edit_add_candidate($form, &$form_state) {
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  if (!empty($form_state['values']['more_authors_search'])) {
+    if ($cid = biblio_get_cid_by_name($form_state['values']['more_authors_search'])) {
+      if ($cid == $form_state['values']['cid']) { // we don't want to merge with ourselves :-(
+        drupal_set_message(t('You cannot merge an author with itself'), 'error');
+      }
+      elseif (in_array($cid, $form_state['biblio_add_merge_author'])) {
+        drupal_set_message(t('Author already exists in the merge list'), 'warning');
+      }
+      else {
+        $form_state['biblio_add_merge_author'][$cid] = $cid;
+      }
+    }
+    else {
+      drupal_set_message(t('The Author was not found in the database.  You must select an Author from the "auto-complete" list of the Keyword search box.'), 'error');
+    }
+  }
+  else {
+    drupal_set_message(t('Cannot add an empty value'), 'error');
+  }
+
+  $form_state['rebuild'] = TRUE;
+
+}
+
+function biblio_admin_author_edit_add_candidate_callback($form, $form_state) {
+  return $form['merge'];
+}
+
+/**
+ * @param array $form
+ * @param array $form_state
+ */
+function biblio_admin_author_edit_form_merge_validate($form, &$form_state) {
+}
+
+/**
+ * @param array $form
+ * @param array $form_state
+ */
+function biblio_admin_author_edit_form_merge_link($form_state) {
+  $op = $form_state['triggering_element']['#value'];
+  $merge_authors = array();
+  $cid = $form_state['values']['cid'];
+
+  foreach ($form_state['values']['candidates'] as $ccid => $options) {
+
+    if ($options['link']) {
+      db_update('biblio_contributor_data')
+      ->fields(array(
+          'aka' => $options['link'],
+          'alt_form' => 0,
+      ))
+      ->condition('cid', $ccid)
+      ->execute();
+    }
+    else {
+      db_update('biblio_contributor_data')
+      ->fields(array(
+          'aka' => 0,
+          'alt_form' => 0,
+      ))
+      ->condition(db_or()->condition('cid', $cid)->condition('cid', $ccid))
+      ->execute();
+    }
+
+    if ($options['merge']) {
+      db_update('biblio_contributor')
+        ->fields(array(
+            'cid' => $cid,
+            'merge_cid' => $ccid))
+        ->condition('cid', $ccid)
+        ->execute();
+    }
+    else {
+      db_update('biblio_contributor')
+        ->fields(array(
+            'cid' => $ccid,
+            'merge_cid' => 0))
+        ->condition('merge_cid', $ccid)
+        ->execute();
+    }
+
+    if ($options['merge'] && $options['retain']) {
+      db_update('biblio_contributor_data')
+        ->fields(array(
+          'alt_form' => $options['retain'] ? $options['retain'] : 0,
+          'aka' => $options['retain'] ? $cid : 0))
+        ->condition('cid', $ccid)
+        ->execute();
+    }
+    elseif ($options['merge'] && !$options['retain']) {
+      db_delete('biblio_contributor_data')
+        ->condition('cid', $ccid)
+        ->execute();
+    }
+  }
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_author_edit_form_link_validate($form, &$form_state) {
+
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_author_edit_form_link_submit($form, &$form_state) {
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  $linked_authors = array();
+  $link_authors = '';
+
+  if (isset($form_state['values']['linked_authors']) ) {
+    $linked_authors = $form_state['values']['linked_authors'];
+  }
+
+  if (isset($form_state['values']['link_authors']) ) {
+    $link_authors = $form_state['values']['link_authors'];
+  }
+
+  foreach ($linked_authors as $key => $value) {
+    if ($value == 0) {
+      db_update('biblio_contributor_data')
+      ->fields(array('aka' => $value))
+      ->condition('cid', $key)
+      ->execute();
+    }
+  }
+
+  if (!empty($link_authors)) {
+    if ( ($cid = biblio_get_cid_by_name($link_authors))) {
+      db_update('biblio_contributor_data')
+      ->fields(array('aka' => $form_state['values']['cid']))
+      ->condition('cid', $cid)
+      ->execute();
+    }
+  }
+
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_author_edit_form_validate($form, &$form_state) {
+  foreach ($form_state['values'] as $key => $value) {
+    if (is_string($value)) $form_state['values'][$key] = trim($value);
+  }
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_author_edit_form_submit($form, &$form_state) {
+  $op = $form_state['values']['op'];
+  switch ($op) {
+    case t('Save'):
+      if ($form_state['values']['drupal_uid'] == 0 ) {
+        $uid = $form['drupal_uid']['#default_value'];
+        $cid = 0;
+      }
+      else {
+        $uid = $form_state['values']['drupal_uid'];
+        $cid = $form_state['values']['cid'] ;
+      }
+      if ($uid) {
+        db_update('biblio_contributor_data')
+          ->fields(array('drupal_uid' => 0))
+          ->condition('drupal_uid', $uid)
+          ->execute();
+        $result = db_query('SELECT data FROM {users} WHERE uid = :uid', array(':uid' => $uid))->fetchField();
+        $data = unserialize($result);
+        $data['biblio_contributor_id'] = $cid;
+        $v = serialize($data);
+        db_update('users')
+          ->fields(array('data' => $v))
+          ->condition('uid', $uid)
+          ->execute();
+      }
+
+      $form_state['values']['name'] =
+        (!empty($form_state['values']['prefix']) ? $form_state['values']['prefix'] . ' ' :'') .
+        (!empty($form_state['values']['firstname']) ? $form_state['values']['firstname'] . ' ' :'') .
+        (!empty($form_state['values']['initials']) ? $form_state['values']['initials'] . ' ' :'') .
+        (!empty($form_state['values']['lastname']) ? $form_state['values']['lastname'] . ' ' :'') .
+        (!empty($form_state['values']['suffix']) ? $form_state['values']['suffix'] :'') ;
+      $form_state['values']['name'] = trim($form_state['values']['name']);
+      $form_state['values']['md5'] = md5($form_state['values']['name']);
+
+      drupal_write_record('biblio_contributor_data',  $form_state['values'], 'cid');
+
+      if (isset($form_state['values']['candidates']) && !empty($form_state['values']['candidates'])) {
+        biblio_admin_author_edit_form_merge_link($form_state);
+      }
+      break;
+    case t('Cancel'):
+      break;
+  }
+}
+
+
+/**
+ *
+ * @param  $form
+ * @param  $form_state
+ * @return array
+ */
+function biblio_admin_orphans_form($form, &$form_state) {
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  $orphans = $options = $names = array();
+
+  $base = variable_get('biblio_base', 'biblio');
+
+  $orphans = biblio_get_orphan_authors();
+
+  foreach ($orphans as $author) {
+    $options[$author->cid] = array(
+        'author' => array(
+            'data' => array(
+                '#type' => 'link',
+                '#title' => $author->name,
+                '#href' => $base . '/authors/' . $author->cid . '/edit',
+            ),
+        ),
+        'affiliation' => check_plain($author->affiliation),
+    );
+    $names[$author->cid] = $author->name;
+  }
+  $form['names'] = array('#type' => 'hidden', '#value' => $names);
+
+  $header = array(
+      'author' => t('Author name'),
+      'affiliation' => t('Author affiliation')
+  );
+
+  $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete Selected'),
+      '#disabled' => (!count($options)),
+      '#submit' => array('biblio_admin_orphans_form_submit'),
+  );
+  $form['delete_all'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete ALL'),
+      '#disabled' => (!count($options)),
+      '#submit' => array('biblio_admin_orphans_form_submit'),
+  );
+  $form['authors'] = array(
+      '#type' => 'tableselect',
+      '#header' => $header,
+      '#options' => $options,
+      '#empty' => t('No orphaned authors.'),
+  );
+
+  return $form;
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_orphans_form_validate($form, &$form_state) {
+  $check_count = array_filter($form_state['values']['authors']);
+  if ($form_state['triggering_element']['#value'] == t('Delete Selected') && count($check_count) == 0) {
+    form_set_error('', t('No items selected.'));
+  }
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_orphans_form_submit($form, &$form_state) {
+  $authors = $names = array();
+  // Filter out unchecked authors
+  if ($form_state['triggering_element']['#value'] == t('Delete Selected')) {
+    $authors = array_filter($form_state['values']['authors']);
+  }
+  elseif ($form_state['triggering_element']['#value'] == t('Delete ALL')) {
+    $authors = drupal_map_assoc(array_keys($form_state['values']['authors']));
+  }
+
+  $names   = array_intersect_key($form_state['values']['names'], $authors);
+  $del_names = implode('; ', $names);
+
+  db_delete('biblio_contributor_data')
+    ->condition('cid', $authors, 'IN')
+    ->execute();
+
+  drupal_set_message(t('The orphaned authors (@author_list) have been deleted.', array('@author_list' => $del_names)));
+
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @return multitype:NULL
+ */
+function biblio_admin_keyword_orphans_form($form, $form_state) {
+  $orphans = $keywords = $options = array();
+
+  $base = variable_get('biblio_base', 'biblio');
+
+  $header = array(
+    'keyword' => t('Keyword')
+  );
+
+  $query = db_select('biblio_keyword', 'bk');
+  $active_kids = $query
+    ->fields('bk', array('kid'))
+    ->groupBy('kid')
+    ->execute()
+    ->fetchCol();
+
+  $query = db_select('biblio_keyword_data', 'bkd');
+  $all_kids = $query
+    ->fields('bkd', array('kid'))
+    ->groupBy('kid')
+    ->execute()
+    ->fetchCol();
+
+  $orphans = array_diff($all_kids, $active_kids);
+
+  if (count($orphans)) {
+    $query = db_select('biblio_keyword_data', 'bkd')->extend('PagerDefault')->limit(50);
+    $query->fields('bkd'); // SELECT * FROM {biblio_contributor_data}
+    $query->condition('kid', $orphans, 'IN');
+    $result = $query->execute(); //pager_query('SELECT * FROM {biblio_keyword_data} WHERE kid NOT IN (SELECT kid FROM {biblio_keyword} GROUP BY kid)', 50);
+    foreach ($result as $keyword) {
+      $options[$keyword->kid] = array(
+        'keyword' => array(
+          'data' => array(
+            '#type' => 'link',
+            '#title' => $keyword->word,
+            '#href' => $base . '/keywords/' . $keyword->kid . '/edit',
+          ),
+        ),
+      );
+    }
+  }
+    $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete'),
+      '#disabled' => (!count($options)),
+      '#submit' => array('biblio_admin_keyword_orphans_form_submit'),
+    );
+    $form['words'] = array(
+      '#type' => 'tableselect',
+      '#header' => $header,
+      '#options' => $options,
+      '#empty' => t('No orphaned keywords.'),
+    );
+
+    $form['pager'] = array('#markup' => theme('pager'));
+
+  return $form;
+}
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_keyword_orphans_form_validate($form, &$form_state) {
+  $check_count = array_filter($form_state['values']['words']);
+  if (count($check_count) == 0) {
+    form_set_error('', t('No items selected.'));
+  }
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_keyword_orphans_form_submit($form, &$form_state) {
+
+  $keywords = array_filter($form_state['values']['words']);
+  db_delete('biblio_keyword_data')
+    ->condition('kid', $keywords, 'IN')
+    ->execute();
+
+  drupal_set_message(t('%count orphaned keywords have been deleted.', array('%count' => count($keywords))));
+
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @param unknown_type $keyword_id
+ * @return multitype:string number NULL
+ */
+function biblio_admin_keyword_edit_form($form, &$form_state, $keyword_id) {
+  $options = array();
+  $keywords = array();
+  $destination = NULL;
+
+  $keyword = db_query('SELECT * FROM {biblio_keyword_data} bkd WHERE bkd.kid = :kid ', array(':kid' => $keyword_id))->fetchObject();
+
+  $base = variable_get('biblio_base', 'biblio');
+//  $path = (strpos($_GET['q'], 'config')) ? 'admin/config/content/biblio/keywords' : $base . '/keywords';
+
+  if (isset($_GET['destination'])) {
+    $destination = $_GET['destination'];
+  }
+  if (!$destination && isset($form_state['complete form']['#action'])) {
+    $action = drupal_parse_url($form_state['complete form']['#action']);
+    $destination = isset($action['query']['destination']) ? $action['query']['destination'] : NULL;
+  }
+  if (!$destination) $destination = $base . '/keywords';
+
+  $form_state['redirect'] = $destination;
+
+  $form['kid'] = array(
+    '#type' => 'value',
+    '#value' => $keyword_id
+  );
+  $form['word'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Keyword'),
+    '#default_value' => $keyword->word,
+    '#size' => 100,
+    '#weight' => -10,
+    '#required' => TRUE,
+    '#maxlength' => 255
+  );
+
+
+  $result = db_query("SELECT kd.word, kd.kid, count(*) as use_count FROM {biblio_keyword_data} kd
+                      LEFT JOIN {biblio_keyword} bk on bk.kid = kd.kid
+                      WHERE LOWER(word) LIKE LOWER(:word)
+                      AND kd.kid <> :kid
+                      GROUP BY kd.kid, kd.word", array(':word' => '%%' . drupal_substr($keyword->word, 0, 5) . '%%', ':kid' => $keyword_id));
+
+  foreach ($result as $keyword) {
+    $keywords[] = $keyword;
+  }
+
+  if (isset($form_state['biblio_add_merge_keywords'])) {
+    $keywords = array_merge($keywords, $form_state['biblio_add_merge_keywords']);
+  }
+
+  foreach ($keywords as $keyword) {
+    $options[$keyword->kid] = array(
+        'keyword' => array(
+            'data' => array(
+                '#type' => 'link',
+                '#title' => $keyword->word . ' (' . $keyword->use_count .')',
+                '#href' => $destination . '/'.  $keyword->kid . '/edit',
+                '#options' => array('query' => array('destination' => $destination)),
+            ),
+        ),
+    );
+  }
+
+  $form['merge'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Keyword Merge'),
+      '#description' => t('If you wish to consolodate references to multiple keywords into single reference to: <b><u>!kw</u></b>, select the others from the list below. This will remove the selected keywords from the database and replace references to them with a reference to: <b><u>!kw</u></b>. You should only do this if you are sure the other keywords represent the same keyword as the one being edited.', array('!kw' => $keyword->word)),
+      '#weight' => 5,
+      '#collapsible' => TRUE,
+      '#collapsed' => FALSE,
+      //    '#theme' => 'biblio_admin_keyword_merge_fieldset'
+  );
+
+  $header = array('keyword' => t('Similar keywords '));
+
+  $form['merge']['merge_words'] = array(
+      '#type' => 'tableselect',
+      '#header' => $header,
+      '#options' => $options,
+      '#empty' => t('No similar keywords automatically detected, use the search box below to manually add others.'),
+      '#prefix' => '<div id="biblio-keyword-merge-table">',
+      '#suffix' => '</div>',
+
+  );
+  $form['merge']['search'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Keyword search'),
+      '#autocomplete_path' => 'biblio/autocomplete/biblio_keywords',
+      '#description' => t('Use this field to find other keywords you would like to merge with: <b><u>!kw</u></b>, then click the "Add to merge list" button. (The merge will not happen until the "Save" button is clicked)', array('!kw' => $keyword->word))
+  );
+  $form['merge']['add'] = array(
+      '#type'   => 'submit',
+      '#value'  => t('Add to merge list'),
+      '#submit' => array('biblio_add_merge_keyword'),
+      '#ajax'   => array(
+          'callback' => 'biblio_add_merge_keyword_callback',
+          'wrapper'  => 'biblio-keyword-merge-table',
+      ),
+  );
+
+  $form['submit'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save'),
+      '#weight' => 6,
+  );
+  $form['delete'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete'),
+      '#weight' => 7,
+  );
+  $form['cancel'] = array(
+      '#type' => 'submit',
+      '#value' => t('Cancel'),
+      '#weight' => 8,
+  );
+
+  return $form;
+}
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_add_merge_keyword_callback($form, &$form_state) {
+  return $form['merge']['merge_words'];
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_add_merge_keyword($form, &$form_state) {
+
+  if (!empty($form_state['values']['search'])) {
+    module_load_include('inc', 'biblio', 'includes/biblio.keywords');
+    if ($word = biblio_get_keyword_by_name($form_state['values']['search'])) {
+      if ($word->kid == $form_state['values']['kid']) { // we don't want to merge with ourselves :-(
+        drupal_set_message(t('You cannot merge a keyword with itself'), 'error');
+      }
+      elseif (isset($form_state['biblio_add_merge_keywords'][$word->kid])) {
+        drupal_set_message(t('Keyword already exists in the merge list'), 'warning');
+      }
+      else {
+        $form_state['biblio_add_merge_keywords'][$word->kid] = $word;
+      }
+    }
+    else {
+      drupal_set_message(t('The keyword was not found in the database.  You must select a keyword from the "auto-complete" list of the Keyword search box.'), 'error');
+    }
+  }
+  else {
+    drupal_set_message(t('Cannot add an empty value'), 'error');
+  }
+
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @param unknown_type $keyword_id
+ */
+function biblio_admin_keyword_delete_confirm($form, &$form_state, $keyword_id) {
+  $base = variable_get('biblio_base', 'biblio');
+  $keyword = db_query('SELECT * FROM {biblio_keyword_data} bkd WHERE bkd.kid = :kid ', array(':kid' => $keyword_id))->fetchObject();
+  $form['kid'] = array(
+    '#type' => 'value',
+    '#value' => $keyword_id,
+  );
+
+  return confirm_form($form,
+    t('Are you sure you want to delete the keyword: %word from ALL publications?', array('%word' => $keyword->word)),
+    isset($_GET['destination']) ? $_GET['destination'] : $base . '/keywords',
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_keyword_delete_confirm_submit($form, &$form_state) {
+  $base = variable_get('biblio_base', 'biblio');
+  module_load_include('inc', 'biblio', 'includes/biblio.keywords');
+  biblio_delete_keyword($form_state['values']['kid']);
+  $form_state['redirect'] = $base . '/keywords';
+}
+
+/**
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ */
+function biblio_admin_keyword_edit_form_submit($form, &$form_state) {
+  switch ($form_state['values']['op']) {
+
+    case t('Save'):
+      drupal_write_record('biblio_keyword_data', $form_state['values'], 'kid');
+      if (isset($form_state['values']['merge_words'])) {
+        $kids = array_filter($form_state['values']['merge_words']);
+        if (count($kids)) {
+          db_update('biblio_keyword')
+            ->fields(array('kid' => $form_state['values']['kid']))
+            ->condition('kid', $kids, 'IN')
+            ->execute();
+
+          db_delete('biblio_keyword_data')
+            ->condition('kid', $kids, 'IN')
+            ->execute();
+        }
+      }
+      break;
+    case t('Delete'):
+      $base = variable_get('biblio_base', 'biblio');
+      unset($_GET['destination']);
+      $form_state['redirect'] = "$base/keyword/" . $form_state['values']['kid'] . '/delete';
+      break;
+    case t('Cancel'):
+      $base = variable_get('biblio_base', 'biblio');
+      $form_state['redirect'] = $base . '/keywords';
+      break;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.contributors.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,625 @@
+<?php
+/**
+ * @param $aid
+ * @return unknown_type
+ */
+function biblio_get_linked_contributors($aid) {
+  $related = &drupal_static(__FUNCTION__);
+
+  if (!isset($related[$aid])) {
+    $aka = db_query('SELECT aka FROM {biblio_contributor_data} WHERE cid = :cid', array(':cid' => $aid))->fetchField();
+    if ($aka == 0) {
+      $query = db_select('biblio_contributor_data', 'bcd');
+      $cids = $query->fields('bcd', array('cid'))
+                    ->condition(db_and()->condition('bcd.aka', $aid, '=')->condition('bcd.alt_form', 0, '='))
+                    ->execute()
+                    ->fetchCol();
+    }
+    else {
+      $query = db_select('biblio_contributor_data', 'bcd');
+      $and = db_and()->condition('bcd.aka', $aka, '=')->condition('bcd.alt_form', 0, '=')->condition('bcd.cid', $aid, '<>');
+      $cids = $query->fields('bcd', array('cid'))
+                    ->condition(db_or()->condition('bcd.cid', $aka)->condition('bcd.aka', $aid)->condition($and))
+                    ->execute()
+                    ->fetchCol();
+    }
+    $related[$aid] = $cids;
+  }
+  return $related[$aid];
+}
+
+function biblio_get_contributor($aid) {
+  $contributor = &drupal_static(__FUNCTION__);
+
+  if (!isset($contributor[$aid])) {
+    $contributor[$aid] = db_query('SELECT * FROM {biblio_contributor_data} WHERE cid = :cid', array(':cid' => $aid))->fetchObject();
+  }
+
+  return $contributor[$aid];
+}
+
+/**
+ * @param array $contributors
+ * @param int $category
+ * @return array $authors
+ */
+function biblio_get_contributor_category($contributors, $category) {
+  $authors = array();
+  foreach ($contributors as $author) {
+    if ($author['auth_category'] == $category) {
+      $authors[] = $author;
+    }
+  }
+  return $authors;
+}
+
+/**
+ * Get an author id from the database using the "name" field as a key.
+ * If the "cid" value is negative, this means we found an "alternate" form of
+ * the name, which should have an "aka" value which points to the preferred form.
+ *
+ * @param string $name
+ * @return int
+ */
+function biblio_get_cid_by_name($name) {
+  $cid = 0;
+  $auth = biblio_get_contributor_by_name($name);
+  if ($auth) {
+    if ($auth->cid > 0) {
+      $cid = $auth->cid;
+    }
+    if ($auth->aka > 0 && $auth->alt_form > 0) {
+      $cid = $auth->aka;
+    }
+  }
+  return $cid;
+}
+
+/**
+ * @param unknown_type $name
+ * @return unknown
+ */
+function biblio_get_contributor_by_name($name) {
+  $contributors = &drupal_static(__FUNCTION__);
+  $name = trim($name);
+  if (!isset($contributors[$name]) || $contributors[$name] === FALSE) {
+    $query = db_select('biblio_contributor_data', 'bcd');
+    $contributors[$name] = $query->fields('bcd')->condition('bcd.name', $name)->execute()->fetchObject();
+  }
+
+  return $contributors[$name];
+}
+
+/**
+ * @param unknown_type $vid
+ * @return Ambigous <NULL>
+ */
+function biblio_get_first_contributor($vid) {
+  static $contributor = array();
+  if (!isset($contributor[$vid])) {
+    $query = db_select('biblio_contributor', 'bc');
+    $query->join('biblio_contributor_data', 'bcd', 'bc.cid=bcd.cid');
+    $query->fields('bcd');
+    $query->condition('bc.vid', $vid);
+    $query->condition('bc.rank', 0);
+    $contributor[$vid] = $query->execute()->fetchObject();
+  }
+
+  return $contributor[$vid];
+}
+
+/**
+ * @param $vid
+ * @return unknown_type
+ */
+function biblio_load_contributors($vid) {
+  $vids = (isset($vid) ? array($vid) : array());
+  return biblio_load_contributors_multiple($vids);
+}
+
+/**
+ * @param unknown_type $vids
+ * @param unknown_type $auth_category
+ * @return multitype:|Ambigous <multitype:, array>
+ */
+function biblio_load_contributors_multiple($vids = array(), $auth_category = 0) {
+  $contributors = array();
+  if (empty($vids)) return $contributors;
+
+  $query = db_select('biblio_contributor', 'bc');
+  $query->innerJoin('biblio_contributor_data', 'bcd', 'bcd.cid = bc.cid');
+  $query->fields('bc');
+  $query->fields('bcd');
+  $query->orderby('bc.vid');
+  $query->orderby('bc.rank');
+  if (count($vids) == 1) {
+    $query->condition('bc.vid', $vids[0]);
+  }
+  else {
+    $query->condition('bc.vid', $vids, 'IN');
+  }
+  if ($auth_category) {
+    $query->condition('bc.auth_category', $auth_category);
+  }
+  $query->addMetaData('base_table', 'biblio_contributor');
+  $query->addTag('node_access');
+  $result = $query->execute();
+
+  foreach ($result as $creator) {
+    $contributors[$creator->vid][] = (array)$creator;
+  }
+
+  return $contributors;
+}
+/**
+ * Add separate author named "et al" to the end of the author array
+ *
+ * @param $authors - author array to augment
+ * @param $type - auth_type
+ * @return TRUE if author was added, FALSE if "etal" was already there
+ */
+function biblio_authors_add_etal(&$authors, $type) {
+  $etal = "et al"; $max_rank = 0;
+  foreach ($authors as $author) { // et al author should be added only once per type
+    if ($author['auth_type'] != $type) continue;
+    if ($author['name'] == $etal) {
+      return FALSE;
+    }
+    $max_rank = max($max_rank, $author['rank']);
+  }
+  $authors[] = biblio_parse_author(array('name' => $etal, 'auth_type' => $type, 'lastname' => $etal, 'rank' => $max_rank + 1));
+  return TRUE;
+}
+
+/**
+ * @param unknown_type $node
+ * @return unknown
+ */
+function biblio_delete_contributors($node) {
+  $count = db_delete('biblio_contributor')
+            ->condition('nid', $node->nid)
+            ->execute();
+  return $count;
+}
+
+/**
+ * @param unknown_type $node
+ * @return unknown
+ */
+function biblio_delete_contributors_revision($node) {
+  $count = db_delete('biblio_contributor')
+            ->condition('vid', $node->vid)
+            ->execute();
+  return $count;
+}
+
+/**
+ * @param unknown_type $cid
+ */
+function biblio_delete_contributor($cid) {
+    db_delete('biblio_contributor')
+      ->condition('cid', $cid)
+      ->execute();
+
+  return db_delete('biblio_contributor_data')
+            ->condition('cid', $cid)
+            ->execute();
+
+}
+/**
+ * @param unknown_type $cid
+ * @param unknown_type $vid
+ */
+function biblio_delete_contributor_revision($cid, $vid) {
+  return db_delete('biblio_contributor')
+          ->condition('cid', $cid)
+          ->condition('vid', $vid)
+          ->execute();
+
+}
+
+/**
+ * Get the number of orphaned authors in the database
+ *
+ * @return number
+ */
+function biblio_count_orphan_authors() {
+  $cids =  biblio_get_orphan_author_ids();
+  return count($cids);
+}
+
+/**
+ * Get an array of authors which are not associated with any biblio entires.
+ * @return array
+ */
+function biblio_get_orphan_authors() {
+  $authors = array();
+  $cids =  biblio_get_orphan_author_ids();
+
+  if (count($cids)) {
+    $query = db_select('biblio_contributor_data', 'bcd');
+    $result = $query->fields('bcd')
+      ->condition('cid', $cids, 'IN')
+      ->orderBy('lastname')
+      ->execute();
+
+    foreach ($result as $author) {
+      $authors[] = $author;
+    }
+  }
+  return $authors;
+}
+
+/**
+ * Get an array of author id's which are not associated with any biblio entries
+ *
+ * @return array
+ */
+function biblio_get_orphan_author_ids() {
+  $orphans = array();
+  $active_cids = array();
+  $all_cids = array();
+
+  $query = db_select('biblio_contributor', 'bc');
+  $active_cids = $query
+    ->fields('bc', array('cid'))
+    ->groupBy('cid')
+    ->execute()
+    ->fetchCol();
+
+  $query = db_select('biblio_contributor_data', 'bcd');
+  $all_cids = $query
+    ->fields('bcd', array('cid'))
+    ->condition(db_and()->condition('bcd.cid', 0, '>')->condition('bcd.alt_form', 0, '='))
+    ->execute()
+    ->fetchCol();
+
+  $orphans = array_diff($all_cids, $active_cids);
+
+  return $orphans;
+}
+
+/**
+ * @param unknown_type $force
+ */
+function biblio_delete_orphan_authors($force = FALSE) {
+  if (variable_get('biblio_auto_orphaned_author_delete', 0) || $force) {
+    $orphans = biblio_get_orphan_author_ids();
+    if (!empty($orphans)) {
+      db_delete('biblio_contributor_data')
+        ->condition('cid', $orphans, 'IN')
+        ->execute();
+    }
+  }
+}
+
+/**
+ * @param unknown_type $node
+ * @return Ambigous <success, boolean>
+ */
+function biblio_insert_contributors($node) {
+  if (!empty($node->biblio_contributors)) {
+    return _save_contributors($node->biblio_contributors, $node->nid, $node->vid);
+  }
+}
+
+/**
+ * @param unknown_type $node
+ */
+function biblio_update_contributors($node) {
+  if (!empty($node->biblio_contributors)) {
+    _save_contributors($node->biblio_contributors, $node->nid, $node->vid, TRUE);
+  }
+  return;
+
+}
+
+/**
+ * @param unknown_type $author
+ */
+function biblio_save_contributor(&$author) {
+  foreach ($author as $key => $value) {
+    $author[$key] = trim($value);
+  }
+  return drupal_write_record('biblio_contributor_data', $author);
+}
+
+/**
+ * @param unknown_type $author
+ * @return boolean
+ */
+function biblio_update_contributor(&$author) {
+  if (!isset($author['cid'])) return FALSE;
+  return drupal_write_record('biblio_contributor_data', $author, 'cid');
+}
+
+/**
+ * @param unknown_type $authors
+ */
+function _biblio_contributor_sort(&$authors) {
+  foreach ($authors as $key => $author) {
+    if (!isset($author['rank']) || empty($author['rank'])) {
+      $authors[$key]['rank'] = $key;
+    }
+  }
+  usort($authors, '_biblio_contributor_usort');
+}
+
+/**
+ * @param unknown_type $a
+ * @param unknown_type $b
+ * @return number
+ */
+function _biblio_contributor_usort($a, $b) {
+  if (empty($a['name'])) return 1;
+  if (empty($b['name'])) return -1;
+  return ($a['rank'] < $b['rank']) ? -1 : 1;
+}
+/**
+ * Save contributors to the database
+ * @param $authors
+ * @param $nid
+ * @param $vid
+ * @param $update
+ * @return success of database operations
+ */
+function _save_contributors(&$contributors, $nid, $vid, $update = FALSE) {
+  $rank = 0;
+
+  db_delete('biblio_contributor')
+      ->condition(db_and()->condition('nid', $nid)->condition('vid', $vid))
+      ->execute();
+
+  // re-sort the authors by rank because the rank may have changed due to tabledrag on the input form
+  _biblio_contributor_sort($contributors);
+
+  $name_parser = new HumanNameParser_Parser();
+
+  foreach ($contributors as  $key => $author) {
+    if (!empty($author['name'])) {
+      if (isset($author['cid']) && !empty($author['cid'])) {
+        // check to make sure the name wasn't changed
+        // this should only happen via the node/add/biblio input form
+        $auth = biblio_get_contributor($author['cid']);
+        if (!empty($auth) && isset($auth->name) && $auth->name != $author['name']) {
+          //if the name has changed, NULL the cid so a new entry is created
+          $author['cid'] = NULL;
+        }
+        else {
+          $contributors[$key] = array_merge($author, (array)$auth);
+        }
+      }
+      // if we don't have a cid, lets see if we can find and exact match
+      // to the name and use that cid
+      if (!isset($author['cid']) || empty($author['cid'])) {
+        $auth = biblio_get_contributor_by_name($author['name']);
+        if (!empty($auth) && isset($auth->cid)) {
+          $author['cid'] = $auth->cid;
+          $contributors[$key] = array_merge($author, (array)$auth);
+        }
+      }
+
+      // if we still don't have a cid, then create a new entry in the biblio_contirbutor_data table
+      if (empty($author['cid'])) {
+        try {
+          $author = $name_parser->parseName($author);
+        }
+        catch (Exception $e) {
+          $link = l('in node ' . $nid, 'node/' . $nid);
+          $message = $e->getMessage() . ' ' . $link;
+          drupal_set_message($message , 'error');
+          watchdog('biblio', $message, array(), WATCHDOG_ERROR);
+        }
+
+        $contributors[$key] = $author;
+        biblio_save_contributor($author);
+      }
+
+      // we should now have a cid, if not we are in big trouble...
+      if (empty ($author['cid'])) {
+        //throw error that author was not saved
+      }
+
+      $link_array = array(
+          'nid' => $nid,
+          'vid' => $vid,
+          'cid' => $author['cid'],
+          'rank' => $rank++,
+          'auth_type' => !empty($author['auth_type']) ? $author['auth_type'] :  $author['auth_category'],
+          'auth_category' =>  $author['auth_category'],
+      );
+
+      if (!drupal_write_record('biblio_contributor', $link_array)) return FALSE;
+    }
+  }
+  //TODO  check if it is necessary to reset aka here...
+  //  db_query("UPDATE {biblio_contributor_data} SET aka = cid WHERE aka = 0 OR aka IS NULL");
+  //  db_update('biblio_contributor_data')
+  //    ->fields(array('aka', )
+  return TRUE; // successfully saved all contributors
+}
+/*
+ Released through http://bibliophile.sourceforge.net under the GPL licence.
+ Do whatever you like with this -- some credit to the author(s) would be appreciated.
+
+ A collection of PHP classes to manipulate bibtex files.
+
+ If you make improvements, please consider contacting the administrators at bibliophile.sourceforge.net so that your improvements can be added to the release package.
+
+ Mark Grimshaw 2004/2005
+ http://bibliophile.sourceforge.net
+
+ 28/04/2005 - Mark Grimshaw.
+ Efficiency improvements.
+
+ 11/02/2006 - Daniel Reidsma.
+ Changes to preg_matching to account for Latex characters in names such as {\"{o}}
+ */
+// For a quick command-line test (php -f PARSECREATORS.php) after installation, uncomment these lines:
+/***********************
+ $authors = "Mark \~N. Grimshaw and Bush III, G.W. & M. C. H{\\'a}mmer Jr. and von Frankenstein, Ferdinand Cecil, P.H. & Charles Louis Xavier Joseph de la Vallee P{\\\"{o}}ussin";
+ $creator = new PARSECREATORS();
+ $creatorArray = $creator->parse($authors);
+ print_r($creatorArray);
+ ***********************/
+/* Create writer arrays from bibtex input.
+ 'author field can be (delimiters between authors are 'and' or '&'):
+ 1. <first-tokens> <von-tokens> <last-tokens>
+ 2. <von-tokens> <last-tokens>, <first-tokens>
+ 3. <von-tokens> <last-tokens>, <jr-tokens>, <first-tokens>
+ */
+/**
+ * @param $author_array
+ * @return unknown_type
+ */
+function biblio_parse_author($author_array, $cat = 0) {
+
+  if (isset($author_array['auth_category']) && $author_array['auth_category'] == 5) {
+    $author_array['firstname'] = '';
+    $author_array['initials'] = '';
+    $author_array['lastname'] = trim($author_array['name']);
+    $author_array['prefix'] = '';
+    $author_array['literal'] = 1;
+  }
+  else {
+    $value = trim($author_array['name']);
+    $appellation = $prefix = $surname = $firstname = $initials = '';
+    $prefix = "";
+    $value = preg_replace("/\s{2,}/", ' ', $value); // replace multiple white space by single space
+    $author = explode(",", $value);
+    $size = sizeof($author);
+    // No commas therefore something like Mark Grimshaw, Mark Nicholas Grimshaw, M N Grimshaw, Mark N. Grimshaw
+    if ($size == 1) {
+      // Is complete surname enclosed in {...}, unless the string starts with a backslash (\) because then it is
+      // probably a special latex-sign..
+      // 2006.02.11 DR: in the last case, any NESTED curly braces should also be taken into account! so second
+      // clause rules out things such as author="a{\"{o}}"
+      //
+      if (preg_match("/(.*) {([^\\\].*)}/", $value, $matches) && !(preg_match("/(.*) {\\\.{.*}.*}/", $value, $matches2))) {
+        $author = explode(" ", $matches[1]);
+        $surname = $matches[2];
+      }
+      else {
+        $author = explode(" ", $value);
+        // last of array is surname (no prefix if entered correctly)
+        $surname = array_pop($author);
+      }
+    }
+    // Something like Grimshaw, Mark or Grimshaw, Mark Nicholas  or Grimshaw, M N or Grimshaw, Mark N.
+    else
+    if ($size == 2) {
+      // first of array is surname (perhaps with prefix)
+      list ($surname, $prefix) = _grabSurname(array_shift($author));
+    }
+    // If $size is 3, we're looking at something like Bush, Jr. III, George W
+    else {
+      // middle of array is 'Jr.', 'IV' etc.
+      $appellation = implode(' ', array_splice($author, 1, 1));
+      // first of array is surname (perhaps with prefix)
+      list ($surname, $prefix) = _grabSurname(array_shift($author));
+    }
+    $remainder = implode(" ", $author);
+    list ($firstname, $initials, $prefix2) = _grabFirstnameInitials($remainder);
+    if (!empty ($prefix2))
+    $prefix .= $prefix2;
+    //var_dump($prefix);
+    //$surname = $surname . ' ' . $appellation;
+    $author_array['firstname'] = trim($firstname);
+    $author_array['initials'] = (strlen(trim($initials)) > 10) ? drupal_substr(trim($initials), 0, 10) : trim($initials);
+    $author_array['lastname'] = trim($surname);
+    $author_array['prefix'] = trim($prefix);
+    $author_array['suffix'] = trim($appellation);
+  }
+  $author_array['md5'] =  _md5sum($author_array);
+  return $author_array;
+}
+/**
+ * @param $creator
+ * @return unknown_type
+ */
+function _md5sum($creator) {
+  $string = $creator['firstname'] . $creator['initials'] . $creator['prefix'] . $creator['lastname'];
+  $string = str_replace(' ', '', drupal_strtolower($string));
+  return md5($string);
+}
+// grab firstname and initials which may be of form "A.B.C." or "A. B. C. " or " A B C " etc.
+/**
+ * @param $remainder
+ * @return unknown_type
+ */
+function _grabFirstnameInitials($remainder) {
+  $prefix = array();
+  $firstname = $initials = '';
+  $array = explode(" ", $remainder);
+  foreach ($array as $value) {
+    $first_char = drupal_substr($value, 0, 1);
+    if ((ord($first_char) >= 97) && (ord($first_char) <= 122)) {
+    $prefix[] = $value;
+    }
+    elseif (preg_match("/[a-zA-Z]{2,}/", trim($value))) {
+      $firstname_array[] = trim($value);
+    }
+    else {
+      $initials_array[] = trim(str_replace(".", " ", trim($value)));
+    }
+  }
+  if (isset ($initials_array)) {
+    $initials = implode(" ", $initials_array);
+  }
+  if (isset ($firstname_array)) {
+    $firstname = implode(" ", $firstname_array);
+  }
+  if (!empty ($prefix)) {
+    $prefix = implode(" ", $prefix);
+  }
+  return array($firstname, $initials, $prefix);
+}
+// surname may have title such as 'den', 'von', 'de la' etc. - characterised by first character lowercased.  Any
+// uppercased part means lowercased parts following are part of the surname (e.g. Van den Bussche)
+/**
+ * @param $input
+ * @return unknown_type
+ */
+function _grabSurname($input) {
+  $no_prefix = FALSE;
+  $surname = FALSE;
+  $prefix  = FALSE;
+
+  $surname_array = explode(" ", $input);
+
+  foreach ($surname_array as $value) {
+    $first_char = substr($value, 0, 1);
+    if (!$no_prefix && (ord($first_char) >= 97) && (ord($first_char) <= 122)) {
+      $prefix[] = $value;
+    }
+    else {
+      $surname[] = $value;
+      $no_prefix = TRUE;
+    }
+  }
+  if (!empty($surname)) {
+    $surname = implode(" ", $surname);
+  }
+  if (!empty ($prefix)) {
+    $prefix = implode(" ", $prefix);
+  }
+  return array($surname, $prefix);
+}
+/**
+ * @return unknown_type
+ */
+function _loadMD5() {
+  static $md5   = array();
+  static $count = 0;
+  $db_count = db_query("SELECT COUNT(*) FROM {biblio_contributor_data}")->fetchField();
+  if ($db_count != $count) { //refresh the cached data as some new authors may have been added or removed
+    $count = $db_count;
+    $md5 = array();
+    $result = db_query('SELECT md5,cid  FROM {biblio_contributor_data} ');
+    foreach ($result as $row ) {
+      $md5[$row->cid] = $row->md5;
+    }
+  }
+  return (count($md5)) ? $md5 : NULL;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.feeds.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,211 @@
+<?php
+function _biblio_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+  if ($entity_type == 'node' && $bundle_name == 'biblio') {
+    $schema = drupal_get_schema('biblio');
+    foreach ($schema['fields'] as $field => $spec) {
+      if (strstr($field, 'biblio_')) {
+        $type = $spec['type'];
+        $length = isset($spec['length']) ? ' ['. $spec['length'] . ']': '';
+        $targets[$field] = array(
+          'name' => $field . '  (' . $type . $length . ')',
+          'description' =>'',
+          'callback' => '_biblio_feeds_set__simple_target',
+        );
+      }
+    }
+    $targets['biblio_type']['callback'] = '_biblio_feeds_set__type_target';
+    $targets['biblio_contributor'] = array(
+      'name' => t('biblio_contributor'),
+      'description' => t('This is a contributor (author) contained in a biblio entry.'),
+      'callback' => '_biblio_feeds_set__contrib_target',
+ //     'real_target' => 'my_node_field_two', // Specify real target field on node.
+    );
+    $targets['biblio_keyword'] = array(
+      'name' => t('biblio_keyword'),
+      'description' => t('This is a keyword contained in a biblio entry.'),
+      'callback' => '_biblio_feeds_set__keyword_target',
+ //     'real_target' => 'my_node_field_two', // Specify real target field on node.
+    );
+  }
+}
+
+function _biblio_feeds_set__type_target($source, $entity, $target, $value) {
+  static $types = array();
+
+  if (empty($value)) {
+    return;
+  }
+
+  // Handle non-multiple value fields.
+  if (!is_array($value)) {
+    $value = array($value);
+  }
+
+  if (isset($value[0]) && !empty($value[0])) {
+    if (intval($value[0]) > 0) {
+      // value[0] is the bibio type ID
+      if (empty($types)) {
+        $result = db_query('SELECT t.* FROM {biblio_types} as t WHERE t.tid > 0');
+        foreach ($result as $row) {
+          $types[$row->tid] = $row->tid;
+        }
+      }
+
+      $type_id = $value[0];
+      $entity->biblio_type = (isset($types[$type_id])) ? $type_id : 129;
+    }
+    elseif (is_string($value[0])) {
+      // value[0] is the bibio type name
+      if (empty($types)) {
+        $result = db_query('SELECT t.* FROM {biblio_types} as t WHERE t.tid > 0');
+        foreach ($result as $row) {
+          $types[$row->tid] = str_replace(" ","_", strtolower($row->name));
+        }
+      }
+
+      $type = array_search($value[0], $types);
+      $entity->biblio_type = (!empty($type)) ? $type : 129;
+    }
+  }
+}
+
+function _biblio_feeds_set__simple_target($source, $entity, $target, $value) {
+  if (empty($value)) {
+    return;
+  }
+
+  // Handle non-multiple value fields.
+  if (!is_array($value)) {
+    $value = array($value);
+  }
+
+  if (isset($value[0]) && !empty($value[0])) {
+    $entity->$target = $value[0];
+    if ($target == 'biblio_abst_e') {
+      $entity->biblio_formats[$target] = 'full_html';
+    }
+  }
+}
+
+function _biblio_feeds_set__contrib_target($source, $entity, $target, $value) {
+  if (is_string($value)) {
+    $value = explode('||', $value);
+  }
+  foreach ($value as $author) {
+    $entity->biblio_contributors[] =  array(
+            'name' => $author,
+            'auth_category' => 1,
+          );
+  }
+}
+
+function _biblio_feeds_set__keyword_target($source, $entity, $target, $value) {
+  if (!empty($value)) {
+    $entity->biblio_keywords = $value;
+  }
+}
+
+function _biblio_feeds_oai_importer_default() {
+
+  $feeds_importer = new stdClass;
+  $feeds_importer->disabled = FALSE; /* Edit this to true to make a default feeds_importer disabled initially */
+  $feeds_importer->api_version = 1;
+  $feeds_importer->id = 'biblio_oai_pmh';
+  $feeds_importer->config = array(
+    'name' => 'Biblio OAI-PMH',
+    'description' => 'Import an OAI-PMH feed into the Biblio node type.',
+    'fetcher' => array(
+      'plugin_key' => 'FeedsOAIHTTPFetcher',
+      'config' => array(
+        'auto_detect_feeds' => FALSE,
+        'use_pubsubhubbub' => FALSE,
+        'last_fetched_timestamp' => '',
+        'earliest_timestamp' => '',
+        'use_dates' => FALSE,
+        'to' => array(),
+        'from' => array(),
+      ),
+    ),
+    'parser' => array(
+      'plugin_key' => 'FeedsOAIParser',
+      'config' => array(),
+    ),
+    'processor' => array(
+      'plugin_key' => 'FeedsNodeProcessor',
+      'config' => array(
+        'content_type' => 'biblio',
+        'expire' => '-1',
+        'author' => 0,
+        'mappings' => array(
+          0 => array(
+            'source' => 'title',
+            'target' => 'title',
+            'unique' => 0,
+          ),
+          1 => array(
+            'source' => 'publisher',
+            'target' => 'biblio_publisher',
+            'unique' => FALSE,
+          ),
+          2 => array(
+            'source' => 'subject',
+            'target' => 'biblio_keyword',
+            'unique' => FALSE,
+          ),
+          3 => array(
+            'source' => 'source',
+            'target' => 'biblio_secondary_title',
+            'unique' => FALSE,
+          ),
+          4 => array(
+            'source' => 'guid',
+            'target' => 'guid',
+            'unique' => 1,
+          ),
+          5 => array(
+            'source' => 'creator',
+            'target' => 'biblio_contributor',
+            'unique' => FALSE,
+          ),
+          6 => array(
+            'source' => 'description',
+            'target' => 'biblio_abst_e',
+            'unique' => FALSE,
+          ),
+          7 => array(
+            'source' => 'contributor',
+            'target' => 'biblio_contributor',
+            'unique' => FALSE,
+          ),
+          8 => array(
+            'source' => 'identifier',
+            'target' => 'biblio_url',
+            'unique' => FALSE,
+          ),
+          9 => array(
+            'source' => 'date',
+            'target' => 'biblio_year',
+            'unique' => FALSE,
+          ),
+          10 => array(
+            'source' => 'setspec_raw',
+            'target' => 'biblio_type',
+            'unique' => FALSE,
+          ),
+        ),
+        'update_existing' => '0',
+        'input_format' => 'plain_text',
+      ),
+    ),
+    'content_type' => '',
+    'update' => 0,
+    'import_period' => '1800',
+    'expire_period' => 3600,
+    'import_on_create' => 1,
+    'process_in_background' => 0,
+  );
+
+  return array(
+    'biblio_oai' => $feeds_importer
+  );
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.fields.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,51 @@
+<?php
+function _biblio_field_extra_fields() {
+  $extras['node']['biblio']['form'] = array();
+  $fields = array();
+
+    $result = db_query("SELECT * FROM {biblio_fields} b
+              INNER JOIN {biblio_field_type} bt ON b.fid = bt.fid
+              INNER JOIN {biblio_field_type_data} btd ON btd.ftdid=bt.ftdid
+              WHERE bt.tid=:tid ORDER BY bt.weight ASC", array(':tid' => 0), array('fetch' => PDO::FETCH_ASSOC));
+
+    foreach ($result as $row) {
+        $fields[$row['name']] = $row;
+    }
+    _biblio_localize_fields($fields);
+
+    $extras['node']['biblio']['form']['biblio_type'] = array(
+      'label'       => t('Publication Type'),
+      'description' => t('Biblio module form.'),
+      'weight'      => -4
+    );
+
+    foreach ($fields as $key => $fld) {
+      $label = check_plain($fld['title']);
+      if ($fld['type'] == 'textarea' ||  $fld['type'] == 'contrib_widget') {
+        $key = $key . '_field';
+        $label = $label . ' (' . t('Fieldset') . ')';
+      }
+      $extras['node']['biblio']['form'][$key] = array(
+        'label'       => $label,
+        'description' => t('Biblio module form.'),
+        'weight'      => $fld['weight'] / 10
+      );
+    }
+    $extras['node']['biblio']['form']['other_fields'] = array(
+        'label'       => t('Other Biblio Fields') . ' (' . t('Fieldset') . ')',
+        'description' => t('Biblio module form.'),
+        'weight'      => 0
+    );
+
+    $extras['user']['user'] = array(
+        'form' => array(
+            'biblio_fieldset' => array(
+                'label' => t('User specific Biblio settings'),
+                'description' => t('Biblio module account form elements.'),
+                'weight' => -10,
+            ),
+        ),
+    );
+
+  return $extras;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.import.export.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,873 @@
+<?php
+
+/**
+ * @file
+ * Functions that are used to import and export biblio data.
+ *
+ */
+/*   biblio.import.export.inc
+ *
+ *   Copyright (C) 2006-2011  Ron Jerome
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License along
+ *   with this program; if not, write to the Free Software Foundation, Inc.,
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+/**
+ * Return a form select box populated with all the users of the site.
+ *
+ * @param $my_uid
+ *   The user id of the person accessing the form so the select box defaults
+ *   to their userid
+ * @return
+ *   An array which will be used by the form builder to add a select box to a form
+ */
+function _biblio_admin_build_user_select($my_uid) {
+  $sql = 'SELECT DISTINCT u.uid, u.name, u.status, u.mail FROM {users} u  WHERE u.uid <> 0 ';
+  $result = db_query($sql);
+  foreach ($result as $user) {
+    $users[$user->uid] = $user->name . " ($user->mail)";
+  }
+  asort($users);
+  $select = array(
+    '#type' => 'select',
+    '#title' => t("Set user ID of entries in this file to"),
+    '#options' => $users,
+    '#default_value' => $my_uid,
+    '#disabled' => (user_access('administer biblio')) ?  FALSE : TRUE
+  );
+  return $select;
+}
+/**
+ * Return a form used to import files into biblio.
+ *
+ * @return
+ *   An array which will be used by the form builder to build the import form
+ */
+function biblio_import_form($form, &$form_state) {
+  global $user;
+  $msg = '';
+  $biblio_vocabs = array();
+
+  if (biblio_access('import')) { // && !user_access('administer nodes')) {
+    $form['#attributes']['enctype'] = 'multipart/form-data';
+    $form['biblio_import_file'] = array(
+        '#type' => 'file',
+        '#title' => t('Import file'),
+        '#default_value' => '',
+        '#size' => 60
+    );
+
+    $import_options = module_invoke_all('biblio_import_options');
+    if (count($import_options) > 1) {
+      $form['filetype'] = array(
+          '#type' => 'select',
+          '#title' => t('File Type'),
+          '#default_value' => 0,
+          '#options' => array(
+              '0' => t('Select type'),
+          )
+      );
+
+      $form['filetype']['#options'] = array_merge($form['filetype']['#options'], $import_options);
+      asort($form['filetype']['#options']);
+    }
+    elseif (count($import_options) == 1) {
+      $form['biblio_import_file']['#description'] = t('Import type: @option', array('@option' => current($import_options)));
+      $form['filetype'] = array(
+          '#type' => 'value',
+          '#value' => key($import_options),
+      );
+    }
+    elseif (count($import_options) == 0) {
+      $form['biblio_import_file']['#disabled'] = TRUE;
+      drupal_set_message(t("You won't be able to select a file until you enable at least one import module."), 'error');
+
+    }
+
+    $form['batch_process'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Batch Process'),
+        '#default_value' => 1,
+        '#description' => t('You should use batch processing if your import file contains more than about 20 records, or if you are experiencing script timeouts during import'),
+    );
+    $form ['userid'] = _biblio_admin_build_user_select($user->uid);
+    // Get the vocabularies  attached to the biblio node type ...
+    foreach (field_info_instances('node', 'biblio') as $instance) {
+      $field = field_info_field_by_id($instance['field_id']);
+      if ($field['type'] == 'taxonomy_term_reference') {
+        foreach ($field['settings']['allowed_values'] as $delta => $tree) {
+          $biblio_vocabs[$tree['vocabulary']] = array('instance' => $instance, 'field' => $field);
+        }
+      }
+    }
+
+    // ... and print a form to select the terms in each of them
+    $form['import_taxonomy'] = array(
+        '#type' => 'fieldset',
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+        '#title' => t('Taxonomy Settings'),
+        '#description' => t('Typically you don\'t have to do anything here, however if you wish, you may select terms to be assigned to imported records. This effectively adds a keyword to all entries being imported.'));
+    if (count($biblio_vocabs)) {
+      $vocabularies = module_invoke('taxonomy', 'get_vocabularies', 'biblio');
+      if (variable_get('biblio_keyword_freetagging', 0)) {
+        $freetag_vocab = $vocabularies[variable_get('biblio_keyword_vocabulary', 0)];
+        unset($vocabularies[variable_get('biblio_keyword_vocabulary', 0)]);
+        $msg = t('<b>NOTE:</b> Keyword "free tagging" is turned on, consequently all incomming keywords will be added to the <b>@name</b> vocabulary as specified in the "Keyword" section of the !url page.', array('@name' => $freetag_vocab->name, '!url' => l(t('admin/config/content/biblio'), 'admin/config/content/biblio')));
+      }
+      else {
+        $msg = t('<b>NOTE:</b> Keyword "free tagging" is turned off, consequently keywords will <b>NOT</b> be added to the vocabulary as specified in the Taxonomy section of the !url page.', array('!url' => l(t('admin/config/content/biblio'), 'admin/config/content/biblio')));
+      }
+      $i = 0;
+      $form += array('#parents' => array());
+      $form['import_taxonomy']['vocabularies'] = array();
+      $term_refs = array();
+
+      foreach ($vocabularies as $vocabulary) {
+        if (in_array($vocabulary->machine_name, array_keys($biblio_vocabs))) {
+          $term_refs[] = $biblio_vocabs[$vocabulary->machine_name]['instance']['field_name'];
+          $entity = new stdClass();
+          $entity->type = 'biblio';
+          $field = $biblio_vocabs[$vocabulary->machine_name]['field'];
+          $instance = $biblio_vocabs[$vocabulary->machine_name]['instance'];
+          $items = array();
+          $form['import_taxonomy']['vocabularies'] += field_default_form('node', $entity, $field, $instance, 'und', $items, $form, $form_state);
+        }
+      }
+      if (!empty($term_refs)) {
+        $form['term_refs'] = array(
+            '#type' => 'hidden',
+            '#value' => $term_refs,
+        );
+        $form['import_taxonomy']['copy_to_biblio'] = array(
+            '#type' => 'checkbox',
+            '#title' => t('Copy these terms to the biblio keyword database'),
+            '#return_value' => 1,
+            '#default_value' =>  variable_get('biblio_copy_taxo_terms_to_keywords', 0),
+            '#description' => t('If this option is selected, the selected taxonomy terms will be copied to the ' . check_plain(variable_get('biblio_base_title', 'Biblio')) . ' keyword database and be displayed as keywords (as well as taxonomy terms) for this entry.')
+        );
+      }
+    }
+    else {
+      if (module_exists('taxonomy')) {
+        $vocab_msg = t('There are currently no "Term references" attached to the biblio node type. If you would like to associate a Taxonomy vocabulary with the Biblio node type, go the the !url page and add one or more "Term reference" fields.', array('!url' => l(t('admin/structure/types/manage/biblio/fields'), 'admin/structure/types/manage/biblio/fields')));
+      }
+      else{
+        $vocab_msg = '<div class="admin-dependencies">' . t('Depends on') . ': ' . t('Taxonomy') . ' (<span class="admin-disabled">' . t('disabled') . '</span>)</div>';
+
+      }
+      $form['import_taxonomy']['vocabulary_message'] = array(
+          '#markup' => '<p><div>' . $vocab_msg . '</div></p>'
+      );
+    }
+    $form['import_taxonomy']['freetagging_information'] = array(
+        '#markup' => '<p><div>' . $msg . '</div></p>'
+    );
+    $form['button'] = array('#type' => 'submit', '#value' => t('Import'));
+    return $form;
+  }
+  else {
+    drupal_set_message(t("You are not authorized to access the biblio import page"), 'error');
+  }
+}
+
+/**
+ * Implementation of hook_validate() for the biblio_import_form.
+ */
+function biblio_import_form_validate($form, & $form_state) {
+  $op = $form_state['values']['op'];
+  $filetype = isset($form_state['values']['filetype']) ? $form_state['values']['filetype'] : 0;
+  if ($error = isset($_FILES['files']) ? $_FILES['files']['error']['biblio_import_file'] : '') {
+    switch ($error) {
+      case 1: form_set_error('biblio_import_form', t("The uploaded file exceeds the upload_max_filesize directive in php.ini."));
+      break;
+      case 2: form_set_error('biblio_import_form', t("The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form."));
+      break;
+      case 3: form_set_error('biblio_import_form', t("The uploaded file was only partially uploaded."));
+      break;
+      case 4: form_set_error('biblio_import_form', t("No file was uploaded."));
+      break;
+      case 6: form_set_error('biblio_import_form', t("Missing a temporary folder."));
+      break;
+      case 7: form_set_error('biblio_import_form', t("Failed to write file to disk."));
+      break;
+      case 8: form_set_error('biblio_import_form', t("File upload stopped by extension."));
+    }
+  }
+
+  if ($op == t('Import') && $filetype == "0") {
+    form_set_error('biblio_import_form', t("You did not select the file type"));
+  }
+}
+/**
+ * Implementation of hook_submit() for the biblio_import_form.
+ */
+function biblio_import_form_submit($form, & $form_state) {
+  global $user;
+  $batch_proc = FALSE;
+  $extensions = 'xml bib enw mrc ris txt';
+  $validators['file_validate_extensions'] = array();
+  $validators['file_validate_extensions'][0] = $extensions;
+  if ($form_state['values']['op'] == t('Import') && isset ($form_state['values']['filetype'])) {
+    if ($import_file = file_save_upload('biblio_import_file', $validators)) {
+      if ($form_state['values']['batch_process'] == 1) {
+        $batch_proc = TRUE;  // we will use batch import for larger files.
+      }
+      // Concatenate all the terms of the different vocabularies
+      // in a single array to be sent to biblio_import
+      $terms = array();
+      if (isset($form_state['values']['term_refs'])) {
+        foreach ($form_state['values']['term_refs'] as $key) {
+          if (isset($form_state['values'][$key]) && !empty($form_state['values'][$key])) {
+            foreach ($form_state['values'][$key]['und'] as $id => $item) {
+              if (!is_array($item) || (empty($item['tid']) && (string) $item['tid'] !== '0')) {
+                unset($form_state['values'][$key]['und'][$id]);
+              }
+            }
+            if (empty($form_state['values'][$key]['und'])) {
+              unset($form_state['values'][$key]);
+            }
+            else {
+              $terms[$key] = $form_state['values'][$key];
+            }
+          }
+          //       }
+
+          //FIXME     if (count($terms) && $key == 'copy_to_biblio') $terms['copy_to_biblio'] = $form_state['values'][$key];
+        }
+      }
+
+      // Added the $terms argument
+      // the array of terms to be attached to the node(s)
+      $userid = (isset($form_state['values']['userid'])) ? $form_state['values']['userid'] : $user->uid;
+      $filetype = $form_state['values']['filetype'];
+      $filesize = sprintf("%01.1f", $import_file->filesize / 1000);
+      $filesize = " ($filesize KB)";
+      if ($batch_proc) {
+        $session_id = microtime();
+        $batch_op = array(
+          'title' => t('Importing @filename', array('@filename' => $import_file->filename . $filesize)),
+          'operations' => array(
+            array('biblio_import', array($import_file, $filetype, $userid, $terms, $batch_proc, $session_id)),
+            array('biblio_import_batch_operations', array($session_id, $user, $userid, $terms))
+          ),
+          'progressive' => TRUE,
+          'finished' => 'biblio_import_batch_finished',
+          'init_message' => t('Parsing file...'),
+          'progress_message' => t('Saving nodes...'),
+          'file' => './' . drupal_get_path('module', 'biblio') . '/includes/biblio.import.export.inc'
+        );
+        batch_set($batch_op);
+
+        $base = variable_get('biblio_base', 'biblio');
+        batch_process("$base/import");
+
+      }
+      else{ //not batch processing the file
+        $session_id = microtime();
+        $context = array();
+        biblio_import($import_file, $filetype, $userid, $terms, $batch_proc, $session_id, $context);
+        biblio_import_finalize(TRUE, $context['results']);
+      }
+      file_delete($import_file);
+    }
+    else {
+      drupal_set_message(t("File was NOT successfully uploaded"), 'error');
+    }
+  }
+}
+
+function biblio_import_batch_operations($session_id, $user, $userid, $terms, &$context) {
+ $limit = 10;
+ if (empty($context['sandbox'])) {
+    // Initiate multistep processing.
+    $context['results']['session_id'] = $session_id;
+    $context['results']['userid']     = $userid;
+    $context['results']['user']       = $user;
+    $context['results']['terms']      = $terms;
+    $context['sandbox']['progress']   = 0;
+    $context['sandbox']['current_id'] = 0;
+    $context['results']['nids'] = array();
+    $context['sandbox']['max'] = db_query("SELECT COUNT(DISTINCT(id)) FROM {biblio_import_cache} WHERE session_id = :sessid", array(':sessid' => $session_id))->fetchField();
+    $context['sandbox']['itters'] = $context['sandbox']['max'] / $limit;
+    $context['sandbox']['eta'] = 0;
+  }
+  // Bail out if the cache is empty.
+  if ($context['sandbox']['max'] == 0) {
+    return;
+  }
+
+  // Process the next 20 nodes.
+  timer_start('biblio_import');
+
+  $result = db_query_range("SELECT id, data FROM {biblio_import_cache} WHERE id > :id AND session_id = :sessid ORDER BY id ASC", 0, $limit, array(':id' => $context['sandbox']['current_id'], ':sessid' => $session_id));
+  foreach ($result as $row) {
+    if ($node = unserialize(base64_decode($row->data))) {
+      biblio_save_node($node, $terms);
+      $context['results']['nids'][] = $node->nid;
+    }
+    $context['sandbox']['progress']++;
+    $context['sandbox']['current_id'] = $row->id;
+  }
+  $looptime = timer_stop('biblio_import');
+  $context['sandbox']['eta'] += $looptime['time'];
+  $itters = $context['sandbox']['progress'] / $limit;
+  if ($itters) {
+    $average_time = $context['sandbox']['eta'] / $itters;
+    $eta = (($context['sandbox']['itters'] * $average_time) - ($average_time * $itters)) / 1000;
+    if ($eta >= 60) {
+      $min = (int) $eta / 60;
+    }
+    else {
+      $min = 0;
+    }
+    $sec = $eta % 60;
+    $eta = sprintf("%d:%02d", $min, $sec);
+    $progress = sprintf("%d / %d", $context['sandbox']['progress'],  $context['sandbox']['max'] );
+    $context['message'] = t('<br>Nodes saved: %progress <br> Time remaining: %eta min.<br>' , array('%progress' => $progress, '%eta' => $eta));
+
+  }
+  // Multistep processing : report progress.
+  if ($context['sandbox']['progress'] <= $context['sandbox']['max']) {
+    $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
+  }
+}
+function biblio_import_batch_finished($success, $results, $operations) {
+
+  biblio_import_finalize($success, $results);
+  //clean up import cache...
+  db_delete('biblio_import_cache')
+    ->condition('session_id', $results['session_id'])
+    ->execute();
+}
+
+function biblio_import_finalize($success, $results) {
+  global $user;
+  $format = $results['format'];
+  $nids = $results['nids'];
+  $dups = $results['dups'];
+  $total = count($nids) + count($dups);
+  //    drupal_set_message(t("<i><b>%count</b></i> of <i><b>%total</b></i> nodes were successfully imported.", array('%count' => count($nids), '%total' => $total)), (count($nids) != $total)?'warning':'status');
+
+  if ($success && (count($nids) || count($dups))) {
+    $message = t("The file <i><b>@file</b></i> was successfully uploaded.", array('@file' => $results['file']->filename));
+    drupal_set_message($message, 'status');
+    watchdog($format, $message);
+    $count = count($nids);
+    $message = format_plural($count, 'One of @total node imported.', '@count of @total nodes imported.', array('@total' => $total));
+    drupal_set_message($message, 'status');
+    watchdog($format, $message, array('@count' => $count, '@total' => $total), WATCHDOG_INFO);
+    if (count($dups)) {
+      $count = count($dups);
+      $message = format_plural($count, 'One duplicate node skipped.', '@count duplicate nodes skipped.');
+      drupal_set_message($message, 'status');
+      watchdog($format, $message, array('@count' => $count), WATCHDOG_INFO);
+      foreach ($dups as $nid) {
+        $message = '';
+        $message = t('The item you are trying to import already exists in the database, see');
+        $message .= ' ' . l('node/' . $nid, 'node/' . $nid);
+
+        drupal_set_message($message, 'status');
+        watchdog($format, $message, array(), WATCHDOG_ERROR);
+      }
+    }
+  }
+  else {
+    $count = count($nids);
+    $message = t('Import finished with an error!') . '  ' .  format_plural($count, 'One node imported.', '@count nodes imported.');
+    drupal_set_message($message, 'error');
+    watchdog($format, $message, array('@count' => $count), WATCHDOG_ERROR);
+  }
+
+  $userid = isset($results['userid']) ? $results['userid'] : $user->uid;
+
+  if (user_access('administer biblio') && count($nids) && $user->uid != $userid) {
+    db_update('node')
+      ->fields(array('uid' => $results['userid']))
+      ->condition('nid', $nids, 'IN')
+      ->execute();
+    db_update('node_revision')
+      ->fields(array('uid' => $results['userid']))
+      ->condition('nid', $nids, 'IN')
+      ->execute();
+  }
+
+}
+
+function biblio_import_from_url($URL) {
+  $handle = fopen($URL, "r"); // fetch data from URL in read mode
+  $data = "";
+  if ($handle) {
+    while (!feof($handle)) {
+      $data .= fread($handle, 4096); // read data in chunks
+    }
+    fclose($handle);
+  }
+  else {
+    $errorMessage = t("Error occurred: Failed to open %url", array('%url', $URL)); // network error
+    drupal_set_message($errorMessage, 'error');
+  }
+
+  return $data;
+}
+
+function biblio_export_form() {
+  $form['pot'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#title' => t('POT Export'),
+    '#description' => t('Here you may export a ".pot" file which contains the titles and hints from the database which are not normally captured by translation extractors)')
+  );
+  $form['pot']['button'] = array(
+    '#type' => 'submit',
+    '#value' => t('Export translation data')
+  );
+
+  return $form;
+}
+function biblio_export_form_submit($form, & $form_state) {
+  if ($form_state['values']['op'] == t('Export translation data')) {
+    biblio_dump_db_data_for_pot();
+  }
+
+}
+
+/**
+ * Import data from a file and return the node ids created.
+ *
+ * @param $userid
+ *   The user id that will be assigned to each node imported
+ * @param $filename
+ *   The name of the file containing the data to import
+ * @param $type
+ *   The format of the file to be imported (tagged, XML, RIS, bibTEX)
+ * @param $terms
+ *   the vocabulary that the imported nodes will be associated with
+ * @return
+ *   An array of node id's of the items imported
+ */
+function biblio_import($import_file, $type, $userid = 1, $terms = NULL, $batch = FALSE, $session_id = NULL, &$context ) {
+  global $user;
+  $parsed = 0;
+  $nids = array();
+  $dups = array();
+
+  if (isset($context['message']))  $context['message'] = t('Parsing file');
+  switch ($type) {
+    case 'csv' : // comma separated variable file
+      //        $file_content = @ file_get_contents($import_file->uri);
+      //        $parsed = biblio_csv_import($file_content, $node_template, $node_array);
+      break;
+    case 'biblio_backup' : // a complete backup of all biblio information
+      $file_content = @ file_get_contents($import_file->uri);
+      $parsed = biblio_restore($file_content, $node_template, $node_array);
+      break;
+    default:
+      list($nids, $dups) = module_invoke($type, 'biblio_import', $import_file, $terms, $batch, $session_id);
+      break;
+  }
+  $context['results']['nids']   = $nids;
+  $context['results']['dups']   = $dups;
+  $context['results']['format'] = $type;
+  $context['results']['userid'] = $userid;
+  $context['results']['user']   = $user;
+  $context['results']['file']   = $import_file;
+
+  return $batch ? NULL : $nids;
+}
+/**
+ * Export nodes in a given file format.
+ *
+ * @param $format
+ *   The file format to export the nodes in (tagged, XML, bibTEX)
+ * @param $nid
+ *   If not NULL, then export only the given nodeid, else we will
+ *   use the session variable which holds the most recent query. If neither
+ *   $nid or the session variable are set, then nothing is exported
+ * @param $version
+ *   The version of EndNote XML to use.  There is one format for ver. 1-7 and
+ *   a different format for versions 8 and greater.
+ * @return
+ *   none
+ */
+function biblio_export($format = "tagged", $nid = NULL, $popup = FALSE) {
+  $params = array();
+  $nids = array();
+  $arg_list = array();
+  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+  if ($nid === NULL ) {
+    module_load_include('inc', 'biblio', 'includes/biblio.pages');
+    $uri = drupal_parse_url(request_uri());
+    $arg_list += $uri['query'];
+    $arg_list['page_limit'] = 0;
+    list($nids,,) = biblio_build_query($arg_list);
+  }
+  elseif (!empty ($nid)) {
+    $nids[] = $nid;
+  }
+  elseif (!count($nids)) {
+    return;
+  }
+
+  module_invoke('biblio_' . $format, 'biblio_export', $nids);
+
+}
+
+/**
+ * Save node imported from a file.
+ *
+ * @param $node_array
+ *   a 2 dimensional array containing all the node information
+ * @return
+ *   The node ids of the saved nodes
+ */
+function biblio_save_imported_nodes(& $node_array) {
+  $dup_count = 0;
+  if (function_exists('node_save')) {
+    foreach ($node_array as $imp_node) {
+      $node_ids[] = biblio_save_node($imp_node);
+    }
+  }
+/*  if ($dup_count)
+    drupal_set_message(t("Detected @dupcount duplicate node(s) when importing", array('@dupcount' => $dup_count)), 'error');
+
+  drupal_set_message(t("Succesfully imported @count entries.", array('@count' => count($node_ids))), 'status');
+*/
+  return $node_ids;
+}
+function biblio_save_node($node, $terms = array(), $batch = FALSE, $session_id = NULL, $save_node = TRUE) {
+  global $user;
+
+  if ($batch && $session_id) { // we are batch processing some import data
+    $cache['session_id'] = $session_id;
+    $cache['data'] = base64_encode(serialize($node));// base64_encode to avoid problems unserializing strings with embeded quotes.
+    drupal_write_record('biblio_import_cache', $cache);
+    return;
+  }
+
+  $node->type = 'biblio';
+  // Persist the node revision log since it will be overridden by
+  // node_object_prepare().
+  $created = !empty($node->created)? $node->created : NULL;
+  $revision_log = !empty($node->log)? $node->log : NULL;
+  node_object_prepare($node);
+  $node->created = $created;
+  $node->log = $revision_log;
+
+  if (!empty($terms)) {
+    foreach ($terms as $key => $value) {
+      $node->{$key} = $value;
+    }
+  }
+
+  $node->language = 'und';  //start by setting the language to undefined and then try to refine it.
+  if (module_exists('locale')) {
+    $node->language = locale_language_url_fallback();
+  }
+  if (module_exists('i18n') && variable_get('i18n_node_biblio', 0) && variable_get('language_content_type_biblio', 0) ) {
+    $node->language = module_invoke('i18n', 'default_language');
+  }
+
+  if (!isset($node->biblio_type)) {
+    $node->biblio_type = 129; // default to misc if not set.
+  }
+
+
+  if ($save_node) { // $save_node = TRUE, the normal save path
+    $validation_errors = array();
+    $validation_errors = biblio_save_node_validate($node);
+    node_save($node);
+    if (!empty($validation_errors)) {
+      foreach ($validation_errors as $field => $value) {
+        $message = $field . ' ' . t('was truncated to fit into the database column');
+        $link = l('node/' . $node->nid, 'node/' . $node->nid);
+        drupal_set_message($message . '; ' . $link, 'warning');
+        watchdog('biblio - import', $message, array(), WATCHDOG_ALERT, $link);
+      }
+    }
+    return; // (isset($node->nid)) ? $node->nid : 0;
+  }
+  else { // $save_node = FALSE, primarily used to parse data and return it to the input form
+    return (array)$node;
+  }
+}
+
+function biblio_save_node_validate($node) {
+  static $schema = array();
+  $error = array();
+
+  if (empty($schema)) {
+    $schema['biblio'] = drupal_get_schema('biblio');
+  }
+  if (isset($node->title) && strlen($node->title) > 255) {
+    $error['title'] = $node->title;
+    $node->title = substr($node->title, 0, 255);
+  }
+  if (isset($node->biblio_keywords) && is_array($node->biblio_keywords)) {
+    foreach ($node->biblio_keywords as $key => $word) {
+      if (strlen($word) > 255) {
+        $error['keyword'] = $word;
+        $node->biblio_keywords[$key] = substr($word, 0, 255);
+      }
+    }
+  }
+  if (isset($node->biblio_contributors) && is_array($node->biblio_contributors)) {
+    foreach ($node->biblio_contributors as $key => $author) {
+      if (strlen($author['name']) > 255) {
+        $error['author'] = $author['name'];
+        $node->biblio_contributors[$key]['name'] = substr($author['name'], 0, 255);
+      }
+    }
+  }
+  foreach ($schema['biblio']['fields'] as $field => $spec) {
+    if (isset($node->$field)) {
+      switch ($spec['type']) {
+        case 'varchar':
+          if (strlen($node->$field) > $spec['length']) {
+            $error[$field] = $node->$field;
+            $node->$field = substr($node->$field, 0, $spec['length']);
+          }
+          break;
+      }
+    }
+  }
+  return $error;
+}
+
+
+function biblio_csv_export_2($result, $bfields) {
+  //  $query_biblio_fields = 'SELECT name, title FROM {biblio_fields}';
+  //  $res_biblio_fields = db_query($query_biblio_fields);
+  //  while ($rec = db_fetch_object($res_biblio_fields)) {
+  //    $bfields[$rec->name] = $rec->title;
+  //  }
+  $bfields = biblio_get_db_fields('all');
+  $query_biblio_types = 'SELECT tid, name FROM {biblio_types}';
+  $res_biblio_types = db_query($query_biblio_types);
+  foreach ($res_biblio_types as $rec) {
+    $btypes[$rec->tid] = $rec->name;
+  }
+  switch (variable_get('biblio_csv_field_sep', 'tab')) {
+    case 'tab' :
+      $filedsep = "\t";
+      break;
+    case 'comma' :
+      $filedsep = ',';
+      break;
+  }
+  switch (variable_get('biblio_csv_text_sep', 'dquote')) {
+    case 'dquote' :
+      $textsep = '"';
+      break;
+    case 'quote' :
+      $textsep = '\'';
+      break;
+  }
+  $label = (variable_get('biblio_csv_col_head', 'label') == 'label' ? 1 : 0); // or 'col_name'
+  $linebreak = variable_get('biblio_linebreak_exp', 1);
+  foreach ($result as $rec) {
+    $node_id = $rec->nid;
+    $node_array[$node_id]['type'] = $btypes[$rec->biblio_type]; // there is no "label" for "type"
+    $col_array['type'] = 'Type';
+    foreach (array_keys($bfields) as $fieldname) {
+      if (!empty ($rec-> $fieldname) && !in_array($fieldname, array(
+          'biblio_citekey',
+          'biblio_coins'
+        ))) {
+        $col_array[$fieldname] = $bfields[$fieldname]; // mark field as in use
+        $text = strtr($rec-> $fieldname, $textsep, "$textsep$textsep");
+        if ($linebreak) {
+          $text = strtr($text, ';', "\n");
+        }
+        $node_array[$node_id][$fieldname] = trim($text);
+      }
+    }
+  } //end while
+  if ($label) { // head line containing column names
+    $csv = $textsep . join("$textsep$filedsep$textsep", array_values($col_array)) . "$textsep\n";
+  }
+  else { // original DB field names
+    $csv = $textsep . join("$textsep$filedsep$textsep", array_keys($col_array)) . "$textsep\n";
+  }
+  // Enclosing text in "<text>" is neccessary to enshure
+  // multi line fields (like author) are handled correctly.
+  // Therefore existing " must be excaped before.
+  $csv = '"' . join("\"\t\"", array_keys($col_array)) . "\"\n";
+  foreach ($node_array as $line_array) {
+    $csv_line = '';
+    foreach (array_keys($col_array) as $col) {
+      $csv_line .= "$filedsep$textsep" . $line_array[$col] . $textsep;
+    }
+    $csv .= substr($csv_line, 1) . "\n"; // cut off leading fieldsep and append EOL
+  }
+  drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
+  drupal_add_http_header('Content-Disposition', 'attachment; filename=biblio_export.csv');
+  return $csv;
+}
+//function _biblio_cck_join($biblio_fields = array()) {    // works not with php4
+function _biblio_cck_join(& $biblio_fields) {
+  $cck_join = '';
+  $biblio_fields['nid'] = 'Node-ID'; // identify records for update operations
+  $query_cck_fields = "SELECT field_name, label from {node_field_instance} where type_name='biblio' and not (widget_type='image')";
+  $res_cck_fields = db_query($query_cck_fields);
+  foreach ($$res_cck_fields as $rec) {
+    $cck_table = 'content_' . $rec->field_name;
+    $cck_field = $rec->field_name . '_value';
+    $biblio_fields[$cck_field] = $rec->label;
+    $cck_join .= ' left join {' . $cck_table . '} on b.vid=' . $cck_table . '.vid';
+  }
+  return $cck_join;
+}
+
+function biblio_backup() {
+
+  $csv_function = (!function_exists('fputcsv')) ? 'biblio_fputcsv' : 'fputcsv';
+  $count_sql = "SELECT COUNT(*)
+                FROM {biblio} b, {node} n, {node_revision} nr
+                WHERE b.vid = n.vid and nr.vid = n.vid;";
+  $field_type_sql = "SELECT *  FROM {biblio_field_type} ";
+  $field_type_data_sql = "SELECT *  FROM {biblio_field_type_data} ";
+  $field_fields_sql = "SELECT *  FROM {biblio_fields} ";
+  $types_sql = "SELECT *  FROM {biblio_types} ";
+  $sql = "SELECT b.*,
+          n.type, n.language, n.title, n.uid, n.status, n.created,
+          n.changed, n.comment, n.promote, n.moderate, n.sticky,
+          n.tnid, n.translate,
+          nr.title, nr.body, nr.teaser, nr.log, nr.timestamp, nr.format
+          FROM {biblio} b, {node} n, {node_revision} nr
+          WHERE b.vid = n.vid and nr.vid = n.vid;";
+
+  $biblio_count = db_result(db_query($count_sql));
+  if ($biblio_count) {
+    drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
+    drupal_add_http_header('Content-Disposition', 'attachment; filename=Biblio-export.csv');
+    $biblio_nodes = db_query($sql);
+    while ($node = db_fetch_array($biblio_nodes)) {
+      $results[] = $node;
+    }
+    print biblio_csv_export($results);
+    unset($results);
+    $result = db_query($field_type_data_sql, 'biblio_field_type_data.csv');
+    while ($data = db_fetch_array($result)) {
+      $results[] = $data;
+    }
+    print biblio_csv_export($results);
+    unset($results);
+    $result = db_query($field_fields_sql, 'biblio_fields.csv');
+    while ($data = db_fetch_array($result)) {
+      $results[] = $data;
+    }
+    print biblio_csv_export($results);
+    unset($results);
+    $result = db_query($types_sql, 'biblio_types.csv');
+    while ($data = db_fetch_array($result)) {
+      $results[] = $data;
+    }
+    print biblio_csv_export($results);
+    unset($results);
+    $result = db_query($field_type_sql, 'biblio_field_type.csv');
+    while ($data = db_fetch_array($result)) {
+      $results[] = $data;
+    }
+    print biblio_csv_export($results);
+  }
+}
+
+function biblio_restore(& $csv_content, $mode = 'create') {
+
+}
+
+function biblio_csv_export($results) {
+  $csv = '';
+  if (!is_array($results)) {
+    $result_array[] = (array) $results;
+  }
+  else {
+    $result_array = $results;
+  }
+  $fieldnames = NULL;
+  foreach ((array)$result_array as $rec) {
+    if (empty($fieldnames)) {
+      $fieldnames = array_keys($rec);
+      $csv .= biblio_strcsv($fieldnames);
+    }
+    $csv .= biblio_strcsv($rec);
+  }
+  return $csv;
+}
+
+function biblio_strcsv($fields = array(), $delimiter = ',', $enclosure = '"') {
+  $str = '';
+  $escape_char = '\\';
+  foreach ($fields as $value) {
+    if (strpos($value, $delimiter) !== FALSE || strpos($value, $enclosure) !== FALSE || strpos($value, "\n") !== FALSE || strpos($value, "\r") !== FALSE || strpos($value, "\t") !== FALSE || strpos($value, ' ') !== FALSE) {
+      $str2 = $enclosure;
+      $escaped = 0;
+      $len = strlen($value);
+      for ($i = 0; $i < $len; $i++) {
+        if ($value[$i] == $escape_char) {
+          $escaped = 1;
+        }
+        else
+          if (!$escaped && $value[$i] == $enclosure) {
+            $str2 .= $enclosure;
+          }
+          else {
+            $escaped = 0;
+          }
+        $str2 .= $value[$i];
+      }
+      $str2 .= $enclosure;
+      $str .= $str2 . $delimiter;
+    }
+    else {
+      $str .= $value . $delimiter;
+    }
+  }
+  $str = substr($str, 0, -1);
+  $str .= "\n";
+  return $str;
+}
+function biblio_dump_db_data_for_pot() {
+  $query = "SELECT name, description FROM {biblio_types} ";
+  $result = db_query($query);
+  $strings = array();
+  foreach ($result as $type) {
+    $strings[] = $type->name;
+    if (!empty($type->description)) $strings[] = $type->description;
+  }
+  $query = "SELECT title, hint FROM {biblio_field_type_data} ";
+  $result = db_query($query);
+  foreach ($result as$type_data) {
+    $strings[] = $type_data->title;
+    if (!empty($type_data->hint)) $strings[] = $type_data->hint;
+  }
+  $query = "SELECT title, hint FROM {biblio_contributor_type_data} ";
+  $result = db_query($query);
+  foreach ($result as $type_data ) {
+    $strings[] = $type_data->title;
+    if (!empty($type_data->hint)) $type_data->hint;
+  }
+  $strings = array_unique($strings);
+  foreach ($strings as $string) {
+    $output .= "t(\"$string\"\);\n";
+  }
+
+  drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
+  drupal_add_http_header('Content-Disposition', 'attachment; filename=biblio_db_values.pot');
+  print $output;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.keywords.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,486 @@
+<?php
+/**
+* @file
+* Contains all keyword related functions
+*/
+
+/**
+ * Gets a keyword ID using keyword text as the key.
+ *
+ * @param $name
+ * @return int Keyword ID
+ */
+function biblio_get_kid_by_name($name) {
+  $kw = biblio_get_keyword_by_name($name);
+  if ($kw) {
+    return $kw->kid;
+  }
+}
+/**
+ * @param $name
+ * @return array of keywords
+ */
+function biblio_get_keyword_by_name($name) {
+  static $keywords = array();
+  if (!$kid = array_search($name, $keywords)) {
+    $term = db_query("SELECT kd.kid, kd.word, COUNT(*) as use_count FROM {biblio_keyword_data} kd
+    								LEFT JOIN {biblio_keyword} bk on bk.kid = kd.kid
+    								WHERE LOWER(kd.word) = LOWER(:name)
+    								GROUP BY kd.kid, kd.word", array(':name' => trim($name)))->fetchObject();
+    if ($term) {
+      $keywords[$term->kid] = $term;
+      return $keywords[$term->kid];
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  return $keywords[$kid];
+}
+
+/**
+ * @param $kid
+ * @return unknown_type
+ */
+function biblio_get_keyword_by_id($kid) {
+  static $keywords = array();
+
+  if (!isset($keywords[$kid])) {
+    $keywords[$kid] = db_query('SELECT * FROM {biblio_keyword_data} WHERE kid = :kid', array(':kid' => $kid))->fetchObject();
+  }
+
+  return $keywords[$kid];
+
+}
+
+/**
+ * Load keywords for a single node
+ *
+ * @param $vid
+ * @return keywords for a given node->vid
+ */
+function biblio_load_keywords($vid) {
+  $vids = (isset($vid) ? array($vid) : array());
+  return biblio_load_keywords_multiple($vids);
+}
+
+/**
+ * Load keywords for multiple nodes
+ *
+ * @param array $vids
+ * @return multitype:
+ */
+function biblio_load_keywords_multiple($vids = array()) {
+  $keywords = array();
+  if (empty($vids)) return $keywords;
+
+  $query = db_select('biblio_keyword', 'bk');
+  $query->innerJoin('biblio_keyword_data', 'bkd', 'bk.kid = bkd.kid');
+  $query->addField('bk', 'vid');
+  $query->fields('bkd', array('kid', 'word'));
+  $query->orderby('bk.vid');
+  $query->orderby('bkd.word');
+  if (count($vids) == 1) {
+    $query->condition('bk.vid', $vids[0]);
+  }
+  else {
+    $query->condition('bk.vid', $vids, 'IN');
+  }
+  $query->addMetaData('base_table', 'biblio_keyword');
+  $query->addTag('node_access');
+  $result = $query->execute();
+
+  foreach ($result as $keyword) {
+    $keywords[$keyword->vid][$keyword->kid] = $keyword->word;
+  }
+
+  return $keywords;
+}
+/**
+ * Update the keyword database from the supplied node
+ *
+ * @param stdClass $node
+ * @return
+ *   An array of keyword ID's
+ */
+function biblio_update_keywords($node) {
+  $kids = biblio_insert_keywords($node, TRUE);
+  return $kids;
+}
+
+/**
+ * Insert keywords into the database
+ *
+ * @param $node
+ *   A node with keywords attached
+ * @param $update
+ *   Set to TRUE if you are updating an existing node
+ * @return
+ *   An array of keyword ID's from this node
+ */
+function biblio_insert_keywords($node, $update = FALSE) {
+  $kw_vocab = variable_get('biblio_keyword_vocabulary', 0);
+  $taxo_terms = $typed_keywords = array();
+  $freetag_vocab = FALSE;
+  if (!is_array($node->biblio_keywords)) {
+    $typed_keywords = biblio_explode_keywords($node->biblio_keywords);
+  }
+  else {
+    $typed_keywords = $node->biblio_keywords;
+  }
+
+  if ($update) {
+        $and = db_and()->condition('nid', $node->nid)
+                       ->condition('vid', $node->vid);
+         db_delete('biblio_keyword')
+            ->condition($and)
+            ->execute();
+  }
+
+  if (empty($node->biblio_keywords)) return;
+
+  $vocabularies = module_invoke('taxonomy', 'get_vocabularies');
+  $vid = variable_get('biblio_keyword_vocabulary', 0);
+
+  if (variable_get('biblio_keyword_freetagging', 0) && $vid) {
+    $freetag_vocab = $vocabularies[variable_get('biblio_keyword_vocabulary', 0)];
+  }
+
+  if (isset($node->taxonomy) && is_array($node->taxonomy) && variable_get('biblio_copy_taxo_terms_to_keywords', 0)) { //add any taxonomy terms to our keyword list
+    foreach ($node->taxonomy as $vid => $term) {
+      if ($vid == 'copy_to_biblio' && $term == 0 ) {// don't copy if user overrides the default to copy, just set the $taxo_terms to an empty array and break out of the for loop
+        $taxo_terms = array();
+        break;
+      }
+      if (is_array($term) && !empty($term)) {
+        foreach ($term as $tid) {
+          if ($tid) {
+            $term_obj = taxonomy_term_load($tid);
+            $taxo_terms[$term_obj->tid] = $term_obj->name;
+          }
+        }
+      }
+      elseif ($term) {
+        $term_obj = taxonomy_term_load($term);
+        $taxo_terms[$term_obj->tid] = $term_obj->name;
+      }
+    }
+  }
+
+  $keywords = array_merge($typed_keywords, $taxo_terms);
+
+  foreach ($keywords as $keyword) {
+    $word = (is_object($keyword)) ? trim($keyword->word) : trim($keyword);
+    if (!strlen(trim($word))) continue; //skip if we have a blank
+    $kid = FALSE;
+    // See if the term exists
+    if ( ($kw = biblio_get_keyword_by_name($word)) ) {
+      $kid = $kw->kid;
+    }
+    if (!$kid) {
+      $kw = array('word' => trim($word));
+      $status = biblio_save_keyword($kw);
+      $kid = $kw['kid'];
+    }
+    // Defend against duplicate, differently cased tags
+    if (!isset($inserted[$kid])) {
+      db_merge('biblio_keyword')
+        ->key(array('kid' => $kid, 'vid' => $node->vid))
+        ->fields(
+          array(
+            'kid' => $kid,
+            'nid' => $node->nid,
+            'vid' => $node->vid
+          ))->execute();
+      $inserted[$kid] = TRUE;
+    }
+  }
+
+  // now if we are saving keywords into a taxonomy freetagging vocabulary, then create the tags string and add it to the node object.
+  $vocabularies = module_invoke('taxonomy', 'get_vocabularies');
+  $vid          = variable_get('biblio_keyword_vocabulary', 0);
+  $freetagging  = variable_get('biblio_keyword_freetagging', 0);
+
+  if ($freetagging && $vid) {
+    $freetag_vocab = $vocabularies[$vid];
+    $term_refs     = biblio_get_term_ref_fields();
+    $ft_field      = 'field_' . $freetag_vocab->machine_name . '_ref';
+    if (!isset($term_refs[$ft_field])) {
+      biblio_create_term_ref($freetag_vocab);
+    }
+  }
+
+
+  if ($freetagging && $freetag_vocab ) {
+    $tids = array();
+    $lang = isset($freetag_vocab->language) ? $freetag_vocab->language : 'und';
+    if (isset($node->{$ft_field}[$lang])) {
+      foreach ($node->{$ft_field}[$lang] as $tag) {
+        $tids[] = $tag['tid'];
+      }
+    }
+
+    if (is_array($typed_keywords) && !empty($typed_keywords)) {
+      $query = new EntityFieldQuery();
+      $query
+      ->entityCondition('entity_type', 'taxonomy_term')
+      ->propertyCondition('vid', $vid)
+      ->propertyCondition('name', $typed_keywords);
+
+      $result = $query->execute();
+
+      if (isset($result['taxonomy_term'])) {
+        $existing_tids  = array_keys($result['taxonomy_term']);
+        $existing_terms = taxonomy_term_load_multiple($existing_tids);
+        $existing_words = array();
+        foreach ($existing_terms as $term) {
+          $existing_words[$term->name] = $term;
+        }
+      }
+    }
+
+    foreach ($typed_keywords as $kw) {
+      if (isset($existing_words[$kw])) {
+        $term = $existing_words[$kw];
+      }
+      else {
+        $term = new stdClass();
+        $term->vid = $freetag_vocab->vid;
+        $term->name  = $kw;
+        $term->vocabulary_machine_name = $freetag_vocab->machine_name;
+        taxonomy_term_save($term);
+      }
+      if (!in_array($term->tid, $tids)) {
+        $node->{$ft_field}[$lang][] = (array)$term;
+      }
+    }
+  }
+
+  return array_keys($inserted);
+}
+/**
+ * @param $word
+ * @return
+ */
+function biblio_save_keyword(&$keyword) {
+  if (!empty($keyword['kid']) && $keyword['word']) {
+    drupal_write_record('biblio_keyword_data', $keyword, 'kid');
+    $status = SAVED_UPDATED;
+  }
+  else {
+    drupal_write_record('biblio_keyword_data', $keyword);
+    $status = SAVED_NEW;
+  }
+
+  return $status;
+}
+
+/**
+ * @return multitype:
+ */
+function biblio_get_orphaned_keyword_ids() {
+  $orphans = $active_kids = $all_kids = array();
+
+  $query = db_select('biblio_keyword', 'bk');
+  $active_kids = $query
+    ->fields('bk', array('kid'))
+    ->groupBy('kid')
+    ->execute()
+    ->fetchCol();
+
+  $query = db_select('biblio_keyword_data', 'bkd');
+  $all_kids = $query
+    ->fields('bkd', array('kid'))
+    ->execute()
+    ->fetchCol();
+
+  $orphans = array_diff($all_kids, $active_kids);
+
+  return $orphans;
+}
+
+/**
+ * Deletes orphaned keywords
+ *
+ * Deletion only occurs if the Drupal Variable "biblio_keyword_orphan_autoclean"
+ * is true OR if the $force argument is TRUE
+ *
+ * @param  bool $force
+ *   Forces deletion to occur even if autoclean is turned off
+ * @return int $count
+ *   The number of orphans removed
+ */
+function biblio_delete_orphan_keywords($force = FALSE) {
+  $count = 0;
+
+  if (variable_get('biblio_keyword_orphan_autoclean', 0) || $force) {
+    $orphans = biblio_get_orphaned_keyword_ids();
+    if (!empty($orphans)) {
+      $count = db_delete('biblio_keyword_data')
+        ->condition('kid', $orphans, 'IN')
+        ->execute();
+    }
+  }
+  return $count;
+}
+
+/**
+ * Delete all keywords references for a given node.
+ *
+ * The actual keywords remain in the biblio_keyword_data table
+ *
+ * @param $node
+ * @return
+ *   The number of links removed
+ */
+function biblio_delete_keywords($node) {
+  $count = db_delete('biblio_keyword')
+            ->condition('nid', $node->nid)
+            ->execute();
+  return $count;
+}
+
+/**
+ * Delete "node revision to keyword" links from the biblio_keyword table
+ *
+ * @param $node
+ * @return
+ *   The number of links removed
+ */
+function biblio_delete_revision_keywords($node) {
+  return db_delete('biblio_keyword')
+            ->condition('vid', $node->vid)
+            ->execute();
+}
+
+/**
+ * Delete multiple keywords.
+ *
+ * Removes from both the biblio_keyword and biblio_keyword_data tables
+ * This will remove the keywords referenced by the supplied ID's from
+ * ALL nodes which reference them.
+ *
+ * @param array $keywords
+ *   An array of keyword id's to delete
+ * @return
+ *   The number of keywords deleted
+ */
+function biblio_delete_multiple_keywords($keywords) {
+  $count = 0;
+  foreach ($keywords as $kid) {
+    $count += biblio_delete_keyword($kid);
+  }
+  return $count;
+}
+/**
+ * Delete a keyword from both the biblio_keyword and biblio_keyword_data tables
+ * This will remove the keyword referenced by the supplied ID from ALL nodes which reference them.
+ *
+ * @param $keyword_id
+ *   The keyword id to delete
+ * @return
+ *   The number of keywords deleted (should always be one)
+ */
+function biblio_delete_keyword($keyword_id) {
+  db_delete('biblio_keyword')
+      ->condition('kid', $keyword_id)
+      ->execute();
+
+  return db_delete('biblio_keyword_data')
+            ->condition('kid', $keyword_id)
+            ->execute();
+}
+
+/**
+ * @param unknown_type $string
+ * @return multitype:string
+ */
+function biblio_explode_keywords($string) {
+  $sep = variable_get('biblio_keyword_sep', ',');
+  $regexp = '%(?:^|' . $sep . '\ *)("(?>[^"]*)(?>""[^"]* )*"|(?: [^"' . $sep . ']*))%x';
+  preg_match_all($regexp, $string, $matches);
+  $keyword_array = array_unique($matches[1]);
+
+  $keywords = array();
+  foreach ($keyword_array as $keyword) {
+    // If a user has escaped a term (to demonstrate that it is a group,
+    // or includes a comma or quote character), we remove the escape
+    // formatting so to save the term into the database as the user intends.
+    $keyword = trim(str_replace('""', '"', preg_replace('/^"(.*)"$/', '\1', $keyword)));
+    if ($keyword != "") {
+      $keywords[] = $keyword;
+    }
+  }
+  return $keywords;
+}
+/**
+ * @param unknown_type $keywords
+ * @param unknown_type $sep
+ * @return Ambigous <string, unknown>
+ */
+function biblio_implode_keywords($keywords, $sep = '') {
+
+  if (empty($sep)) $sep = variable_get('biblio_keyword_sep', ',');
+  $string = '';
+  foreach ($keywords as $kid => $keyword) {
+    $string .= strlen($string)?"$sep ":'';
+    if (strpos($keyword, $sep) !== FALSE) {
+      $string .= '"' . $keyword . '"';
+    }
+    else {
+      $string .= $keyword;
+    }
+  }
+  return $string;
+}
+
+function biblio_get_term_ref_fields() {
+  $termfields = array();
+  foreach (field_info_instances('node', 'biblio') as $instance) {
+    $field = field_info_field_by_id($instance['field_id']);
+    if ($field['type'] == 'taxonomy_term_reference') {
+      $termfields[$field['field_name']] = $instance['label'];
+    }
+  }
+  return $termfields;
+}
+
+function biblio_create_term_ref($vocabulary) {
+  $field_name = 'field_' . $vocabulary->machine_name . '_ref';
+
+  $field = array(
+      'field_name' => $field_name,
+      'type' => 'taxonomy_term_reference',
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+      'settings' => array(
+          'allowed_values' => array(
+              array(
+                  'vocabulary' => $vocabulary->machine_name,
+                  'parent' => 0
+              ),
+          ),
+      ),
+  );
+
+  field_create_field($field);
+
+
+  $instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'node',
+      'label' => $vocabulary->name,
+      'bundle' => 'biblio',
+      'required' => FALSE,
+      'widget' => array(
+          'type' => 'options_select',
+          'cardinality' => -1
+      ),
+      'display' => array(
+          'default' => array('type' => 'hidden'),
+          'teaser' => array('type' => 'hidden')
+      )
+  );
+
+  field_create_instance($instance);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.pages.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1342 @@
+<?php
+/**
+ *
+ *   Copyright (C) 2006-2011  Ron Jerome
+ *
+ */
+
+
+function biblio_view_node($nid) {
+  $options = array();
+  drupal_goto('node/' . (int)$nid, $options, 301); // set a 301 response code
+}
+
+function biblio_arg_handler($arg_info) {
+  $arg_list = array();
+  if (count($arg_info['func_args']) == 1 && is_array($arg_info['func_args'][0])) {
+    return $arg_info['func_args'][0];
+  }
+
+  while ($arg_info['func_args']) {
+    $arg   = array_shift($arg_info['func_args']);
+    $value = array_shift($arg_info['func_args']);
+    if ($arg == 'sort') {
+      $arg_list['s'] = $value;
+    }
+    elseif ($arg == 'order') {
+      $arg_list['o'] = (strtolower($value) == 'desc') ? 'desc' : 'asc';
+    }
+    else {
+      $arg_list['f'][$arg] = $value;
+    }
+  }
+  $arg_list = array_merge_recursive($arg_list, $arg_info['uri']['query']);
+  return $arg_list;
+}
+
+function biblio_profile_page($user) {
+  $arg_list = array();
+  if (isset($user->data['biblio_contributor_id']) && $user->data['biblio_contributor_id'] > 0 ) {
+    $arg_list = array(
+      'f' => array(
+        'author' => $user->data['biblio_contributor_id'],
+      ),
+    );
+  }
+  elseif (isset($user->data['biblio_lastname']) && !empty($user->data['biblio_lastname'])) {
+    $arg_list = array(
+      'f' => array(
+        'author' => $user->data['biblio_lastname'],
+      ),
+    );
+  }
+  else {
+    $arg_list = array(
+      'f' => array(
+        'uid' => $user->uid
+      ),
+    );
+  }
+  $arg_list['page_limit'] = variable_get('biblio_rowsperpage', 25);
+
+  list($nids, $extras, $rss_info) = biblio_build_query($arg_list);
+
+  $render['biblio_page']['profile'] = biblio_page_content($nids, $extras);
+
+  return $render;
+}
+
+function biblio_page() {
+  $nodes = $nids = $extras = $rss_info = $info = $arg_list = $render = array();
+  $base = variable_get('biblio_base', 'biblio');
+
+  $info['func_args'] = func_get_args();
+  $info['uri']  = drupal_parse_url(request_uri());
+  $arg_list = biblio_arg_handler($info);
+  $arg_list['page_limit'] = variable_get('biblio_rowsperpage', 25);
+
+  list($nids, $extras, $rss_info) = biblio_build_query($arg_list);
+  if ($rss_info['feed']) {
+    biblio_filter_feed($rss_info, $nids);
+    return;
+  }
+
+  if (variable_get('biblio_rss', 0)) {
+    drupal_add_html_head_link(array(
+        'rel' => 'alternate',
+        'type' => 'application/rss+xml',
+        'title' => variable_get('site_name', 'Drupal') . ' RSS',
+        'href' => url("$base/rss.xml")
+    ));
+  }
+
+  drupal_set_title(t(check_plain(variable_get('biblio_base_title', 'Biblio'))));
+  $filter = (isset($arg_list['f'])) ? array('f' => $arg_list['f']) : array();
+
+  $render['biblio_page']['header']  = biblio_page_header($filter);
+  $render['biblio_page']['content'] = biblio_page_content($nids, $extras);
+
+  // if no content AND we have a filter give a hint on what to do...
+  if (isset($render['biblio_page']['content']['section_0']) && !empty($render['biblio_page']['header']['filter_status'])) {
+    $render['biblio_page']['content']['hint']['#markup'] = t('!modify_link or !remove_link your filters and try again.', array('!modify_link' => l(t('Modify'), "$base/filter"), '!remove_link' => l(t('remove'), "$base/filter/clear")));
+  }
+
+  return $render;
+}
+function biblio_page_header($filter = array()) {
+  $header = array();
+  $header = array(
+      '#prefix' => '<div id="biblio-header" class="clear-block">',
+      '#suffix' => '</div>',
+      '#weight' => -100,
+  );
+
+  // Search box. Has same permissions as the filter tab.
+  if (variable_get('biblio_search', 0) && user_access('show filter tab')) {
+    $header += array(
+      'search_form' => drupal_get_form('biblio_search_form'),
+    );
+  }
+  $header += array(
+    'export_links' => array(
+      '#prefix' => '<div class="biblio-export">',
+      '#node'    => NULL,
+      '#filter' => $filter,
+      '#theme'  => 'biblio_export_links',
+      '#suffix' => '</div>',
+    ),
+  );
+
+  if ( !biblio_access('export')) {
+    global $pager_total_items;
+    $header['export_links']['#markup'] = t('Found @count results', array('@count' => $pager_total_items[0]));
+    unset($header['export_links']['#theme']);
+  }
+  // Add some links to the top of the page to change the sorting/ordering...
+  if (user_access('show sort links')) {
+    $header += array(
+      'sort_links' => array(
+        '#markup' => theme('biblio_sort_tabs')
+      ),
+    );
+  }
+  $header += array(
+    'filter_status' => array(
+      '#prefix' => '<div class="biblio-filter-status">',
+      '#suffix' => '</div>',
+      '#markup' => _biblio_filter_info_line($filter),
+    ),
+  );
+  if (isset($_GET['s'])) {
+    if ( $_GET['s'] == 'title' ||
+    $_GET['s'] == 'author' ||
+    $_GET['s'] == 'keyword') {
+      if (strpos($_GET['q'], 'ag') ||
+      strpos($_GET['q'], 'tg') ||
+      strpos($_GET['q'], 'keyword')) {
+        $value = substr($_GET['q'], strrpos($_GET['q'], '/') + 1);
+      }
+      else {
+        $value = '';
+      }
+      $header += array(
+        'alpha_line' => array(
+          '#prefix' => '<div class="biblio-alpha-line">',
+          '#suffix' => '</div>',
+          '#markup' => theme('biblio_alpha_line', array(
+          'type' => $_GET['s'],
+          'current' => $value,
+          'path' => variable_get('biblio_base', 'biblio'))
+          ),
+        ),
+      );
+    }
+  }
+
+  return $header;
+}
+
+function biblio_page_content($nids = array(), $extras = array()) {
+  $base =  variable_get('biblio_base', 'biblio');
+  $content = $raw_nodes = $nodes = array();
+  $count = $section_id = 0;
+
+  if (module_exists('popups')) {
+     popups_add_popups();
+  }
+
+  if (count($nids)) {
+  //  $nids = array_unique($nids);
+    $raw_nodes = node_load_multiple($nids);
+    $langcode = $GLOBALS['language_content']->language;
+    field_attach_prepare_view('node', $raw_nodes, 'biblio_list', $langcode);
+    entity_prepare_view('node', $raw_nodes, $langcode);
+
+    foreach ($nids as $key => $nid) {
+      if (!empty($extras)) {
+        $nodes[] = (object)array_merge((array)$raw_nodes[$nid], (array)$extras[$key]);
+      }
+      else {
+        $nodes[] = $raw_nodes[$nid];
+      }
+    }
+
+  }
+
+  foreach ($nodes as $node) {
+    $count++;
+    if (is_array($node)) $node = (object)$node;
+    if (variable_get('biblio_hide_bibtex_braces', 0)) $node->title = biblio_remove_brace($node->title);
+
+    // output new section if needed
+    if ($section = biblio_category_section($node)) {
+      $section_id++;
+      $content['section_'.$section_id] = $section;
+    }
+
+     $content['section_'.$section_id][] = biblio_entry($node);
+
+  }
+
+  $content['pager']['#markup'] = theme('pager');
+  if ($count == 0) {
+    $content['section_0']['#markup'] = "<h3>" . t("No items found") . "</h3>";
+  }
+  return $content;
+}
+
+function biblio_entry($node) {
+  $entry = array();
+  $style = biblio_get_style();
+
+  /*
+  $select_box = array(
+    '#type' => 'checkbox',
+    '#return_value'  => $node->nid,
+    '#default_value' => 0,
+    '#attributes' => array('class' => array('biblio-export-selector'),)
+
+  );
+*/
+  $prefix = '<div class="biblio-entry">';
+  $suffix = '</div>';
+  if (!$node->status) {
+    $prefix .= '<div id="node-' . $node->nid . '" class="node node-unpublished">';
+    $suffix .= '</div>';
+  }
+//  $prefix .= theme('checkbox', array('element' => $select_box));
+
+  $entry  = array(
+    '#prefix' => $prefix,
+    '#suffix' => $suffix,
+  );
+
+  $entry['entry']['#markup'] =  theme('biblio_style', array('node' => $node, 'style_name' => $style));
+
+  $annotation_field = variable_get('biblio_annotations', 'none');
+  if ($annotation_field != 'none' && $node-> $annotation_field) {
+    $entry['annotation'] = array(
+     '#prefix' => '<div class="biblio-annotation">',
+     '#markup' => filter_xss($node->$annotation_field, biblio_get_allowed_tags()),
+     '#suffix' => '</div>',
+    );
+  }
+
+  $openurl_base = variable_get('biblio_baseopenurl', '');
+
+  if ($openurl_base) {
+    $entry['openurl'] = array(
+      '#markup' => theme('biblio_openurl', array('openURL' => biblio_openurl($node))),
+    );
+  }
+
+  if (biblio_access('export')) {
+    $base = variable_get('biblio_base', 'biblio');
+    $entry['export_links'] = array(
+      '#markup' => theme('biblio_export_links', array('node' => $node)),
+    );
+  }
+
+  if (biblio_access('download', $node)) {
+    // add links to attached files (if any)
+    $entry['download_links'] = array(
+      '#markup' => theme('biblio_download_links', array('node' => $node)),
+    );
+  }
+
+  return $entry;
+}
+
+/*
+ * biblio_db_search builds the SQL query which will be used to
+ * select and order "biblio" type nodes.  The query results are
+ * then passed to biblio_show_results for output
+ *
+ *
+ */
+function biblio_build_query($arg_list) {
+  global $user;
+  static $bcc = 0; //biblio_contributor (bc) count , increase for every invocation
+  static $bkd = 0;
+  static $tcc = 0; //term counter, increase for every invocation
+  $rss_info['feed'] = FALSE;
+  $rss_info['title'] = variable_get('biblio_base_title', 'Biblio');
+  $rss_info['link'] = '';
+  $rss_info['description'] = '';
+
+  if ($arg_list['page_limit'] > 0) {
+    $query = db_select('node', 'n')->extend('PagerDefault');
+    $query->limit($arg_list['page_limit']);
+  }
+  else {
+    $query = db_select('node', 'n');
+  }
+
+  //add a tag of "node_access" to ensure that only nodes to which the user has access are retrieved
+  $query->addTag('node_access');
+
+  $query->addField('n', 'nid');
+  $type_name = $query->addField('bt', 'name', 'biblio_type_name');
+  $query->leftJoin('biblio', 'b', 'n.vid=b.vid');
+  $query->innerJoin('biblio_types', 'bt', 'b.biblio_type=bt.tid');
+//  $query->distinct();
+
+  // POSIX regular expression matching, case insensitive
+  $match_op = (db_driver() == 'pgsql') ? '~*' : 'RLIKE';
+
+  $limit = '';
+  if (variable_get('biblio_view_only_own', 0) ) {
+    $limit .= " AND n.uid = $user->uid ";
+  }
+
+  if (isset($arg_list['s']) || isset($arg_list['sort'])) {
+    $sort = isset($arg_list['s']) ? $arg_list['s'] : $arg_list['sort'];
+    unset($arg_list['s']);
+    unset($arg_list['sort']);
+  }
+  else {
+    $sort = variable_get('biblio_sort', 'year');
+  }
+
+  if (isset($arg_list['o']) || isset($arg_list['order'])) {
+    if (isset($arg_list['o'])) {
+      $order = (strcasecmp($arg_list['o'], 'ASC')) ? 'DESC' : 'ASC';
+      unset($arg_list['o']);
+    }
+    if (isset($arg_list['order'])) {
+      $order = (strcasecmp($arg_list['order'], 'ASC')) ? 'DESC' : 'ASC';
+      unset($arg_list['order']);
+    }
+  }
+  else {
+      $order = strtolower(variable_get('biblio_order', 'DESC'));
+  }
+
+/*  if (!isset($_SESSION['biblio_filter']) || !is_array($_SESSION['biblio_filter'])) {
+    $_SESSION['biblio_filter'] = array();
+  }
+
+  $session = &$_SESSION['biblio_filter'];
+
+  if (!in_array('no_filters', $arg_list)) {
+    foreach ($session as $filter) {
+      $arg_list = array_merge($arg_list, $filter);
+    }
+  }
+*/
+
+
+  switch ($sort) {
+    case 'type':
+      //$sortby = "ORDER BY bt.name %s, b.biblio_year DESC ";
+      $query->addField('n', 'title');
+      $query->orderBy($type_name, $order);
+      $query->orderBy('biblio_sort_title', $order);
+      break;
+    case 'title':
+      $query->addField('n', 'title');
+      $query->orderBy('biblio_sort_title', $order);
+      break;
+    case 'author':
+      //$last_name = $query->addField('bcd', 'lastname');
+      $query->innerJoin('biblio_contributor', 'bc', 'b.vid = bc.vid');
+      $query->join('biblio_contributor_data', 'bcd', 'bc.cid = bcd.cid');
+      $query->condition('bc.rank', 0);
+      $query->addField('bcd', 'lastname');
+      $query->orderBy('bcd.lastname', $order);
+      // $query->condition('bc.auth_category', 1);
+      break;
+    case 'keyword': // added msh 070808
+      $word = $query->addField('bkd', 'word', 'biblio_keyword');
+      $query->orderBy($word, $order);
+      $query->innerJoin('biblio_keyword', 'bk', 'b.vid = bk.vid');
+      $query->innerJoin('biblio_keyword_data', 'bkd', 'bk.kid = bkd.kid');
+      break;
+    case 'year':
+    default:
+      $query->addField('b', 'biblio_year');
+      $query->addField('b', 'biblio_date');
+      $query->orderBy('biblio_year', $order);
+      $query->orderBy('biblio_sort_title');
+  } //end switch
+
+
+  if (isset($arg_list['f']) && count($arg_list['f']) ) {
+    $fields = biblio_get_db_fields();
+    foreach ($arg_list['f'] as $type => $value) {
+      $tables = array_keys($query->getTables());
+      switch ($type) {
+        case 'no_filters':
+          break;
+        case 'rss.xml':
+          $rss_info['feed'] = TRUE;
+          $query->limit(variable_get('biblio_rss_number_of_entries', 10));
+          break;
+        case 'term':
+        case 'term_id':
+          $query->innerJoin('taxonomy_index', "ti$tcc", "n.nid = ti$tcc.nid");
+          if ($type == 'term') {
+            $query->innerJoin('taxonomy_term_data', 'td', "ti$tcc.tid = td.tid");
+            $query->condition('td.name', $value);
+          }
+          elseif ($type == 'term_id') {
+            $query->condition("ti$tcc.tid", $value);
+          }
+          $tcc++;
+          break;
+        case 'tg':
+          $query->where("UPPER(substring(biblio_sort_title,1 ,1)) = :letter", array(':letter' => $value));
+          break;
+        case 'ag': //selects entries whoose authors firstname starts with the letter provided
+          $query->where(" UPPER(substring(bcd.lastname,1,1)) = :letter ", array(':letter' => $value));
+          //$where['bc-rank'] = "bc.rank=0";
+          if ($sort != 'author') {
+            $query->innerJoin('biblio_contributor', 'bc', 'b.vid = bc.vid');
+            $query->innerJoin('biblio_contributor_data', 'bcd', 'bc.cid = bcd.cid');
+          }
+          break;
+        case 'cid':
+        case 'aid':
+          $bcc++;
+          $query->innerJoin('biblio_contributor', "bc$bcc", "n.vid = bc$bcc.vid");
+          $query->condition("bc$bcc.cid", $value);
+          break;
+        case 'author':
+          module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+          $bcc++;
+          if (array_search('bc', $tables) === FALSE) {
+            $query->innerJoin('biblio_contributor', 'bc', 'n.vid = bc.vid');
+          }
+          if (is_numeric($value)) {
+            $cids = biblio_get_linked_contributors($value);
+            $cids[] = $value;
+            $cid_count = 0;
+            $or = db_or();
+
+            foreach ($cids as $cid) {
+              $or->condition("bc.cid", $cid);
+              $cid_count++;
+            }
+
+            if ($cid_count == 0) {
+              $query->condition("bc.cid", -1);
+            }
+            else {
+              $query->condition($or);
+            }
+
+          }
+          else {
+            if (array_search('bcd', $tables) === FALSE) {
+              $query->innerJoin('biblio_contributor_data', 'bcd', 'bcd.cid = bc.cid');
+            }
+            $query->condition('bcd.name', "[[:<:]]" . $value . "[[:>:]]", $match_op);
+            $rss_info['title'] = t("Publications by @value", array('@value' => $value));
+            $rss_info['description'] = t("These publications by %author are part of the works listed at %sitename", array('%author' => $value, '%sitename' => variable_get('site_name', 'Drupal')));
+            $rss_info['link'] = '/author/' . $value;
+          }
+          break;
+        case 'publisher':
+          $query->condition('b.biblio_publisher', "[[:<:]]" . $value . "[[:>:]]", $match_op);
+          break;
+        case 'year':
+          $query->condition('b.biblio_year', $value);
+          break;
+        case 'uid':
+          $query->addField('n', 'uid');
+          $query->condition('n.uid', $value);
+          break;
+        case 'keyword':
+          $bkd++;
+          if (array_search('bk', $tables) === FALSE) {
+            $query->innerJoin('biblio_keyword', 'bk', 'n.vid = bk.vid');
+          }
+          if (is_numeric($value)) {
+            $query->condition('bk.kid', $value);
+          }
+          else{
+            if (array_search('bkd', $tables) === FALSE) {
+              $query->innerJoin('biblio_keyword_data', 'bkd', 'bkd.kid = bk.kid');
+            }
+            if (strlen($value) == 1) {
+             // $query->condition('',  $value, 'SUBSTR(bkd.word, 1, 1) =');
+              $query->where(" UPPER(substring(bkd.word,1,1)) = :letter ", array(':letter' => $value));
+            }
+            else {
+              $query->condition('bkd.word', "[[:<:]]" . $value . "[:>:]]", 'LIKE');
+            }
+            $rss_info['title'] = t("Keyword @value", array('@value' => $value));
+            $rss_info['description'] = t("These publications, containing the keyword: %keyword, are part of the works listed at %sitename", array('%keyword' => $value, '%sitename' => variable_get('site_name', 'Drupal')));
+            $rss_info['link'] = '/keyword/' . $value;
+          }
+          break;
+        case 'citekey':
+          $query->condition('b.biblio_citekey', $value);
+          break;
+        case 'type':
+          $query->condition('b.biblio_type', $value);
+          break;
+        case 'search':
+          $search_nids = array();
+          $search_nids =  biblio_search_query($value);
+          if (empty($search_nids)) {
+            $search_nids[] = -1;  // if we didn't find anything, then add one value of -1 since there will never be a node id == -1
+          }
+          $query->condition('n.nid', $search_nids, 'IN');
+          break;
+        default:
+          if (in_array("biblio_$type", $fields)) {
+            $query->condition("b.biblio_$type ", $value, 'LIKE');
+          }
+          break;
+      }
+    }
+  }
+
+  // show unpublished nodes to users with uid = 1 or  with 'Administer Biblio' permissions
+  if ($user->uid != 1 && !biblio_access('admin')) {
+    $query->condition('n.status', 1);
+  }
+
+  $result = $query->execute();
+  $nids = array();
+  $extras = array();
+
+  foreach ($result as $node) {
+    $nids[] = $node->nid;
+    if (isset($node->biblio_year)) unset($node->biblio_year);
+    $extras[] = $node;
+  }
+
+  return array($nids, $extras, $rss_info);
+
+}
+
+function _biblio_filter_info_line($args = array()) {
+  $content = '';
+  $filtercontent = '';
+  $search_content = '';
+  $base =  variable_get('biblio_base', 'biblio');
+  $session = &$_SESSION['biblio_filter'];
+  // if there are any filters in place, print them at the top of the list
+  $uri = drupal_parse_url(request_uri());
+  $uri['path'] = variable_get('biblio_base', 'biblio');
+  $filters = isset($uri['query']['f']) ? $uri['query']['f'] : (isset($args['f'])? $args['f']: array());
+  if (count($filters)) {
+    $i = 0;
+    foreach ($filters as $type => $value) {
+      if ($type == 'search') {
+        $search_content = $value;
+        continue;
+      }
+      if ($type == 'term_id') {
+        $term = taxonomy_term_load($value);
+        $value = $term->name;
+        $type = t("Taxonomy term");
+      }
+      if ($type == 'keyword') {
+        module_load_include('inc', 'biblio', 'includes/biblio.keywords');
+        $type = t("Keyword");
+        if (is_numeric($value)) {
+          $term = biblio_get_keyword_by_id($value);
+          if (isset($term->word)) {
+            $value = $term->word;
+          }
+        }
+        elseif (is_string($value) && strlen($value) == 1) {
+          $type = t("First letter of keyword");
+        }
+      }
+      if ($type == 'uid' ) {
+        $user = user_load($value);
+        $value = $user->name;
+        $type = t("Drupal user");
+      }
+      if ($type == 'aid' || ($type == 'author' && is_numeric($value))) {
+        module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+        $author = biblio_get_contributor($value);
+        $value = isset($author->name) ? $author->name : t('Unknown Author');
+        $type = t("Author");
+      }
+      if ($type == 'ag' ) {
+        //return;
+        $type = t("First letter of last name");
+      }
+      if ($type == 'tg' ) {
+        //return;
+        $type = t("First letter of title");
+      }
+      if ($type == 'type' && $value > 0) {
+        if (($pub_type = db_query('SELECT t.* FROM {biblio_types} as t WHERE t.tid=:tid', array(':tid' => $value))->fetchObject())) {
+          $value = drupal_ucfirst(_biblio_localize_type($pub_type->tid, $pub_type->name));
+          $type = t("Type");
+        }
+      }
+      $params = array('%a' =>  check_plain(ucwords($type)) , '%b' =>  check_plain($value) );
+      $filtercontent .= ($i++ ? t('<em> and</em> <strong>%a</strong> is <strong>%b</strong>', $params) : t('<strong>%a</strong> is <strong>%b</strong>', $params)) ;
+    }
+    if ($search_content) {
+      $content .= '<div class="biblio-current-filters"><b>' . t('Search results for') . '</b>';
+      $content .= '<em> ' . check_plain($search_content) . '</em>';
+      if ($filtercontent) {
+        $content .= '<br><b>' . t('Filters') . ': </b>';
+      }
+    }
+    else {
+      $content .= '<div class="biblio-current-filters"><b>' . t('Filters') . ': </b>';
+    }
+    $content .= $filtercontent;
+
+    $link_options = array();
+    if (isset($_GET['s'])) {
+      $link_options['query']['s'] = $_GET['s'];
+    }
+    if (isset($_GET['o'])) {
+      $link_options['query']['o'] = $_GET['o'];
+    }
+    unset($uri['query']['f']);
+    if ($search_content) {
+      $content .= '&nbsp;&nbsp;' . l('[' . t('Reset Search') . ']', "$base/filter/clear", $link_options);
+    }
+    else {
+      $content .= '&nbsp;&nbsp;' . l('[' . t('Clear All Filters') . ']', "$base/filter/clear", $uri);
+    }
+    $content .= '</div>';
+  }
+
+  return $content;
+}
+
+function _biblio_category_separator_bar($node, $reset = FALSE) {
+  $_text = &drupal_static(__FUNCTION__, '');
+  if ($reset) {
+    $_text = &drupal_static(__FUNCTION__, '', TRUE);
+    return;
+  }
+  $content = '';
+
+  if (isset($_GET['s'])) {
+    $sort = $_GET['s'];
+  }
+  else {
+    $sort = variable_get('biblio_sort', 'year');
+  }
+
+  switch ($sort) {
+    case 'title':
+      $title = $node->biblio_sort_title;
+      $first = drupal_substr(drupal_ucfirst(ltrim($title)), 0, 1);
+      if ( $first  != $_text) {
+        if ($_text != '' ) {
+          $content .= theme_biblio_end_category_section();
+        }
+        $_text =  $first ;
+        $content .= theme_biblio_separator_bar($_text);
+      }
+      break;
+    case 'author':
+      if ( (isset($node->biblio_contributors[0]['lastname'])) &&
+      (drupal_substr(drupal_ucfirst(ltrim($node->biblio_contributors[0]['lastname'])), 0, 1) != $_text))
+      {
+        if ($_text != '' ) {
+          $content .= theme_biblio_end_category_section();
+        }
+        $_text = drupal_substr(drupal_ucfirst(ltrim($node->biblio_contributors[0]['lastname'])), 0, 1) ;
+        $content .= theme_biblio_separator_bar($_text);
+      }
+      break;
+    case 'type':
+      if ($node->biblio_type_name != $_text) {
+        if ($_text != '' ) {
+          $content .= theme_biblio_end_category_section();
+        }
+        $_text = $node->biblio_type_name;
+        //      $name = db_result(db_query("SELECT name FROM {biblio_types} as t where t.tid=%d", $node->biblio_type)) ;
+        $content .= theme_biblio_separator_bar(_biblio_localize_type($node->biblio_type, $_text));
+      }
+      break;
+    case 'keyword':   // added msh 08 aug 07
+      // $kw = array_shift($node->biblio_keyword);
+      $tok = $node->biblio_keyword;
+      if (empty($tok)) {
+        $tok = t("No Keywords");
+      }
+      if ($tok != $_text) {
+        if ($_text != '' ) {
+          $content .= theme_biblio_end_category_section();
+        }
+        $_text = $tok;
+        if ($_text != '') {
+          $content .= theme_biblio_separator_bar($_text);
+        }
+      }
+      break;
+    case 'year':
+    default:
+      if ($node->biblio_year != $_text) {
+        if ($_text != '' ) {
+          $content .= theme_biblio_end_category_section();
+        }
+        $_text = $node->biblio_year;
+        $content .= theme_biblio_separator_bar($_text);
+      }
+  } //end switch
+  return $content;
+}
+function biblio_category_section($node, $reset = FALSE) {
+  $_text = &drupal_static(__FUNCTION__, '');
+  if ($reset) {
+    $_text = &drupal_static(__FUNCTION__, '', TRUE);
+    return;
+  }
+
+  $section = array();
+
+  if (isset($_GET['s'])) {
+    $sort = $_GET['s'];
+  }
+  else {
+    $sort = variable_get('biblio_sort', 'year');
+  }
+
+  switch ($sort) {
+    case 'title':
+      $title = $node->biblio_sort_title;
+      $first = drupal_substr(drupal_ucfirst(ltrim($title)), 0, 1);
+      if ( $first  != $_text) {
+        $_text =  $first ;
+        $section['bar'] = biblio_section_bar($_text);
+      }
+      break;
+    case 'author':
+      if ( (isset($node->biblio_contributors[0]['lastname'])) &&
+      (drupal_substr(drupal_ucfirst(ltrim($node->biblio_contributors[0]['lastname'])), 0, 1) != $_text))
+      {
+        $_text = drupal_substr(drupal_ucfirst(ltrim($node->biblio_contributors[0]['lastname'])), 0, 1) ;
+        $section['bar'] = biblio_section_bar($_text);
+      }
+      break;
+    case 'type':
+      if ($node->biblio_type_name != $_text) {
+        $_text = $node->biblio_type_name;
+        //      $name = db_result(db_query("SELECT name FROM {biblio_types} as t where t.tid=%d", $node->biblio_type)) ;
+        $section['bar'] = biblio_section_bar(_biblio_localize_type($node->biblio_type, $_text));
+      }
+      break;
+    case 'keyword':   // added msh 08 aug 07
+      // $kw = array_shift($node->biblio_keyword);
+      $tok = $node->biblio_keyword;
+      if (empty($tok)) {
+        $tok = t("No Keywords");
+      }
+      if ($tok != $_text) {
+        $_text = $tok;
+        if ($_text != '') {
+          $section['bar'] = biblio_section_bar($_text);
+        }
+      }
+      break;
+    case 'year':
+    default:
+      if ($node->biblio_year != $_text) {
+        $_text = $node->biblio_year;
+        $section['bar'] = biblio_section_bar($_text);
+      }
+  } //end switch
+  if (!empty($section)) {
+    $section += array(
+      '#prefix' => '<div class="biblio-category-section">',
+      '#suffix' => '</div>',
+    );
+  }
+  return $section;
+}
+
+function biblio_section_bar($text) {
+  return array(
+    '#prefix' => '<div class="biblio-separator-bar">',
+    '#suffix' => '</div>',
+    '#markup' => check_plain($text),
+  );
+}
+
+/**
+ * Add a search field on the main biblio page.
+ */
+/**
+ * @param $form_state
+ * @return unknown_type
+ */
+function biblio_search_form($form, &$form_state) {
+  $base = variable_get('biblio_base', 'biblio');
+  $searchform['biblio_search'] = array(
+    '#prefix' => '<div class="container-inline biblio-search clear-block">',
+    '#suffix' => '</div>',
+    );
+  $searchform['biblio_search']['keys'] = array(
+    '#type' => 'textfield',
+    '#title' => '',
+    '#default_value' => '',
+    '#size' => 25,
+    '#maxlength' => 255,
+  );
+  $button_text = variable_get('biblio_search_button_text', 'Biblio search');
+  $searchform['biblio_search']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t($button_text)
+  );
+
+  $form['search_form'] = array(
+        '#type'   => 'fieldset',
+        '#title'   => t('Search'),
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+        'searchform' => $searchform,
+        'filterform' => biblio_form_filter(),
+      );
+
+  return $form;
+}
+
+function biblio_search_form_submit($form, &$form_state) {
+  static $keys = '';
+  $base = variable_get('biblio_base', 'biblio');
+  $keys =  trim($form_state['values']['keys']);
+  if (!empty($keys)) {
+    $uri = drupal_parse_url(request_uri());
+    $uri['path'] = variable_get('biblio_base', 'biblio');
+    $uri['query']['f']['search'] = $keys;
+    $form_state['redirect'] = array($uri['path'], $uri);
+  }
+
+}
+
+function biblio_search_query($keys) {
+  if (!empty($keys)) {
+    $query = db_select('search_index', 'i', array('target' => 'slave'))
+      ->extend('SearchQuery');
+     // ->extend('PagerDefault');
+    $query->join('node', 'n', 'n.nid = i.sid');
+    $query->condition('n.status', 1)
+      ->addTag('node_access')
+      ->searchExpression($keys, 'node');
+
+    // Insert special keywords.
+    $query->setOption('type', 'n.type');
+    $query->setOption('language', 'n.language');
+    if ($query->setOption('term', 'ti.tid')) {
+      $query->join('taxonomy_index', 'ti', 'n.nid = ti.nid');
+    }
+    // Only continue if the first pass query matches.
+    if (!$query->executeFirstPass()) {
+      return array();
+    }
+
+    // Add the ranking expressions.
+    _node_rankings($query);
+
+    // Load results.
+    $find = $query->execute();
+
+    $nids = array();
+    foreach ($find as $item) {
+      $nids[] = $item->sid;
+    }
+    return $nids;
+  }
+}
+
+  /**
+ * @param $arg
+ * @return unknown_type
+ */
+function _get_biblio_search_filter($arg = 'keys') {
+  if (variable_get('biblio_search', 0) &&
+    !empty($_SESSION['biblio_filter']) &&
+    is_array($_SESSION['biblio_filter']) &&
+    is_array($_SESSION['biblio_filter'][0]) &&
+    in_array('search', $_SESSION['biblio_filter'][0])
+  ) {
+    switch ($arg) {
+      case 'keys': return $_SESSION['biblio_filter'][0][2]; break;
+      case 'nodelist': return $_SESSION['biblio_filter'][0][1]; break;
+    }
+  }
+}
+
+
+function _get_biblio_filters() {
+
+  $fields = " b.biblio_year, t.name , t.tid ";
+  $order = " b.biblio_year DESC";
+  $taxo_fields = "td.name as termname, td.tid as taxid, v.name as vocab_name";
+  $taxo_order = "vocab_name ASC, termname ASC";
+  $table = "{node} as n  inner join {biblio} as b on n.vid=b.vid ";
+  $join = "left join {biblio_types} as t on b.biblio_type = t.tid";
+  $taxo_join = array("inner join {taxonomy_index} as ti on n.nid = ti.nid",
+                     "left join  {taxonomy_term_data} as td on ti.tid = td.tid",
+                     "left join  {taxonomy_vocabulary} as v on v.vid = td.vid");
+
+  $taxo_joins = implode(' ', $taxo_join);
+
+  $result = db_query("SELECT $fields FROM $table $join ORDER BY $order");
+  $authors = db_query("SELECT DISTINCT firstname, initials, lastname, bcd.cid
+                       FROM {biblio_contributor_data} as bcd
+                       INNER JOIN {biblio_contributor} as bc on bc.cid = bcd.cid
+                       ORDER BY lastname ASC");
+  $keywords = db_query("SELECT word, kid FROM {biblio_keyword_data} ORDER BY word ASC");
+  $taxoresult = db_query("SELECT $taxo_fields FROM $table $taxo_joins ORDER BY $taxo_order");
+  $pub_years['any'] = t('any');
+  $pub_type['any']  = t('any');
+  $pub_authors['any']  = t('any');
+  $pub_keywords['any']  = t('any');
+  $pub_taxo['any']  = t('any');
+  foreach ($result as $option) {
+    if (isset ($option->biblio_year)) {
+      $option->biblio_year = _biblio_text_year($option->biblio_year);
+    }
+    $pub_years[$option->biblio_year] = $option->biblio_year;
+    $pub_type[$option->tid] = _biblio_localize_type($option->tid, $option->name);
+  }
+
+  foreach ($authors as $auth) {
+    $pub_authors[$auth->cid] = $auth->lastname . ((!empty($auth->firstname) || !empty($auth->initials))?', ' . $auth->firstname . ' ' . $auth->initials :'');
+  }
+  foreach ($keywords as $keyword) {
+    $pub_keywords[$keyword->kid] = $keyword->word;
+  }
+  foreach ($taxoresult as $tax) {
+    $pub_taxo["$tax->taxid"] = "$tax->vocab_name - $tax->termname";
+  }
+  $author_select = isset($pub_authors) ? array('title' => t('Author'), 'options' => $pub_authors) : NULL;
+  $years_select  = isset($pub_years) ? array('title' => t('Year'), 'options' => array_unique($pub_years)) : NULL;
+  $type_select   = isset($pub_type)  ? array('title' => t('Type'), 'options' => array_unique($pub_type))  : NULL;
+  $tax_select    = isset($pub_taxo)  ? array('title' => t('Term'), 'options' => array_unique($pub_taxo))  : NULL;
+  $keyword_select = isset($pub_keywords) ? array('title' => t('Keyword'), 'options' => $pub_keywords) : NULL;
+
+  $filters = array(
+    'author'    => $author_select,
+    'type'      => $type_select,
+    'term_id'   => $tax_select,
+    'year'      => $years_select,
+    'keyword'   => $keyword_select,
+  );
+
+  return $filters;
+}
+
+/**
+ * @return unknown_type
+ */
+function biblio_form_filter() {
+  $session = isset($_SESSION['biblio_filter']) ? $_SESSION['biblio_filter'] : array();
+  $filters = _get_biblio_filters();
+
+  $i = 0;
+  $form['filters'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Show only items where'),
+    '#theme' => 'exposed_filters__node',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+
+  foreach ($session as $filter) {
+    $type = key($filter);
+    $value = $filter[$type];
+   // list($type, $value) = $filter;
+    if ($type == 'search') {
+      $session = array();
+      break;
+    }
+    if ($type == 'category') {
+      // Load term name from DB rather than search and parse options array.
+      $value = module_invoke('taxonomy', 'get_term', $value);
+      $value = $value->name;
+    }
+    else {
+      $value = $filters[$type]['options'][$value];
+    }
+    $t_args = array('%property' => $filters[$type]['title'], '%value' => $value);
+    if ($i++) {
+      $form['filters']['current'][] = array('#markup' => t('and where %property is %value', $t_args));
+    }
+    else {
+      $form['filters']['current'][] = array('#markup' => t('where %property is %value', $t_args));
+    }
+    if (in_array($type, array('type', 'language'))) {
+      // Remove the option if it is already being filtered on.
+      unset($filters[$type]);
+    }
+  }
+
+  $form['filters']['status'] = array(
+    '#type' => 'container',
+    '#attributes' => array('class' => array('clearfix')),
+    '#prefix' => ($i ? '<div class="additional-filters">' . t('and where') . '</div>' : ''),
+  );
+  $form['filters']['status']['filters'] = array(
+    '#type' => 'container',
+    '#attributes' => array('class' => array('filters')),
+  );
+  foreach ($filters as $key => $filter) {
+    $form['filters']['status']['filters'][$key] = array(
+      '#type' => 'select',
+      '#options' => $filter['options'],
+      '#title' => $filter['title'],
+      '#default_value' => 'any',
+    );
+  }
+
+  $form['filters']['status']['actions'] = array(
+    '#type' => 'actions',
+    '#attributes' => array('class' => array('container-inline')),
+  );
+  $form['filters']['status']['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => count($session) ? t('Refine') : t('Filter'),
+    '#submit' => array('biblio_form_filter_submit'),
+  );
+  if (count($session)) {
+    $form['filters']['status']['actions']['undo'] = array(
+      '#type' => 'submit',
+      '#value' => t('Undo'),
+      '#submit' => array('biblio_form_filter_submit')
+    );
+    $form['filters']['status']['actions']['reset'] = array(
+      '#type' => 'submit',
+      '#value' => t('Reset'),
+      '#submit' => array('biblio_form_filter_submit')
+    );
+  }
+
+  return $form;
+}
+
+
+/**
+ * @param $form
+ * @param $form_state
+ * @return unknown_type
+ */
+function biblio_form_filter_submit($form, &$form_state) {
+  // If the search filter was set, remove it now.
+  if (_get_biblio_search_filter()) {
+    $_SESSION['biblio_filter'] = array();
+  }
+  $op = $form_state['values']['op'];
+  $filters = _get_biblio_filters();
+  switch ($op) {
+    case t('Filter'):
+    case t('Refine'):
+        $uri = drupal_parse_url(request_uri());
+        $uri['path'] = variable_get('biblio_base', 'biblio');
+      foreach ($filters as $filter => $options) {
+        if (isset($form_state['values'][$filter]) && $form_state['values'][$filter] != 'any') {
+          // Flatten the options array to accommodate hierarchical/nested options.
+          $flat_options = form_options_flatten($filters[$filter]['options']);
+          // Only accept valid selections offered on the dropdown, block bad input.
+          if (isset($flat_options[$form_state['values'][$filter]])) {
+            $_SESSION['biblio_filter'][] = array($filter => $form_state['values'][$filter]);
+            $uri['query']['f'][$filter] = $form_state['values'][$filter];
+          }
+        }
+      }
+      $form_state['redirect'] =  array($uri['path'], $uri);
+      break;
+    case t('Undo'):
+      array_pop($_SESSION['biblio_filter']);
+      break;
+    case t('Reset'):
+      $_SESSION['biblio_filter'] = array();
+      break;
+  }
+}
+
+
+/**
+ * @return unknown_type
+ */
+function biblio_citekey_view() {
+  $citekey = arg(2);
+  $nid = db_query("SELECT nid FROM {biblio} WHERE biblio_citekey = :citekey ORDER BY vid DESC", array(':citekey' => $citekey))->fetchObject();
+  if ($nid->nid > 0) {
+    $node = node_load($nid->nid);
+    return node_page_view($node);
+  }
+  else {
+    return t("Sorry, citekey @cite not found", array('@cite' => $citekey));
+  }
+
+}
+
+
+function biblio_author_page() {
+  $path = drupal_get_path('module', 'biblio');
+  drupal_add_js($path . '/misc/biblio.highlight.js', 'file');
+
+  $uri = drupal_parse_url(request_uri());
+  $filter = isset($uri['query']['f']['author']) ? $uri['query']['f']['author'] : '';
+  $authors = _biblio_get_authors($filter);
+
+  return _biblio_format_author_page($uri['path'], $filter, $authors);
+}
+
+function _biblio_get_authors($filter = NULL) {
+  global $user;
+  $where = array();
+  $authors = array();
+  $where_clause = '';
+  $output = '';
+
+  if ($filter) {
+    $filter = strtoupper($filter);
+    $where['filter'] =  "UPPER(SUBSTRING(lastname,1,1)) = :filter ";
+    $header_ext = t(' (whose last name starts with the letter "@letter") ', array('@letter' => $filter ));
+  }
+  else {
+    $query_ext =  NULL;
+    $header_ext = NULL;
+  }
+
+  if (!biblio_access('edit_author')) {
+    $where['access'] = 'n.status = 1 ';
+  }//show only published entries to everyone except admin
+
+  if (count($where)) {
+    $where_clause =  'WHERE (' . implode(') AND (', $where) . ')';
+  }
+
+  $suspects = array();
+  $query = db_select('biblio_contributor_data', 'bcd')
+              ->fields('bcd', array('lastname', 'firstname', 'initials', 'alt_form'))
+              ->groupBy('lastname')
+              ->groupBy('firstname')
+              ->groupBy('initials')
+              ->groupBy('alt_form')
+              ->having('COUNT(*) > 1');
+
+  if ($filter) {
+    $filter = strtoupper($filter);
+    $query->where("UPPER(SUBSTRING(lastname,1,1)) = :filter ", array(':filter' => $filter));
+   }
+  $result = $query->execute();
+
+  foreach ($result as $author) {
+    $suspects[] = $author->lastname;
+  }
+
+  $db_result = db_query('SELECT bd.cid, bd.drupal_uid, bd.name, bd.lastname,
+                                bd.firstname, bd.prefix, bd.suffix,
+                                bd.initials, bd.affiliation, bd.md5, bd.literal,
+                                COUNT(*) AS cnt
+                            FROM {biblio_contributor} b
+                                 LEFT JOIN {biblio_contributor_data} bd ON b.cid = bd.cid
+                                 INNER JOIN {node} n on n.vid = b.vid
+                            ' . $where_clause . '
+                            GROUP BY bd.cid, bd.drupal_uid, bd.name, bd.lastname,
+                                     bd.firstname, bd.prefix, bd.suffix,
+                                     bd.initials, bd.affiliation, bd.md5, bd.literal
+                            ORDER BY  lastname ASC, SUBSTRING(firstname,1,1) ASC,
+                            initials ASC', array(':filter' => $filter));
+
+  foreach ($db_result as $author) {
+    if (array_search($author->lastname, $suspects) !== FALSE) {
+      $author->suspect = TRUE;
+    }
+    $authors[] = $author;
+  }
+
+  return $authors;
+}
+
+function _biblio_format_author_page($path, $filter, $authors) {
+  $header_ext = $checkbox = '';
+  $header = array();
+
+  if (biblio_access('edit_author')) {
+    if (!empty($filter)) {
+      $header_ext = ' ' . t('whose last name begins with the letter') . ': ' . $filter;
+    }
+    $checkbox = array(
+      '#title' => t('Highlight possible duplicates'),
+      '#type'  => 'checkbox',
+      '#id'    => 'biblio-highlight',
+    );
+    $checkbox = '<div class="biblio-alpha-line">' . drupal_render($checkbox) . '</div>';
+    $header = array(array('data' => t('There are a total of @count authors in the database!header_ext.', array('@count' => count($authors), '!header_ext' => $header_ext)), 'align' =>'center', 'colspan' => 3));
+  }
+
+  $rows[] = array(
+    array('data' =>
+      theme('biblio_alpha_line', array('type' => 'authors', 'current' => $filter, 'path' => $path)) . $checkbox, 'colspan' => 3));
+  if (count($authors)) {
+    for ($i=0; $i < count($authors); $i+=3) {
+      $rows[] = array( array('data' => _biblio_format_author($authors[$i]) ),
+      array('data' => isset($authors[$i+1])?_biblio_format_author($authors[$i+1]):'' ),
+      array('data' => isset($authors[$i+2])?_biblio_format_author($authors[$i+2]):'' ));
+    }
+  }
+
+
+  return array(
+    '#theme' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+}
+/*
+ * Helper function to format the authors and add edit links if required
+ */
+function _biblio_format_author($author) {
+  if ($author->literal) {
+    $name = $author->name;
+  }
+  else {
+    $name = $author->lastname;
+    $name .= (!empty($author->firstname)) ? ', ' . drupal_substr($author->firstname, 0, 1) . '.' :
+             (!empty($author->initials) ? ', ' . $author->initials : '');
+  }
+
+  $uri['path'] = variable_get('biblio_base', 'biblio');
+  $uri['query']['f']['author'] = $author->cid;
+  $uri['attributes'] = array();
+
+  if (isset($author->drupal_uid) && $author->drupal_uid > 0) {
+    $uri['attributes'] += array('class' => array('biblio-local-author'));
+  }
+  if (variable_get('biblio_links_target_new_window', null)){
+    $uri['attributes'] +=  array('target'=>'_blank');
+    $uri['html'] = TRUE;
+  }
+
+  $name = l(trim($name), $uri['path'], $uri );
+
+ // $format = biblio_format_authors(array($author));
+  $name .= ' (' . $author->cnt . ') ' . ((biblio_access('edit_author'))?_biblio_author_edit_links($author):'');
+  if (biblio_access('edit_author') && isset($author->suspect)) {
+    $name = '<div class="suspect">' . $name . '</div>';
+  }
+
+  return $name;
+}
+
+function _biblio_author_edit_links($author) {
+  static $path = '';
+  $destination = drupal_get_destination();
+  if (empty($path)) {
+    $path =  (ord(substr($_GET['q'], -1)) > 97) ? $_GET['q'] . "/" : substr($_GET['q'], 0, -1);
+    $path = (strpos($path, 'list/')) ? str_replace('list/', '', $path) : $path;
+  }
+  return l(' [' . t('edit') . ']', $path . $author->cid . "/edit" );
+}
+
+function biblio_keyword_page() {
+  $uri = drupal_parse_url(request_uri());
+//  $uri['path'] = variable_get('biblio_base', 'biblio');
+  $filter = isset($uri['query']['f']['keyword']) ? $uri['query']['f']['keyword'] : '';
+  $keywords = _biblio_get_keywords($filter);
+  return _biblio_format_keyword_page($uri, $filter, $keywords);
+}
+
+function _biblio_get_keywords($filter = NULL) {
+  global $user;
+  $keywords = array();
+  $where = array();
+  $where_clause = '';
+  if ($filter) {
+    $filter = strtoupper($filter);
+    $where[] =  "UPPER(SUBSTRING(word,1,1)) = :filter ";
+    $header_ext = t(' (which start with the letter "@letter") ', array('@letter' => $filter ));
+  }
+  else {
+    $query_ext =  NULL;
+    $header_ext = NULL;
+  }
+
+  if ($user->uid != 1 ) {
+    $where[] = 'n.status = 1 ';
+  }//show only published entries to everyone except admin
+
+  if (count($where)) {
+    $where_clause = count($where) > 1 ? 'WHERE (' . implode(') AND (', $where) . ')': 'WHERE ' . $where[0];
+  }
+
+  $db_result = db_query('SELECT bkd.kid, bkd.word, COUNT(*) AS cnt
+                         FROM {biblio_keyword} bk
+                         LEFT JOIN {biblio_keyword_data} bkd ON bkd.kid = bk.kid
+                         INNER JOIN {node} n ON n.vid = bk.vid
+                         '. $where_clause . '
+                         GROUP BY bkd.kid, bkd.word
+                         ORDER BY  word ASC', array(':filter' => $filter));
+
+  foreach ($db_result as $keyword) {
+    $keywords[] = $keyword;
+  }
+  return $keywords;
+}
+
+function _biblio_format_keyword_page($uri, $filter, $keywords) {
+  $rows[] = array(array('data' => theme('biblio_alpha_line', array('type' => 'keywords', 'current' => $filter, 'path' => $uri['path'])), 'colspan' => 3));
+  for ($i=0; $i < count($keywords); $i+=3) {
+    $rows[] = array( array('data' => _biblio_format_keyword($uri, $keywords[$i]) ),
+    array('data' => isset($keywords[$i+1]) ? _biblio_format_keyword($uri, $keywords[$i+1]) : '' ),
+    array('data' => isset($keywords[$i+2]) ? _biblio_format_keyword($uri, $keywords[$i+2]) : '' ));
+  }
+  //$header = array(array('data' => t('There are a total of @count keywords !header_ext in the database',array('@count' => count($keywords), '!header_ext' => $header_ext)), 'align' =>'center', 'colspan' => 3));
+  $output = theme('table', array('rows' => $rows));
+  return $output;
+}
+function _biblio_format_keyword($uri, $keyword) {
+  $base      = variable_get('biblio_base', 'biblio');
+  $uri['path'] = $base;
+  $uri['query']['f']['keyword'] = $keyword->kid;
+  $format    = l(trim($keyword->word), $base, $uri);
+  $format   .= ' (' . $keyword->cnt . ') ' ;
+  $destination = drupal_get_destination();
+  $path =  (ord(substr($_GET['q'], -1)) > 97) ? $_GET['q'] . "/" : substr($_GET['q'], 0, -1);
+  $edit_link = ' [' . l(t('edit'), $path . $keyword->kid . "/edit", array('query' => $destination)) . '] ';
+  $format   .= (user_access('administer biblio')) ? $edit_link : '';
+
+  return $format;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.search.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,303 @@
+<?php
+
+function _biblio_search_info() {
+  return array(
+    'title' => 'Content',
+    'path' => 'node',
+    'conditions_callback' => 'sample_search_conditions_callback',
+  );
+}
+
+function sample_search_conditions_callback($keys) {
+  $conditions = array();
+
+  if (!empty($_REQUEST['keys'])) {
+    $conditions['keys'] = $_REQUEST['keys'];
+  }
+  if (!empty($_REQUEST['sample_search_keys'])) {
+    $conditions['sample_search_keys'] = $_REQUEST['sample_search_keys'];
+  }
+  if ($force_keys = variable_get('sample_search_force_keywords', '')) {
+    $conditions['sample_search_force_keywords'] = $force_keys;
+  }
+  return $conditions;
+}
+
+function _biblio_search_access() {
+  return user_access('access content');
+}
+
+/**
+ * Take action when the search index is going to be rebuilt.
+ *
+ * Modules that use hook_update_index() should update their indexing
+ * bookkeeping so that it starts from scratch the next time
+ * hook_update_index() is called.
+ *
+ * @ingroup search
+ */
+function _biblio_search_reset() {
+  db_update('search_dataset')
+    ->fields(array('reindex' => REQUEST_TIME))
+    ->condition('type', 'node')
+    ->execute();
+}
+
+/**
+ * Report the status of indexing.
+ *
+ * @return
+ *  An associative array with the key-value pairs:
+ *  - 'remaining': The number of items left to index.
+ *  - 'total': The total number of items to index.
+ *
+ * @ingroup search
+ */
+function _biblio_search_status() {
+  $total = db_query('SELECT COUNT(*) FROM {node} WHERE status = 1')->fetchField();
+  $remaining = db_query("SELECT COUNT(*) FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE n.status = 1 AND d.sid IS NULL OR d.reindex <> 0")->fetchField();
+  return array('remaining' => $remaining, 'total' => $total);
+}
+
+/**
+ * Add elements to the search settings form.
+ *
+ * @return
+ *   Form array for the Search settings page at admin/config/search/settings.
+ *
+ * @ingroup search
+ */
+function _biblio_search_admin() {
+  // Output form for defining rank factor weights.
+  $form['content_ranking'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Content ranking'),
+  );
+  $form['content_ranking']['#theme'] = 'node_search_admin';
+  $form['content_ranking']['info'] = array(
+    '#value' => '<em>' . t('The following numbers control which properties the content search should favor when ordering the results. Higher numbers mean more influence, zero means the property is ignored. Changing these numbers does not require the search index to be rebuilt. Changes take effect immediately.') . '</em>'
+  );
+
+  // Note: reversed to reflect that higher number = higher ranking.
+  $options = drupal_map_assoc(range(0, 10));
+  foreach (module_invoke_all('ranking') as $var => $values) {
+    $form['content_ranking']['factors']['node_rank_' . $var] = array(
+      '#title' => $values['title'],
+      '#type' => 'select',
+      '#options' => $options,
+      '#default_value' => variable_get('node_rank_' . $var, 0),
+    );
+  }
+  return $form;
+}
+
+/**
+ * Execute a search for a set of key words.
+ *
+ * Use database API with the 'PagerDefault' query extension to perform your
+ * search.
+ *
+ * If your module uses hook_update_index() and search_index() to index its
+ * items, use table 'search_index' aliased to 'i' as the main table in your
+ * query, with the 'SearchQuery' extension. You can join to your module's table
+ * using the 'i.sid' field, which will contain the $sid values you provided to
+ * search_index(). Add the main keywords to the query by using method
+ * searchExpression(). The functions search_expression_extract() and
+ * search_expression_insert() may also be helpful for adding custom search
+ * parameters to the search expression.
+ *
+ * See node_search_execute() for an example of a module that uses the search
+ * index, and user_search_execute() for an example that doesn't ues the search
+ * index.
+ *
+ * @param $keys
+ *   The search keywords as entered by the user.
+ * @param $conditions
+ *   An optional array of additional conditions, such as filters.
+ *
+ * @return
+ *   An array of search results. To use the default search result
+ *   display, each item should have the following keys':
+ *   - 'link': Required. The URL of the found item.
+ *   - 'type': The type of item (such as the content type).
+ *   - 'title': Required. The name of the item.
+ *   - 'user': The author of the item.
+ *   - 'date': A timestamp when the item was last modified.
+ *   - 'extra': An array of optional extra information items.
+ *   - 'snippet': An excerpt or preview to show with the result (can be
+ *     generated with search_excerpt()).
+ *   - 'language': Language code for the item (usually two characters).
+ *
+ * @ingroup search
+ */
+function _biblio_search_execute($keys = NULL, $conditions = NULL) {
+  // Build matching conditions
+  $query = db_select('search_index', 'i', array('target' => 'slave'))->extend('SearchQuery')->extend('PagerDefault');
+  $query->join('node', 'n', 'n.nid = i.sid');
+  $query
+    ->condition('n.status', 1)
+    ->addTag('node_access')
+    ->searchExpression($keys, 'node');
+
+  // Insert special keywords.
+  $query->setOption('type', 'n.type');
+  $query->setOption('language', 'n.language');
+  if ($query->setOption('term', 'ti.tid')) {
+    $query->join('taxonomy_index', 'ti', 'n.nid = ti.nid');
+  }
+  // Only continue if the first pass query matches.
+  if (!$query->executeFirstPass()) {
+    return array();
+  }
+
+  // Add the ranking expressions.
+  _node_rankings($query);
+
+  // Load results.
+  $find = $query
+    ->limit(10)
+    ->execute();
+  $results = array();
+  foreach ($find as $item) {
+    // Build the node body.
+    $node = node_load($item->sid);
+    node_build_content($node, 'search_result');
+    $node->body = drupal_render($node->content);
+
+    // Fetch comments for snippet.
+    $node->rendered .= ' ' . module_invoke('comment', 'node_update_index', $node);
+    // Fetch terms for snippet.
+    $node->rendered .= ' ' . module_invoke('taxonomy', 'node_update_index', $node);
+
+    $extra = module_invoke_all('node_search_result', $node);
+
+    $results[] = array(
+      'link' => url('node/' . $item->sid, array('absolute' => TRUE)),
+      'type' => check_plain(node_type_get_name($node)),
+      'title' => $node->title,
+      'user' => theme('username', array('account' => $node)),
+      'date' => $node->changed,
+      'node' => $node,
+      'extra' => $extra,
+      'score' => $item->calculated_score,
+      'snippet' => search_excerpt($keys, $node->body),
+    );
+  }
+  return $results;
+}
+
+/**
+ * Override the rendering of search results.
+ *
+ * A module that implements hook_search_info() to define a type of search
+ * may implement this hook in order to override the default theming of
+ * its search results, which is otherwise themed using theme('search_results').
+ *
+ * Note that by default, theme('search_results') and theme('search_result')
+ * work together to create an ordered list (OL). So your hook_search_page()
+ * implementation should probably do this as well.
+ *
+ * @see search-result.tpl.php, search-results.tpl.php
+ *
+ * @param $results
+ *   An array of search results.
+ *
+ * @return
+ *   A renderable array, which will render the formatted search results with
+ *   a pager included.
+ */
+function _biblio_search_page($results) {
+  $output['prefix']['#markup'] = '<ol class="search-results">';
+
+  foreach ($results as $entry) {
+    $output[] = array(
+      '#theme' => 'search_result',
+      '#result' => $entry,
+      '#module' => 'my_module_name',
+    );
+  }
+  $output['suffix']['#markup'] = '</ol>' . theme('pager');
+
+  return $output;
+}
+
+/**
+ * Preprocess text for search.
+ *
+ * This hook is called to preprocess both the text added to the search index and
+ * the keywords users have submitted for searching.
+ *
+ * Possible uses:
+ * - Adding spaces between words of Chinese or Japanese text.
+ * - Stemming words down to their root words to allow matches between, for
+ *   instance, walk, walked, walking, and walks in searching.
+ * - Expanding abbreviations and acronymns that occur in text.
+ *
+ * @param $text
+ *   The text to preprocess. This is a single piece of plain text extracted
+ *   from between two HTML tags or from the search query. It will not contain
+ *   any HTML entities or HTML tags.
+ *
+ * @return
+ *   The text after preprocessing. Note that if your module decides not to alter
+ *   the text, it should return the original text. Also, after preprocessing,
+ *   words in the text should be separated by a space.
+ *
+ * @ingroup search
+ */
+function _biblio_search_preprocess($text) {
+  // Do processing on $text
+  return $text;
+}
+
+/**
+ * Update the search index for this module.
+ *
+ * This hook is called every cron run if search.module is enabled, your
+ * module has implemented hook_search_info(), and your module has been set as
+ * an active search module on the Search settings page
+ * (admin/config/search/settings). It allows your module to add items to the
+ * built-in search index using search_index(), or to add them to your module's
+ * own indexing mechanism.
+ *
+ * When implementing this hook, your module should index content items that
+ * were modified or added since the last run. PHP has a time limit
+ * for cron, though, so it is advisable to limit how many items you index
+ * per run using variable_get('search_cron_limit') (see example below). Also,
+ * since the cron run could time out and abort in the middle of your run, you
+ * should update your module's internal bookkeeping on when items have last
+ * been indexed as you go rather than waiting to the end of indexing.
+ *
+ * @ingroup search
+ */
+function _biblio_update_index() {
+  $limit = (int)variable_get('search_cron_limit', 100);
+
+  $result = db_query_range("SELECT n.nid FROM {node} n LEFT JOIN {search_dataset} d ON d.type = 'node' AND d.sid = n.nid WHERE d.sid IS NULL OR d.reindex <> 0 ORDER BY d.reindex ASC, n.nid ASC", 0, $limit);
+
+  foreach ($result as $node) {
+    $node = node_load($node->nid);
+
+    // Save the changed time of the most recent indexed node, for the search
+    // results half-life calculation.
+    variable_set('node_cron_last', $node->changed);
+
+    // Render the node.
+    node_build_content($node, 'search_index');
+    $node->rendered = drupal_render($node->content);
+
+    $text = '<h1>' . check_plain($node->title) . '</h1>' . $node->rendered;
+
+    // Fetch extra data normally not visible
+    $extra = module_invoke_all('node_update_index', $node);
+    foreach ($extra as $t) {
+      $text .= $t;
+    }
+
+    // Update index
+    search_index($node->nid, 'node', $text);
+  }
+}
+/**
+ * @} End of "addtogroup hooks".
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio.util.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,387 @@
+<?php
+function biblio_normalize_title($title) {
+  $stop_words = 'a,an,the,is,on';
+  $stop_words = explode(',', variable_get('biblio_stop_words', $stop_words));
+  if (!@preg_match('/\pL/u', 'a')) {
+    // probably a broken PCRE library
+    $title = trim(_strip_punctuation($title));
+  }
+  else {
+    // Unicode safe filter for the value
+    $title = trim(_strip_punctuation_utf8($title));
+  }
+
+  $title = trim(_strip_punctuation($title));
+
+  if (function_exists('mb_regex_encoding')) {
+    mb_regex_encoding("utf-8");
+    $title_words = mb_split(' +', $title);
+  }
+  else {
+    $title_words = explode(' ', $title);
+  }
+
+  while (array_search(drupal_strtolower($title_words[0]), $stop_words) !== FALSE) {
+    array_shift($title_words);
+  }
+
+  return drupal_substr(implode(' ', $title_words), 0, 64);
+}
+function biblio_coins($node) {
+  // Copyright:          Matthias Steffens <mailto:refbase@extracts.de> and the file's
+  //                     original author.
+  // Original Author:    Richard Karnesky <mailto:karnesky@gmail.com>  //
+  // Adapted for biblio: Ron Jerome
+  // fmt_info (type)
+  $fmt = "info:ofi/fmt:kev:mtx:";
+  // 'dissertation' is compatible with the 1.0 spec, but not the 0.1 spec
+  if ($node->biblio_type == 108) {
+    $fmt .= "dissertation";
+  }
+  elseif ($node->biblio_type == 102) {
+    $fmt .= "journal";
+  }
+  elseif ($node->biblio_type == 100 || $node->biblio_type == 101) {
+    $fmt .= "book";
+  }
+  // 'dc' (dublin core) is compatible with the 1.0 spec, but not the 0.1 spec.
+  // We default to this, as it is the most generic type.
+  else {
+   $fmt .= "dc";
+  }
+
+  $co = biblio_contextObject($node);
+  $coins = "ctx_ver=Z39.88-2004&amp;rft_val_fmt=" . urlencode($fmt);
+  foreach ($co as $coKey => $coValue) {
+    // 'urlencode()' differs from 'rawurlencode() (i.e., RFC1738 encoding)
+    // in that spaces are encoded as plus (+) signs
+    $coKey = preg_replace("/au[0-9]*/", "au", $coKey);
+    $coins .= "&amp;" . $coKey . "=" . urlencode($coValue);
+  }
+  $coinsSpan = "<span class=\"Z3988\" title=\"" . $coins . "\"></span>";
+  return $coinsSpan;
+}
+
+function biblio_contextObject($node) {
+  // Copyright:          Matthias Steffens <mailto:refbase@extracts.de> and the file's
+  //                     original author.
+  // Original Author:    Richard Karnesky <mailto:karnesky@gmail.com>  //
+  // Adapted for biblio: Ron Jerome
+  global $base_url;
+  $i = 0;
+    // $openurl_base = variable_get('biblio_baseopenurl', '');
+  $co = array();
+  // rfr_id
+//  $co["rfr_id"] = "info:sid/". ereg_replace("http://", "", $base_url);
+//  // genre (type)
+//  if (isset($node->biblio_type)) {
+//    if ($node->biblio_type == 102)
+//    $co["rft.genre"] = "article";
+//    elseif ($node->biblio_type == 101) $co["rft.genre"] = "bookitem";
+//    elseif ($node->biblio_type == 100) $co["rft.genre"] = "book";
+//    elseif ($node->biblio_type == "Journal") $co["rft.genre"] = "journal";
+//  }
+  // atitle, btitle, title (title, publication)
+  if (($node->biblio_type == 102) || ($node->biblio_type == 101)) {
+    if (!empty($node->title)) $co["rft.atitle"] = check_plain($node->title);
+    if (!empty($node->biblio_secondary_title)) {
+      $co["rft.title"] = check_plain($node->biblio_secondary_title);
+      if ($node->biblio_type == 101)
+      $co["rft.btitle"] = check_plain($node->biblio_secondary_title);
+    }
+  }
+  elseif (!empty($node->title)) {
+   $co["rft.title"] = check_plain($node->title);
+  }
+  if (($node->biblio_type == 100) && (!empty($node->biblio_secondary_title))) $co["rft.btitle"] = check_plain($node->biblio_secondary_title);
+  // stitle (abbrev_journal)
+  if (!empty($node->biblio_short_title)) $co["rft.stitle"] = check_plain($node->biblio_short_title);
+  // series (series_title)
+  if (!empty($node->biblio_tertiary_title)) $co["rft.series"] = check_plain($node->biblio_tertiary_title);
+  // issn
+  if (!empty($node->biblio_issn)) $co["rft.issn"] = check_plain($node->biblio_issn);
+  // isbn
+  if (!empty($node->biblio_isbn)) $co["rft.isbn"] = check_plain($node->biblio_isbn);
+  // date (year)
+  if (!empty($node->biblio_year)) $co["rft.date"] = check_plain($node->biblio_year);
+  // volume
+  if (!empty($node->biblio_volume)) $co["rft.volume"] = check_plain($node->biblio_volume);
+  // issue
+  if (!empty($node->biblio_issue)) $co["rft.issue"] = check_plain($node->biblio_issue);
+  // spage, epage, tpages (pages)
+  // NOTE: lifted from modsxml.inc.php--should throw some into a new include file
+  if (!empty($node->biblio_pages)) {
+    if (preg_match("/[0-9] *- *[0-9]/", $node->biblio_pages)) {
+      list ($pagestart, $pageend) = preg_split('/\s*[-]\s*/', $node->biblio_pages);
+      if ($pagestart < $pageend) {
+        $co["rft.spage"] = check_plain($pagestart);
+        $co["rft.epage"] = check_plain($pageend);
+      }
+    }
+    elseif ($node->biblio_type == 100) { //"Book Whole") {
+      $pagetotal = preg_replace('/^(\d+)\s*pp?\.?$/', "\\1", $node->biblio_pages);
+      $co["rft.tpages"] = check_plain($pagetotal);
+    }
+    else {
+      $co["rft.spage"] = check_plain($node->biblio_pages);
+    }
+  }
+  // aulast, aufirst, author (author)
+  if (!empty($node->biblio_contributors)) {
+    if (!empty($node->biblio_contributors[0]['lastname'])) {
+      $co["rft.aulast"] = check_plain($node->biblio_contributors[0]['lastname']);
+    }
+    if (!empty($node->biblio_contributors[0]['firstname'])) {
+      $co["rft.aufirst"] = check_plain($node->biblio_contributors[0]['firstname']);
+    }
+    elseif (!empty($node->biblio_contributors[0]['initials'])) {
+      $co["rft.auinit"] = check_plain($node->biblio_contributors[0]['initials']);
+    }
+    for($i = 1; $i < count($node->biblio_contributors); $i++) {
+      $author = $node->biblio_contributors[$i];
+      if ($author['auth_category'] == 1) {
+        if (!empty($author['lastname'])) {
+          $au = $author['lastname'];
+          if (!empty($author['firstname']) || !empty($author['initials'])) $au .= ", ";
+        }
+        if (!empty($author['firstname'])) {
+          $au .= $author['firstname'];
+        }
+        elseif (!empty($author['initials'])) {
+          $au .= $author['initials'];
+        }
+        if (!empty($au)) $co["rft.au" . $i] = $au;
+      }
+    }
+  }
+  // pub (publisher)
+  if (!empty($node->biblio_publisher)) $co["rft.pub"] = check_plain($node->biblio_publisher);
+  // place
+  if (!empty($node->biblio_place_published)) $co["rft.place"] = check_plain($node->biblio_place_published);
+  // id (doi, url)
+  if (!empty($node->biblio_doi)) {
+    $co["rft_id"] = "info:doi/" . check_plain($node->biblio_doi);
+  }
+//  elseif (!empty($node->biblio_url)) {
+//    $co["rft_id"] = $node->biblio_url;
+//  }
+
+  return $co;
+}
+
+function biblio_coins_generate(& $node) {
+  if (!isset($node->vid)) {
+    $node->biblio_coins = biblio_coins($node);
+    return;
+  }
+  if ($node) {
+    $node->biblio_coins = biblio_coins($node);
+    db_update('biblio')
+      ->fields(array('biblio_coins' => $node->biblio_coins))
+      ->condition('vid', $node->vid)
+      ->execute();
+  }
+  else {
+    $result = db_query("SELECT nr.*, b.*
+                        FROM {node} AS n
+                        LEFT JOIN {node_revision}  AS nr ON n.vid = nr.vid LEFT JOIN {biblio} AS b ON n.vid = b.vid
+                        WHERE n.type = 'biblio'  ");
+
+    foreach ($result as $node) {
+      $node->biblio_coins = biblio_coins($node);
+      db_update('biblio')
+        ->fields(array('biblio_coins' => $node->biblio_coins))
+        ->condition('vid', $node->vid)
+        ->execute();
+    }
+    drupal_goto('');
+  }
+}
+
+function _strip_punctuation($text) {
+  return preg_replace("/[[:punct:]]/", '', $text);
+}
+/**
+ * Copyright (c) 2008, David R. Nadeau, NadeauSoftware.com.
+ * All rights reserved.
+ *
+ * Strip punctuation characters from UTF-8 text.
+ *
+ * Characters stripped from the text include characters in the following
+ * Unicode categories:
+ *
+ *   Separators
+ *   Control characters
+ *  Formatting characters
+ *  Surrogates
+ *  Open and close quotes
+ *  Open and close brackets
+ *  Dashes
+ *  Connectors
+ *  Numer separators
+ *  Spaces
+ *  Other punctuation
+ *
+ * Exceptions are made for punctuation characters that occur withn URLs
+ * (such as [ ] : ; @ & ? and others), within numbers (such as . , % # '),
+ * and within words (such as - and ').
+ *
+ * Parameters:
+ *   text    the UTF-8 text to strip
+ *
+ * Return values:
+ *   the stripped UTF-8 text.
+ *
+ * See also:
+ *   http://nadeausoftware.com/articles/2007/9/php_tip_how_strip_punctuation_characters_web_page
+ */
+function _strip_punctuation_utf8( $text )
+{
+  $urlbrackets    = '\[\]\(\)';
+  $urlspacebefore = ':;\'_\*%@&?!' . $urlbrackets;
+  $urlspaceafter  = '\.,:;\'\-_\*@&\/\\\\\?!#' . $urlbrackets;
+  $urlall         = '\.,:;\'\-_\*%@&\/\\\\\?!#' . $urlbrackets;
+
+  $specialquotes = '\'"\*<>';
+
+  $fullstop      = '\x{002E}\x{FE52}\x{FF0E}';
+  $comma         = '\x{002C}\x{FE50}\x{FF0C}';
+  $arabsep       = '\x{066B}\x{066C}';
+  $numseparators = $fullstop . $comma . $arabsep;
+
+  $numbersign    = '\x{0023}\x{FE5F}\x{FF03}';
+  $percent       = '\x{066A}\x{0025}\x{066A}\x{FE6A}\x{FF05}\x{2030}\x{2031}';
+  $prime         = '\x{2032}\x{2033}\x{2034}\x{2057}';
+  $nummodifiers  = $numbersign . $percent . $prime;
+
+  return preg_replace(
+    array(
+    // Remove separator, control, formatting, surrogate,
+    // open/close quotes.
+      '/[\p{Z}\p{Cc}\p{Cf}\p{Cs}\p{Pi}\p{Pf}]/u',
+    // Remove other punctuation except special cases
+      '/\p{Po}(?<![' . $specialquotes .
+        $numseparators . $urlall . $nummodifiers . '])/u',
+    // Remove non-URL open/close brackets, except URL brackets.
+      '/[\p{Ps}\p{Pe}](?<![' . $urlbrackets . '])/u',
+    // Remove special quotes, dashes, connectors, number
+    // separators, and URL characters followed by a space
+      '/[' . $specialquotes . $numseparators . $urlspaceafter .
+        '\p{Pd}\p{Pc}]+((?= )|$)/u',
+    // Remove special quotes, connectors, and URL characters
+    // preceded by a space
+      '/((?<= )|^)[' . $specialquotes . $urlspacebefore . '\p{Pc}]+/u',
+    // Remove dashes preceded by a space, but not followed by a number
+      '/((?<= )|^)\p{Pd}+(?![\p{N}\p{Sc}])/u',
+    // Remove consecutive spaces
+      '/ +/',
+    ),
+    ' ',
+    $text );
+}
+
+/**
+ * Copyright (c) 2008, David R. Nadeau, NadeauSoftware.com.
+ * All rights reserved.
+ *
+ * Strip symbol characters from UTF-8 text.
+ *
+ * Characters stripped from the text include characters in the following
+ * Unicode categories:
+ *
+ *   Modifier symbols
+ *   Private use symbols
+ *   Math symbols
+ *   Other symbols
+ *
+ * Exceptions are made for math symbols embedded within numbers (such as
+ * + - /), math symbols used within URLs (such as = ~), units of measure
+ * symbols, and ideograph parts.  Currency symbols are not removed.
+ *
+ * Parameters:
+ *   text    the UTF-8 text to strip
+ *
+ * Return values:
+ *   the stripped UTF-8 text.
+ *
+ * See also:
+ *  http://nadeausoftware.com/articles/2007/09/php_tip_how_strip_symbol_characters_web_page
+ */
+function _strip_symbols( $text )
+{
+  $plus   = '\+\x{FE62}\x{FF0B}\x{208A}\x{207A}';
+  $minus  = '\x{2012}\x{208B}\x{207B}';
+
+  $units  = '\\x{00B0}\x{2103}\x{2109}\\x{23CD}';
+  $units .= '\\x{32CC}-\\x{32CE}';
+  $units .= '\\x{3300}-\\x{3357}';
+  $units .= '\\x{3371}-\\x{33DF}';
+  $units .= '\\x{33FF}';
+
+  $ideo   = '\\x{2E80}-\\x{2EF3}';
+  $ideo  .= '\\x{2F00}-\\x{2FD5}';
+  $ideo  .= '\\x{2FF0}-\\x{2FFB}';
+  $ideo  .= '\\x{3037}-\\x{303F}';
+  $ideo  .= '\\x{3190}-\\x{319F}';
+  $ideo  .= '\\x{31C0}-\\x{31CF}';
+  $ideo  .= '\\x{32C0}-\\x{32CB}';
+  $ideo  .= '\\x{3358}-\\x{3370}';
+  $ideo  .= '\\x{33E0}-\\x{33FE}';
+  $ideo  .= '\\x{A490}-\\x{A4C6}';
+
+  return preg_replace(
+    array(
+    // Remove modifier and private use symbols.
+      '/[\p{Sk}\p{Co}]/u',
+    // Remove math symbols except + - = ~ and fraction slash
+      '/\p{Sm}(?<![' . $plus . $minus . '=~\x{2044}])/u',
+    // Remove + - if space before, no number or currency after
+      '/((?<= )|^)[' . $plus . $minus . ']+((?![\p{N}\p{Sc}])|$)/u',
+    // Remove = if space before
+      '/((?<= )|^)=+/u',
+    // Remove + - = ~ if space after
+      '/[' . $plus . $minus . '=~]+((?= )|$)/u',
+    // Remove other symbols except units and ideograph parts
+      '/\p{So}(?<![' . $units . $ideo . '])/u',
+    // Remove consecutive white space
+      '/ +/',
+    ),
+    ' ',
+    $text );
+}
+/**
+ * Remove HTML tags, including invisible text such as style and
+ * script code, and embedded objects.  Add line breaks around
+ * block-level tags to prevent word joining after tag removal.
+ */
+function _strip_html_tags( $text )
+{
+    $text = preg_replace(
+        array(
+          // Remove invisible content
+            '@<head[^>]*?>.*?</head>@siu',
+            '@<style[^>]*?>.*?</style>@siu',
+            '@<script[^>]*?.*?</script>@siu',
+            '@<object[^>]*?.*?</object>@siu',
+            '@<embed[^>]*?.*?</embed>@siu',
+            '@<applet[^>]*?.*?</applet>@siu',
+            '@<noframes[^>]*?.*?</noframes>@siu',
+            '@<noscript[^>]*?.*?</noscript>@siu',
+            '@<noembed[^>]*?.*?</noembed>@siu',
+          // Add line breaks before and after blocks
+            '@</?((address)|(blockquote)|(center)|(del))@iu',
+            '@</?((div)|(h[1-9])|(ins)|(isindex)|(p)|(pre))@iu',
+            '@</?((dir)|(dl)|(dt)|(dd)|(li)|(menu)|(ol)|(ul))@iu',
+            '@</?((table)|(th)|(td)|(caption))@iu',
+            '@</?((form)|(button)|(fieldset)|(legend)|(input))@iu',
+            '@</?((label)|(select)|(optgroup)|(option)|(textarea))@iu',
+            '@</?((frameset)|(frame)|(iframe))@iu',
+        ),
+        array(
+            ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
+            "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0",
+            "\n\$0", "\n\$0",
+        ),
+        $text );
+    return strip_tags( $text );
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio_theme.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1255 @@
+<?php
+/**
+ *
+ *   Copyright (C) 2006-2011  Ron Jerome
+ *
+ *
+ */
+module_load_include('inc', 'biblio', 'biblio.pages');
+
+
+/**
+ * @param $openURL
+ * @return unknown_type
+ */
+function theme_biblio_openurl($variables) {
+  $open_url = $variables['openURL'];
+  $openurl_image = variable_get('biblio_openurlimage', '');
+  if ($openurl_image != '') {
+    $output .= '<div class="biblio-openurl-image"><a href="' . $open_url . '"target=_blank><img border="0" src="' . $openurl_image . '"/></a></div>';
+  }
+  else {
+    $output .= '<div class="biblio-openurl-text"><a href="' . $open_url . '" target=_blank>' . t('Find It Via OpenURL!') . '</a></div>';
+  }
+  return $output;
+}
+
+/**
+ * @param $node
+ * @return unknown_type
+ */
+function biblio_openurl($node) {
+  global $user;
+  $open_url = '';
+  // Copyright:          Matthias Steffens <mailto:refbase@extracts.de> and the file's
+  //                     original author.
+  // Original Author:    Richard Karnesky <mailto:karnesky@gmail.com>  //
+  // Adapted for biblio: Ron Jerome
+  //  global $open_url_resolver; // these variables are defined in 'ini.inc.php'
+  //  global $hostInstitutionAbbrevName;
+  $open_url_resolver = !empty($user->data['biblio_baseopenurl']) ? $user->data['biblio_baseopenurl'] : '';
+  if (empty($open_url_resolver)) $open_url_resolver = variable_get('biblio_baseopenurl', '');
+  if (!empty($open_url_resolver)) {
+    $co = biblio_contextObject($node);
+
+    $sid = "biblio:" . variable_get('site_name', 'Drupal');
+    $user_sid = !empty($user->data['biblio_openurl_sid']) ? $user->data['biblio_openurl_sid'] : '';
+    $co["sid"] = !empty($user_sid) ? $user_sid : variable_get('biblio_openurl_sid', $sid);
+
+    $open_url = $open_url_resolver;
+    if (!preg_match("/\?/", $open_url_resolver)) {
+      $open_url .= "?";
+    }
+    else {
+      $open_url .= "&amp;";
+    }
+    $open_url .= "ctx_ver=Z39.88-2004";
+    foreach ($co as $coKey => $coValue) {
+      $coKey = preg_replace("/rft./", "", $coKey);
+      $coKey = preg_replace("/au[0-9]*/", "au", $coKey);
+      $open_url .= "&amp;" . $coKey . "=" . rawurlencode($coValue);
+    }
+  }
+  return $open_url;
+}
+
+
+/**
+ * DEPRECIATED! this was the original output format which is not to flexable it will be removed
+ * TODO: remove this function
+ * @param $node
+ * @param $base
+ * @param $style
+ * @return unknown_type
+ */
+function theme_biblio_long($variables) {
+  $output = '';
+  $node = $variables['node'];
+  if (module_exists('popups')) {
+     popups_add_popups();
+  }
+
+  $output .= filter_xss($node->biblio_coins, array('span'));
+  $layout = variable_get('biblio_node_layout', 'orig');
+
+  // Check body value.
+  $has_body = !empty($node->body);
+
+  if (variable_get('biblio_node_layout', 'orig') == 'ft' && $has_body && user_access('view full text')) {
+    $output .= '<div class="biblio-head">' . theme('biblio_style', $variables) . '</div>';
+    $annotation_field = variable_get('biblio_annotations', 'none');
+    if ($annotation_field != 'none' && $node-> $annotation_field) {
+      $output .= '<div class="biblio-annotation">';
+      $output .= filter_xss($node->$annotation_field, biblio_get_allowed_tags());
+      $output .= '</div>';
+    }
+    $output .= drupal_render(field_view_field('node', $node, 'body', array('label' => 'hidden')));
+    if (biblio_access('export', $node)) {
+      $output .= theme('biblio_export_links', array('node' => $node));
+    }
+    return $output;
+  }
+  foreach ((array)$node->biblio_contributors as $auth) {
+    if ($auth['auth_category'] == 1) {
+      $authors[] = theme('biblio_author_link', array('author' => $auth));
+    }
+  }
+  $authors = implode('; ', (array)$authors);
+  $openurl_base = variable_get('biblio_baseopenurl', '');
+  if ($openurl_base)
+    $output .= theme('biblio_openurl', array('openURL' => biblio_openurl($node)));
+  $output .= '<div class="biblio_type"><h3>' . t("Publication Type") . ":</h3> $node->biblio_type_name</div>\n";
+  $output .= '<div class="biblio_authors"><h3>' . t("Authors") . ':</h3> ' . $authors . "</div>\n";
+  $output .= '<div class="biblio_source"><h3>' . t("Source") . ': </h3> ';
+  $source = NULL;
+  if ($node->biblio_secondary_title)
+    $source .= check_plain($node->biblio_secondary_title);
+  if ($node->biblio_publisher) {
+    $source .= $source ? ", " : "";
+    $source .= check_plain($node->biblio_publisher);
+  }
+  if ($node->biblio_volume) {
+    $source .= $source ? ", " : "";
+    $source .= t('Volume') . ' ' . check_plain($node->biblio_volume);
+  }
+  if ($node->biblio_issue) {
+    $source .= $source ? ", " : "";
+    $source .= t('Issue') . ' ' . check_plain($node->biblio_issue);
+  }
+  if ($node->biblio_number) {
+    $source .= $source ? ", " : "";
+    $source .= t('Number') . ' ' . check_plain($node->biblio_number);
+  }
+  if ($node->biblio_place_published) {
+    $source .= $source ? ", " : "";
+    $source .= check_plain($node->biblio_place_published);
+  }
+  if ($node->biblio_pages) {
+    $source .= $source ? ", " : "";
+    $source .= 'p.' . check_plain($node->biblio_pages);
+  }
+  if (isset ($node->biblio_year)) {
+    $node->biblio_year = _biblio_text_year($node->biblio_year);
+    $source .= ' (' . check_plain($node->biblio_year) . ')';
+  }
+  $output .= "$source</div>\n";
+  if ($node->biblio_isbn)
+    $output .= '<h3>' . t("ISBN") . ':</h3> ' . check_plain($node->biblio_isbn) . "\n";
+  if ($node->biblio_call_number)
+    $output .= '<h3>' . t("Call Number") . ':</h3> ' . check_plain($node->biblio_call_number) . "\n";
+  if ($node->biblio_accession_number)
+    $output .= '<h3>' . t("Accession Number") . ':</h3> ' . check_plain($node->biblio_accession_number) . "\n";
+  if ($node->biblio_other_number)
+    $output .= '<h3>' . t("Other Number") . ':</h3> ' . check_plain($node->biblio_other_number) . "\n";
+  if ($node->biblio_url) {
+    $attrib = (variable_get('biblio_links_target_new_window', FALSE)) ? array('target' => '_blank') : array();
+    $output .= '<h3>' . t("URL") . ':</h3>' . l($node->biblio_url, $node->biblio_url, $attrib) . "\n";
+  }
+  if (!empty($node->biblio_keywords)) {
+    $output .= '<h3>' . t("Keywords") . ':</h3> ' . _biblio_keyword_links( $node->biblio_keywords) . "\n";
+  }
+  if ($node->biblio_abst_e)
+    $output .= '<h3>' . t("Abstract") . ':</h3> ' . check_markup($node->biblio_abst_e) . "\n";
+  if ($node->biblio_abst_f)
+    $output .= '<p>' . check_markup($node->biblio_abst_f) . "\n";
+  if ($node->biblio_notes)
+    $output .= '<h3>' . t("Notes") . ': </h3>' . check_markup($node->biblio_notes) . "\n";
+  if (!empty($node->body) && user_access('view full text') ) {
+       $output .= drupal_render(field_view_field('node', $node, 'body'));
+  }
+
+  return $output;
+}
+
+function _biblio_get_field_information($biblio_type, $only_visible = FALSE) {
+  $fields = array();
+  $visible = $only_visible ? ' AND (bt.common = 1 OR bt.visible=1) ' : '';
+
+  $result = db_query("SELECT b.*, btd.*, btt.name AS type_name
+                      FROM {biblio_fields} AS b
+                      INNER JOIN {biblio_field_type} AS bt ON bt.fid = b.fid
+                      INNER JOIN {biblio_field_type_data} AS btd ON btd.ftdid = bt.ftdid
+                      INNER JOIN {biblio_types} as btt ON btt.tid = bt.tid
+                      WHERE bt.tid = :tid $visible
+                      ORDER BY bt.weight ASC", array(':tid' => $biblio_type), array('fetch' => PDO::FETCH_ASSOC));
+
+  foreach ($result as $row) {
+    $fields[$row['fid']] = $row;
+  }
+
+  return $fields;
+}
+
+/**
+ * @param $node
+ * @param $base
+ * @param $teaser
+ * @return unknown_type
+ */
+function theme_biblio_tabular($variables) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $node = $variables['node'];
+  $base = $variables['base'];
+  static $citeproc;
+
+  if (module_exists('popups')) {
+     popups_add_popups();
+  }
+  $tid = $node->biblio_type;
+  $fields = _biblio_get_field_information($node->biblio_type, TRUE);
+  $rows[] = array(
+    array('data' => t('Title'), 'class' => array('biblio-row-title')),
+    array('data' => filter_xss($node->title, biblio_get_allowed_tags()))
+  );
+
+  if (!isset($node->biblio_type_name) && isset($node->biblio_type)) { // needed for preview
+    if (($pub_type = db_query('SELECT t.tid, t.name FROM {biblio_types} as t WHERE t.tid=:tid', array(':tid' => $node->biblio_type))->fetchObject())) {
+      $node->biblio_type_name = drupal_ucfirst(_biblio_localize_type($pub_type->tid, $pub_type->name));
+    }
+  }
+
+  $rows[] = array(
+    array('data' => t('Publication Type'), 'class' => array('biblio-row-title')),
+    array('data' => $node->biblio_type_name)
+  );
+
+  $attrib = (variable_get('biblio_links_target_new_window', FALSE)) ? array('target' => '_blank') : array();
+
+  $doi = '';
+  if (!empty($node->biblio_doi)) {
+    $doi_url = '';
+    if ( ($doi_start = strpos($node->biblio_doi, '10.')) !== FALSE) {
+      $doi = substr($node->biblio_doi, $doi_start);
+      $doi_url .= 'http://dx.doi.org/' . $doi;
+      $doi = l($doi, $doi_url, $attrib);
+    }
+
+  }
+
+  foreach ($fields as $key => $row) {
+    // handling the contributor categories like any other field orders them correctly by weight
+    if ($row['type'] == 'contrib_widget' && ($authors = biblio_get_contributor_category($node->biblio_contributors, $row['fid']))) {
+      $data = biblio_format_authors($authors);
+    }
+    elseif (empty ($node->$row['name']) || $row['name'] == 'biblio_coins') {
+      continue;
+    }
+    else {
+      switch ($row['name']) {
+        case 'biblio_keywords' :
+         $data = _biblio_keyword_links($node->$row['name'], $base);
+          break;
+        case 'biblio_url' :
+          $data = l($node->$row['name'], $node->$row['name'], $attrib);
+          break;
+        case 'biblio_doi' :
+           $data = $doi;
+          break;
+        default:
+          if ($row['type'] == 'text_format') {
+            $format = filter_default_format();
+            if (!empty($node->biblio_formats) ) {
+              $formats = $node->biblio_formats;
+              $format  = isset($formats[$row['name']]) ? $formats[$row['name']] : $format;
+            }
+            $data = check_markup($node->$row['name'], $format);
+          }
+          else {
+            $data = check_plain($node->$row['name']);
+          }
+      }
+    }
+    $rows[] = array(
+      array(
+        'data' => t($row['title']),
+        'class' => array('biblio-row-title')
+      ),
+      array(
+        'data' => $data
+      )
+    );
+  }
+  if (isset($node->body) && !empty($node->body) && user_access('view full text')) {
+    $rows[] = array(
+        array('data' => t('Full Text'),  'valign' => 'top'),
+        array('data' =>  drupal_render(field_view_field('node', $node, 'body', array('label' => 'hidden')))),
+    );
+
+  }
+  // let other modules add rows if desired...
+  drupal_alter('biblio_node_table_rows', $rows, $node);
+
+  $output = '<div id="biblio-node">';
+  $output .= filter_xss($node->biblio_coins, array('span'));
+  $header = array();
+  $output .= theme('table', array('header' => $header, 'rows' => $rows));
+  $output .= '</div>';
+
+  return $output;
+}
+
+function _biblio_get_latin1_regex() {
+  $alnum = "[:alnum:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+
+  // Matches ISO-8859-1 letters:
+  $alpha = "[:alpha:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+
+  // Matches ISO-8859-1 control characters:
+  $cntrl = "[:cntrl:]";
+
+  // Matches ISO-8859-1 dashes & hyphens:
+  $dash = "-–";
+
+  // Matches ISO-8859-1 digits:
+  $digit = "[\d]";
+
+  // Matches ISO-8859-1 printing characters (excluding space):
+  $graph = "[:graph:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+
+  // Matches ISO-8859-1 lower case letters:
+  $lower = "[:lower:]äåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+
+  // Matches ISO-8859-1 printing characters (including space):
+  $print = "[:print:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+
+  // Matches ISO-8859-1 punctuation:
+  $punct = "[:punct:]";
+
+  // Matches ISO-8859-1 whitespace (separating characters with no visual representation):
+  $space = "[\s]";
+
+  // Matches ISO-8859-1 upper case letters:
+  $upper = "[:upper:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆ";
+
+  // Matches ISO-8859-1 "word" characters:
+  $word = "_[:alnum:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+
+  // Defines the PCRE pattern modifier(s) to be used in conjunction with the above variables:
+  // More info: <http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php>
+  $patternModifiers = "";
+
+  return array($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
+       $print, $punct, $space, $upper, $word, $patternModifiers);
+
+}
+/*
+ * Helper function for theme_biblio_format_authors() and theme_biblio_page_number()
+ */
+function _biblio_get_utf8_regex() {
+
+    // Matches Unicode letters & digits:
+  $alnum = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}"; // Unicode-aware equivalent of "[:alnum:]"
+
+  // Matches Unicode letters:
+  $alpha = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}"; // Unicode-aware equivalent of "[:alpha:]"
+
+  // Matches Unicode control codes & characters not in other categories:
+  $cntrl = "\p{C}"; // Unicode-aware equivalent of "[:cntrl:]"
+
+  // Matches Unicode dashes & hyphens:
+  $dash = "\p{Pd}";
+
+  // Matches Unicode digits:
+  $digit = "\p{Nd}"; // Unicode-aware equivalent of "[:digit:]"
+
+  // Matches Unicode printing characters (excluding space):
+  $graph = "^\p{C}\t\n\f\r\p{Z}"; // Unicode-aware equivalent of "[:graph:]"
+
+  // Matches Unicode lower case letters:
+  $lower = "\p{Ll}\p{M}"; // Unicode-aware equivalent of "[:lower:]"
+
+  // Matches Unicode printing characters (including space):
+  $print = "\P{C}"; // same as "^\p{C}", Unicode-aware equivalent of "[:print:]"
+
+  // Matches Unicode punctuation (printing characters excluding letters & digits):
+  $punct = "\p{P}"; // Unicode-aware equivalent of "[:punct:]"
+
+  // Matches Unicode whitespace (separating characters with no visual representation):
+  $space = "\t\n\f\r\p{Z}"; // Unicode-aware equivalent of "[:space:]"
+
+  // Matches Unicode upper case letters:
+  $upper = "\p{Lu}\p{Lt}"; // Unicode-aware equivalent of "[:upper:]"
+
+  // Matches Unicode "word" characters:
+  $word = "_\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}"; // Unicode-aware equivalent of "[:word:]" (or "[:alnum:]" plus "_")
+
+  // Defines the PCRE pattern modifier(s) to be used in conjunction with the above variables:
+  // More info: <http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php>
+  $patternModifiers = "u"; // the "u" (PCRE_UTF8) pattern modifier causes PHP/PCRE to treat pattern strings as UTF-8
+
+  return array($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
+       $print, $punct, $space, $upper, $word, $patternModifiers);
+}
+
+function _biblio_get_regex_patterns() {
+  // Checks if PCRE is compiled with UTF-8 and Unicode support
+  if (!@preg_match('/\pL/u', 'a')) {
+    // probably a broken PCRE library
+    return _biblio_get_latin1_regex();
+  }
+  else {
+    // Unicode safe filter for the value
+    return _biblio_get_utf8_regex();
+  }
+}
+
+function biblio_format_authors($authors) {
+  if (module_exists('biblio_citeproc')) {
+    static $auth_proc;
+    if (!isset($auth_proc)) {
+      module_load_include('inc', 'biblio_citeproc', 'CSL');
+      $csl = '<name form="long" name-as-sort-order="all" sort-separator=", " initialize-with="" delimiter=", " />';
+      $csl_doc = new DOMDocument();
+      $csl_doc->loadXML($csl);
+      $auth_proc = new csl_rendering_element($csl_doc);
+    }
+    $data = $auth_proc->render($authors);
+  }
+  else {
+    $style_name = biblio_get_style();
+    $style_function = "biblio_style_$style_name" . "_author_options";
+    if (!function_exists($style_function)) {
+      module_load_include('inc', 'biblio', "/styles/biblio_style_$style_name");
+    }
+    $author_options = $style_function();
+    $author_options['numberOfAuthorsTriggeringEtAl'] = 100; //set really high so we see all authors
+    $data = theme('biblio_format_authors', array('contributors' => $authors, 'options' => $author_options));
+  }
+
+  return $data;
+}
+function theme_biblio_format_authors($variables) {
+  $contributors = $variables['contributors'];
+  $options      = $variables['options'];
+
+  if (empty($contributors)) return;
+  list($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
+       $print, $punct, $space, $upper, $word, $patternModifiers) = _biblio_get_regex_patterns();
+  $base  = variable_get('biblio_base', 'biblio');
+  $author_links = variable_get('biblio_author_links', 1);
+
+  $authorCount = count($contributors); // check how many authors we have to deal with
+  $output = ""; // this variable will hold the final author string
+  $includeStringAfterFirstAuthor = FALSE;
+
+  if (empty($options['numberOfAuthorsTriggeringEtAl']))  $options['numberOfAuthorsTriggeringEtAl'] = $authorCount;
+
+  if (empty($options['includeNumberOfAuthors']))  $options['includeNumberOfAuthors'] = $authorCount;
+
+  foreach ($contributors as $rank => $author) {
+    if (empty($author['name'])) continue;
+    if (!isset($author['lastname']) && empty($author['literal'])) {
+      module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+      $author = biblio_parse_author($author, $author['auth_type']); // this is needed for form preview to fill in all fields
+    }
+    if (empty($author['literal'])) {
+      if (!empty($author['firstname'])) {
+        if ($options['shortenGivenNames']) {// if we're supposed to abbreviate given names
+          // within initials, reduce all full first names (-> defined by a starting uppercase character, followed by one ore more lowercase characters)
+          // to initials, i.e., only retain their first character
+          $author['firstname'] = preg_replace("/([$upper])[$lower]+/$patternModifiers", '\\1', $author['firstname']);
+          //$author['firstname'] = drupal_substr($author['firstname'], 0, 1);
+          // the next line caused extra betweenInitialsDelim to appear in some circumstances
+          //$author['firstname'] = preg_replace("/($space|$dash)?/$patternModifier", $options['betweenInitialsDelim'], $author['firstname']);
+        }
+      }
+      if (isset($author['initials'])) {
+        // within initials, remove any dots:
+        $author['initials'] = preg_replace("/([$upper])\.+/$patternModifiers", "\\1", $author['initials']);
+        //$author['initials'] = str_replace('.', '',  $author['initials']);
+
+        // within initials, remove any spaces *between* initials:
+        $author['initials'] = preg_replace("/(?<=[-$upper]) +(?=[-$upper])/$patternModifiers", "", $author['initials']);
+        //$author['initials'] = str_replace(' ', '',  $author['initials']);
+
+        // within initials, add a space after a hyphen, but only if ...
+        if (preg_match('/ $/', $options['betweenInitialsDelim'])) { // ... the delimiter that separates initials ends with a space
+          $author['initials'] = preg_replace("/-(?=[$upper])/$patternModifiers", "- ", $author['initials']);
+        }
+        // then, separate initials with the specified delimiter:
+        $delim = $options['betweenInitialsDelim'];
+        $author['initials'] = preg_replace("/([$upper])(?=[^$lower]+|$)/$patternModifiers", "\\1$delim", $author['initials']);
+
+        $shortenInitials = (isset($options['numberOfInitialsToKeep'])) ? $options['numberOfInitialsToKeep'] : FALSE;
+        if ($shortenInitials) $author['initials'] = drupal_substr($author['initials'], 0, $shortenInitials);
+
+        if ($options['shortenGivenNames'] && !empty($author['firstname'])) {
+          $author['firstname'] = $author['firstname'] . $options['betweenInitialsDelim'] . $author['initials'];
+          if ($shortenInitials) $author['firstname'] = drupal_substr($author['firstname'], 0, $shortenInitials);
+        }
+        elseif (!empty($author['firstname'])) {
+          $author['firstname'] = $author['firstname'] . ' ' . $author['initials'];
+        }
+        elseif (empty($author['firstname'])) {
+          $author['firstname'] = $author['initials'];
+        }
+      }
+
+      // if there is a surname prefix like "van", "von" etc, stick it back before the last name.
+      if (!empty($author['prefix'])) $author['lastname'] = $author['prefix'] . ' ' . $author['lastname'];
+      if (!empty($author['suffix'])) $author['lastname'] = $author['lastname'] . ', ' . $author['suffix'];
+
+      if (!empty($author['firstname'])) {
+        if ($rank == 0) { // -> first author
+          if ($options['initialsBeforeAuthorFirstAuthor']) {
+            $author['name'] = $author['firstname'] . $options['AuthorsInitialsDelimFirstAuthor'] . $author['lastname'];
+          }
+          else{
+            $author['name'] = $author['lastname'] . $options['AuthorsInitialsDelimFirstAuthor'] . $author['firstname'];
+          }
+        }
+        else { // $rank > 0 // -> all authors except the first one
+          if ($options['initialsBeforeAuthorStandard']) {
+            $author['name'] = $author['firstname'] . $options['AuthorsInitialsDelimStandard'] . $author['lastname'];
+          }
+          else{
+            $author['name'] = $author['lastname'] . $options['AuthorsInitialsDelimStandard'] . $author['firstname'];
+          }
+        }
+      }
+      else {
+        $author['name'] = $author['lastname'];
+      }
+    }
+    if ($author_links) {
+      $author['name'] = theme('biblio_author_link', array('author' => $author));
+    }
+    else {
+      $author['name'] = check_plain($author['name']);
+    }
+    // append this author to the final author string:
+    if (($rank == 0) OR ($rank + 1) < $authorCount) {// -> first author, or (for multiple authors) all authors except the last one
+      if ($rank == 0) { // -> first author
+        $output .= $author['name'];
+      }
+      else {// -> for multiple authors, all authors except the first or the last one
+        $output .= $options['BetweenAuthorsDelimStandard'] . $author['name'];
+      }
+      // we'll append the string in '$customStringAfterFirstAuthors' to the number of authors given in '$includeNumberOfAuthors' if the total number of authors is greater than the number given in '$numberOfAuthorsTriggeringEtAl':
+      if ((($rank + 1) == $options['includeNumberOfAuthors']) AND ($authorCount > $options['numberOfAuthorsTriggeringEtAl'])) {
+        if (preg_match("/__NUMBER_OF_AUTHORS__/", $options['customStringAfterFirstAuthors'])) {
+          $customStringAfterFirstAuthors = preg_replace("/__NUMBER_OF_AUTHORS__/", ($authorCount - $options['includeNumberOfAuthors']), $options['customStringAfterFirstAuthors']); // resolve placeholder
+        }
+        $includeStringAfterFirstAuthor = TRUE;
+        break;
+      }
+    }
+    elseif (($authorCount > 1) AND (($rank + 1) == $authorCount)) {// -> last author (if multiple authors)
+      $output .= $options['BetweenAuthorsDelimLastAuthor'] . $author['name'];
+    }
+  }
+
+  // do some final clean up:
+  //if ($options['encodeHTML'])
+  //$output = encodeHTML($output); // HTML encode higher ASCII characters within the newly arranged author contents
+
+  if ($includeStringAfterFirstAuthor) {
+    $output .= $options['customStringAfterFirstAuthors']; // the custom string won't get HTML encoded so that it's possible to include HTML tags (such as '<i>') within the string
+  }
+  $output = preg_replace("/  +/", " ", $output); // remove double spaces (which occur e.g., when both, $betweenInitialsDelim & $newAuthorsInitialsDelim..., end with a space)
+  $output = preg_replace("/ +([,.;:?!()]|$)/", "\\1", $output); // remove excess spaces before [,.;:?!()] and from the end of the author string
+
+  return $output;
+}
+
+function theme_biblio_author_link($variables) {
+  $base  = variable_get('biblio_base', 'biblio');
+  $author = $variables['author'];
+  $options = isset($variables['options']) ? $variables['options'] : array();
+
+  $link_to_profile = variable_get('biblio_author_link_profile', 0);
+  $link_to_profile_path = variable_get('biblio_author_link_profile_path', 'user/[user:uid]');
+
+  $uri = drupal_parse_url(request_uri());
+  $uri = array_merge($uri, $options);
+  if (!isset($uri['attributes'])) {
+    $uri['attributes'] = array('rel' => 'nofollow');
+  }
+  $path = $uri['path'];
+
+  if (isset($author['drupal_uid']) && $author['drupal_uid'] > 0) {
+    $uri['attributes'] += array('class' => array('biblio-local-author'));
+  }
+  if (variable_get('biblio_links_target_new_window', null)){
+    $uri['attributes'] +=  array('target'=>'_blank');
+    $uri['html'] = TRUE;
+  }
+
+  if ($link_to_profile && isset($author['drupal_uid'])  &&  $author['drupal_uid'] > 0) {
+    $data['user'] = user_load($author['drupal_uid']);
+    $path = token_replace($link_to_profile_path, $data);
+    $alias = drupal_get_path_alias($path);
+    $path_profile = variable_get('biblio_show_profile', '0') ? "$path/$base" : $alias;
+    return l(trim($author['name']), $path_profile, $uri);
+  }
+  else {
+    $uri['path'] = variable_get('biblio_base', 'biblio');
+    $uri['query']['f']['author'] = $author['cid'];
+    return l(trim($author['name']), $uri['path'], $uri );
+  }
+
+}
+
+// Format page information:
+//
+// NOTES: - this function (and refbase in general) assumes following rules for the original formatting of page information in '$orig_page_info':
+//          - single-page items are given as a page range with identical start & end numbers (e.g. "127-127")
+//          - multi-page items are given as a page range where the end number is greater than the start number (e.g. "127-132")
+//          - for multi-page items where only the start page is known, a hyphen is appended to the start page (e.g. "127-")
+//          - total number of pages are given with a "pp" suffix (e.g. "498 pp"), see TODO
+//          - the given page info is left as is if it does not match any of the above rules (e.g. a single page number is ambiguous since it
+//            could mean a single page or the total number of pages)
+//        - the function attempts to deal with page locators that contain letters (e.g. "A1 - A3" or "4a-4c") but, ATM, locator parts (e.g. "A1")
+//          must contain at least one digit character & must not contain any whitespace
+//
+// TODO:  - should we only use Unicode-aware regex expressions (i.e. always use '$space', '$digit' or '$word' instead of ' ', '\d' or '\w', etc)?
+//        - recognize & process total number of pages
+//        - for '$shortenPageRangeEnd=TRUE', add support for page locators that contain letters (e.g. "A1 - A3" or "4a-4c")
+function theme_biblio_page_number($variables) {
+  $orig_page_info         = $variables['orig_page_info'];
+  $page_range_delim       = $variables['page_range_delim'];
+  $single_page_prefix     = $variables['single_page_prefix'];
+  $page_range_prefix      = $variables['page_range_prefix'];
+  $total_pages_prefix     = $variables['total_pages_prefix'];
+  $single_page_suffix     = $variables['single_page_suffix'];
+  $page_range_suffix      = $variables['page_range_prefix'];
+  $total_pages_suffix     = $variables['total_pages_prefix'];
+  $shorten_page_range_end = $variables['single_page_suffix'];
+
+  list($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
+       $print, $punct, $space, $upper, $word, $patternModifiers) = _biblio_get_regex_patterns();
+
+  // Check original page info for any recognized page locators, and process them appropriately:
+  if (preg_match("/\w*\d+\w* *[$dash]+ *(?:\w*\d+\w*)?/$patternModifiers", $orig_page_info)) {// the original page info contains a page range (like: "127-127", "127-132", "A1 - A3", "4a-4c", or "127-" if only start page given)
+    // Remove any whitespace around dashes or hyphens that indicate a page range:
+    $orig_page_info = preg_replace("/(\w*\d+\w*) *([$dash]+) *(\w*\d+\w*)?(?=[^\w\d]|$)/$patternModifiers", "\\1\\2\\3", $orig_page_info);
+
+    // Split original page info into its functional parts:
+    // NOTE: ATM, we simply split on any whitespace characters, then process all parts with page ranges
+    //       (this will also reduce runs of whitespace to a single space)
+    $partsArray = preg_split("/ +/", $orig_page_info);
+    $partsCount = count($partsArray);
+
+    for ($i=0; $i < $partsCount; $i++) {
+      // Format parts with page ranges:
+      // - single-page item:
+      if (preg_match("/(\w*\d+\w*)[$dash]+\\1(?=[^\w\d]|$)/$patternModifiers", $partsArray[$i])) // this part contains a page range with identical start & end numbers (like: "127-127")
+      $partsArray[$i] = preg_replace("/(\w*\d+\w*)[$dash]+\\1(?=[^\w\d]|$)/$patternModifiers", $single_page_prefix . "\\1" . $single_page_suffix, $partsArray[$i]);
+
+      // - multi-page item:
+      elseif (preg_match("/\w*\d+\w*[$dash]+(?:\w*\d+\w*)?(?=[^\w\d]|$)/$patternModifiers", $partsArray[$i])) {// this part contains a page range (like: "127-132", or "127-" if only start page given)
+        // In case of '$shorten_page_range_end=TRUE', we abbreviate ending page numbers so that digits aren't repeated unnecessarily:
+        if ($shorten_page_range_end AND preg_match("/\d+[$dash]+\d+/$patternModifiers", $partsArray[$i])) {// ATM, only digit-only page locators (like: "127-132") are supported
+          // NOTE: the logic of this 'if' clause doesn't work if the original page info contains something like "173-190; 195-195" (where, for the first page range, '$endPage' would be "190;" and not "190")
+          list($startPage, $endPage) = preg_split("/[$dash]+/$patternModifiers", $partsArray[$i]);
+
+          $countStartPage = strlen($startPage);
+          $countEndPage = strlen($endPage);
+
+          if (($countStartPage == $countEndPage) AND ($startPage < $endPage)) {
+            for ($j=0; $j < $countStartPage; $j++) {
+              if (preg_match("/^" . substr($startPage, $j, 1) . "/", $endPage)) {// if the ending page number has a digit that's identical to the starting page number (at the same digit offset)
+                $endPage = substr($endPage, 1); // remove the first digit from the remaining ending page number
+              }
+              else {
+                break;
+              }
+            }
+          }
+
+          $partsArray[$i] = $page_range_prefix . $startPage . $page_range_delim . $endPage . $page_range_suffix;
+        }
+        else {// don't abbreviate ending page numbers:
+          $partsArray[$i] = preg_replace("/(\w*\d+\w*)[$dash]+(\w*\d+\w*)?(?=[^\w\d]|$)/$patternModifiers", $page_range_prefix . "\\1" . $page_range_delim . "\\2" . $page_range_suffix, $partsArray[$i]);
+        }
+      }
+    }
+
+    $newPageInfo = join(" ", $partsArray); // merge again all parts
+  }
+  else {
+    $newPageInfo = $orig_page_info; // page info is ambiguous, so we don't mess with it
+  }
+
+  return $newPageInfo;
+}
+
+
+/**
+ * Applies a "style" function to a single node.
+ *
+ * @param $node A node
+ * @param $style_name The name of the style to apply
+ * @return A string containing the styled (HTML) node
+ */
+function theme_biblio_style($variables ) {
+  $node       = $variables['node'];
+  $style_name = $variables['style_name'];
+  $styled_node = '';
+  module_load_include('inc', 'biblio', "/styles/biblio_style_$style_name");
+
+  $style_function = "biblio_style_$style_name";
+  if (function_exists($style_function)) {
+    $styled_node = $style_function ($node);
+  }
+  else {
+    drupal_set_message(t('The style function: @funct does not exist', array('@funct' => $style_function)), 'error');
+  }
+  return ($styled_node . filter_xss($node->biblio_coins, array('span')));
+}
+
+/**
+ * @param $node
+ * @param $base
+ * @param $style
+ * @return unknown_type
+ */
+function theme_biblio_entry($variables) {
+  $node       = $variables['node'];
+  $style_name = $variables['style_name'];
+
+  $output  = "\n" . '<div class="biblio-entry">' . "\n" ;
+  $output  .= '<div class="biblio-style-' . $style_name . '">' . "\n" ;
+  if (!$node->status) {
+    $output .= '<div id="node-' . $node->nid . '" class="node node-unpublished">';
+  }
+
+  // first add the styled entry...
+  $output .= theme('biblio_style', array('node' => $node, 'style_name' => $style_name));
+
+  // now add the various links
+//  if ($node->biblio_abst_e) {
+//    $output .= '<span class="biblio-abstract-link">';
+//    $output .= l(" Abstract", "node/$node->nid") . "\n";
+//    $output .= '</span>';
+//  }
+  $annotation_field = variable_get('biblio_annotations', 'none');
+  if ($annotation_field != 'none' && $node-> $annotation_field) {
+    $output .= '<div class="biblio-annotation">';
+    $output .= filter_xss($node->$annotation_field, biblio_get_allowed_tags());
+    $output .= '</div>';
+  }
+  $openurl_base = variable_get('biblio_baseopenurl', '');
+
+  if ($openurl_base) {
+    $output .= theme('biblio_openurl', array('openURL' => biblio_openurl($node)));
+  }
+
+  if (biblio_access('export')) {
+    $base = variable_get('biblio_base', 'biblio');
+    $output .= theme('biblio_export_links', array('node' => $node));
+  }
+
+  if (biblio_access('download', $node)) {
+    // add links to attached files (if any)
+    $output .= theme('biblio_download_links', array('node' => $node));
+  }
+  if (!$node->status) {
+    $output .= '</div>';
+  }
+
+  $output .= "\n</div></div>";
+
+  return $output;
+}
+
+/**
+ * @param $form
+ * @return unknown_type
+ */
+function theme_biblio_filters($variables) {
+  $form = $variables['form'];
+  $output = '';
+  if (isset($form['current'])) {
+    $output .= '<ul>';
+    foreach (element_children($form['current']) as $key) {
+      $output .= '<li>' . drupal_render($form['current'][$key]) . '</li>';
+    }
+    $output .= '</ul>';
+  }
+  $output .= '<dl class="multiselect">' . (isset($form['current']) ? '<dt><em>' . t('and') . '</em> ' . t('where') . '</dt>' : '') . '<dd class="a">';
+  foreach (element_children($form['filter']) as $key) {
+    $output .= drupal_render($form['filter'][$key]);
+  }
+  $output .= '</dd>';
+  $output .= '<dt>' . t('is') . '</dt><dd class="b">';
+  foreach (element_children($form['status']) as $key) {
+    $output .= drupal_render($form['status'][$key]);
+  }
+  $output .= '</dd>';
+  $output .= '</dl>';
+  $output .= '<div class="container-inline" id="node-buttons">' . drupal_render($form['buttons']) . '</div>';
+  $output .= '<br class="clear" />';
+  return $output;
+}
+
+/**
+ * @param $form
+ * @return unknown_type
+ */
+function theme_biblio_form_filter($variables) {
+ $form = $variables['form'];
+
+  $output .= '<div id="biblio-admin-filter">';
+  $output .= drupal_render($form['filters']);
+  $output .= '</div>';
+  $output .= drupal_render($form);
+  return $output;
+}
+
+function theme_biblio_field_tab($variables) {
+  $form = $variables['form'];
+  $rows = array();
+  $headers = $form['#header'];
+  drupal_add_tabledrag($form['#id'], 'order', 'sibling', 'weight');
+
+  foreach (element_children($form['rows']) as $key) {
+    // No need to print the field title every time.
+//    unset($form[$key]['name']['#title'], $form[$key]['auth_type']['#title'], $form[$key]['auth_category']['#title']);
+    // Add class to group weight fields for drag and drop.
+    $form['rows'][$key]['weight']['#attributes']['class'] = array('weight');
+
+    // Build the table row.
+    $row = array('');
+    $row[] = array('data' => drupal_render($form['rows'][$key]['name']));
+    $row[] = array('data' => drupal_render($form['rows'][$key]['title']));
+    $row[] = array('data' => drupal_render($form['rows'][$key]['hint']));
+    foreach (element_children($form['rows'][$key]['checkboxes']) as $oid) {
+      if (is_array($form['rows'][$key]['checkboxes'])) {
+        $row[] = array(
+          'data' => drupal_render($form['rows'][$key]['checkboxes'][$oid]),
+          'title' => $oid);
+      }
+    }
+
+
+    $row[] = drupal_render($form['rows'][$key]['weight']);
+    $rows[] = array('data' => $row, 'class' => array('draggable'));
+  }
+  $output = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => $form['#id'])));
+  $output .= drupal_render_children($form);
+  return $output;
+
+}
+/**
+ * @param $form
+ * @return unknown_type
+ */
+function theme_biblio_admin_types_edit_form($variables) {
+  $form = $variables['form'];
+  $output = '';
+
+  $output .= drupal_render($form['help']);
+  $output .= drupal_render($form['pub_type']);
+  $output .= drupal_render($form['change_type']);
+  if (isset($form['type_name'])) {
+    $output .= drupal_render($form['type_name']);
+  }
+  $output .= drupal_render($form['biblio_tabs']);
+  $output .= drupal_render_children($form);
+  return $output;
+}
+
+function theme_biblio_download_links($variables) {
+  static $langcode = NULL;
+  $file_links = array();
+  $node = $variables['node'];
+  if (!isset($langcode)) {
+    $langcode = $GLOBALS['language_content']->language;
+  }
+
+  $fields = field_attach_view('node', $node, 'full', $langcode);
+  foreach (element_children($fields) as $field) {
+    if($fields[$field]['#access']  && $fields[$field]['#field_type'] == 'file') {
+      foreach ($fields[$field]['#items'] as $delta => $item) {
+        if (module_exists('filefield_paths')) {
+          $alias =  drupal_get_path_alias('filefield_paths/alias/' . $item['fid']);
+        }
+        $link_type = variable_get('biblio_file_link_type', 'text');
+        if ($link_type == 'icon') {
+          $url = file_create_url($item['uri']);
+          $icon = theme('file_icon', array('file' => (object) $item));
+          $options['html'] = TRUE;
+          $options['attributes']['title'] = check_plain($item['filename']);
+          $file_links[] = array(
+              l($icon, $url, $options),
+              format_size($item['filesize']),
+          );
+        }
+        elseif ($link_type == 'text') {
+          $file_links[] = array(
+              theme('file_link', array('file' => (object) $item)),
+              format_size($item['filesize']),
+          );
+        }
+      }
+    }
+  }
+  $files = '';
+  if (count($file_links) > 0 && (user_access('show download links') || user_access('show own download links'))) {
+    $files .= '<span class="biblio_file_links">';
+   // $files .= '&nbsp;' . t('Download') . ':&nbsp;';
+    $file_count = 0;
+    foreach ($file_links as $file) {
+        $files .= $file[0] . '&nbsp;(' . $file[1] . ')';
+
+    }
+    $files .= '</span>';
+  }
+
+  return $files;
+}
+
+/**
+ * Creates a group of links for the various export functions
+ * @param $nid the node id to export (if omitted, all nodes in the current view will be exported
+ * @return an un-ordered list of class "biblio-export-buttons"
+ */
+function theme_biblio_export_links($variables) {
+  global $pager_total_items;
+  $node = $variables['node'];
+  $filter = ($variables['node'] == NULL && isset($variables['filter'])) ? $variables['filter'] : array();
+  $links = array();
+  $output = '';
+
+  if (biblio_access('export')) {
+    $show_link = variable_get('biblio_lookup_links', array('google' => TRUE));
+    $lookup_links = module_invoke_all('biblio_lookup_link', $node);
+    if ($show_link['google'] && !empty($node)) {
+      $lookup_links['biblio_google_scholar'] = theme('google_scholar_link', array('node' => $node));
+    }
+    $nid = (isset($node->nid)) ? $node->nid : NULL;
+    $export_links = module_invoke_all('biblio_export_link', $nid, $filter);
+    $links = array_merge($lookup_links, $export_links);
+  }
+  if (empty($node) && !empty($links)) {
+    $output = t('Export @count results', array('@count' => $pager_total_items[0])) . ': ';
+  }
+
+  return $output . theme('links', array('links' => $links, 'attributes' => array('class' => array('biblio-export-buttons'))));
+}
+
+
+function theme_google_scholar_link($variables) {
+  $node = $variables['node'];
+  $query = array();
+
+  $query['btnG'] = 'Search+Scholar';
+  $query['as_q'] = '"' . str_replace(array(' ', '(', ')'), array('+'), $node->title) . '"'; // as_q = all the words
+  if (isset($node->biblio_contributors[0]['lastname'])) {
+    $query['as_sauthors'] = $node->biblio_contributors[0]['lastname'];
+  }
+  $query['as_occt'] = 'any';
+  $query['as_epq'] = ''; // exact phrase
+  $query['as_oq'] = ''; // at least one of the words
+  $query['as_eq'] = ''; // without the words
+  $query['as_publication'] = ''; // published in
+  $query['as_ylo'] = ''; // lower date in date range
+  $query['as_yhi'] = ''; // upper date in date range
+  $query['as_sdtAAP'] = 1; //Search articles in all subject areas
+  $query['as_sdtp'] = 1; //include patents
+
+  $attrs = array('title' => t("Click to search Google Scholar for this entry"));
+  if (variable_get('biblio_links_target_new_window', NULL)){
+    $attrs = array_merge($attrs, array('target '=> '_blank'));
+  }
+
+  $attrs = array_merge($attrs, array('rel' => 'nofollow'));
+
+  return array(
+        'title'      => t('Google Scholar'),
+        'href'       => 'http://scholar.google.com/scholar',
+        'attributes' => $attrs,
+        'query'      => $query,
+  );
+}
+
+/**
+ * @param $form
+ * @return unknown_type
+ */
+function theme_biblio_contributors($variables) {
+  $form = $variables['form'];
+  $rows = array();
+  $headers = array('', t('Name'), t('Category'), t('Role'), t('Weight'));
+  drupal_add_tabledrag($form['#id'], 'order', 'sibling', 'rank');
+
+  foreach (element_children($form) as $key) {
+    // No need to print the field title every time.
+//    unset($form[$key]['name']['#title'], $form[$key]['auth_type']['#title'], $form[$key]['auth_category']['#title']);
+    // Add class to group weight fields for drag and drop.
+    $form[$key]['rank']['#attributes']['class'] = array('rank');
+
+    // Build the table row.
+    $row = array('');
+    $row[] = array('data' => drupal_render($form[$key]['name']),
+                   'class' => array('biblio-contributor'));
+    $row[] = array('data' => drupal_render($form[$key]['auth_category']),
+                     'class' => array('biblio-contributor-category'));
+    $row[] = array('data' => drupal_render($form[$key]['auth_type']),
+                     'class' => array('biblio-contributor-type'));
+    $row[] = drupal_render($form[$key]['rank']);
+    $rows[] = array('data' => $row, 'class' => array('draggable'));
+  }
+  $output = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => $form['#id'])));
+  //$output .= drupal_render_children($form);
+  return $output;
+}
+
+/**
+ * This function creates a string of letters (A - Z), which
+ * depending on the sorting are either linked to author or title
+ * filters i.e. clicking on the A when in the listing is sorted by
+ * authors will bring up a list of all the entries where the first
+ * character of the primary authors last name is "A"
+ *
+ * @param $type either "author or title"
+ * @return a chunk of HTML code as described above
+ */
+function theme_biblio_alpha_line($variables) {
+  $type    = $variables['type'];
+  $all = '';
+  $uri = drupal_parse_url(request_path());
+
+  //replace path in case we are in a multi-language environment, otherwise we end up with double language prefixes.
+  $languages =  language_list('enabled');
+  if (isset($languages[1])) {
+    $path_parts = empty($uri['path']) ? array() : explode('/', $uri['path']);
+    foreach ($languages[1] as $code => $lang) {
+      if ($path_parts[0] == $code) {
+        array_shift($path_parts);
+        break;
+      }
+    }
+    $uri['path'] = implode('/', $path_parts);
+  }
+
+  $uri['attributes'] = array('rel' => 'nofollow');
+  $all_uri = $uri;
+  $current = '';
+
+  switch ($type) {
+    case 'authors':
+      $filter = 'author';
+      $current = isset($uri['query']['f']['author']) ? $uri['query']['f']['author'] : '';
+      unset($all_uri['query']['f']['author']);
+      break;
+    case 'keywords':
+    case 'keyword':
+      $filter = 'keyword';
+      $current = isset($uri['query']['f']['keyword']) ? $uri['query']['f']['keyword'] : '';
+      unset($all_uri['query']['f']['keyword']);
+      break;
+    case 'author':
+      $current = isset($uri['query']['f']['ag']) ? $uri['query']['f']['ag'] : '';
+      $filter = 'ag';
+      if (!isset($uri['query']['s'])) $uri['query']['s'] = 'author';
+      unset($all_uri['query']['f']['ag']);
+      break;
+    case 'title':
+      $current = isset($uri['query']['f']['tg']) ? $uri['query']['f']['tg'] : '';
+      $filter = 'tg';
+      unset($all_uri['query']['f']['tg']);
+      break;
+    default:
+  }
+  $output = '<div class="biblio-alpha-line">';
+//TODO   for Cyrillic use 1040 to 1071... e.g. &#1068;
+
+  for ($i = 65; $i <= 90; $i++) {
+    if ($i == ord($current)) {
+      $output .= '<b>[' . chr($i) . ']</b>&nbsp;';
+    }
+    else{
+      $uri['query']['f'][$filter] =  chr($i);
+      $output .= l(chr($i), $uri['path'], $uri) . '&nbsp;';
+    }
+  }
+  if ($current) {
+    if (empty($all_uri['query']['f'])) unset($all_uri['query']['f']);
+    $output .= '&nbsp;&nbsp;' . '[' . l(t('Show ALL'), $all_uri['path'], $all_uri) . ']';
+  }
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Themes the author editing form
+ *
+ * @param $form
+ * @return rendered form
+ */
+function theme_biblio_admin_author_edit_form($variables) {
+  $form = $variables['form'];
+  $rows = array();
+  $rows[] = array(
+            array('data' => drupal_render($form['prefix'])),
+            array('data' => drupal_render($form['firstname'])),
+            array('data' => drupal_render($form['initials'])),
+            array('data' => drupal_render($form['lastname'])),
+            array('data' => drupal_render($form['suffix'])));
+  $rows[] = array(array('data' => drupal_render($form['name']) . drupal_render($form['literal']), 'colspan' => 5));
+  $rows[] = array(array('data' => drupal_render($form['affiliation']), 'colspan' => 5));
+  $rows[] = array(array('data' => drupal_render($form['drupal_uid']), 'colspan' => 5));
+
+  $output = theme('table', array('rows' => $rows));
+  $output .= drupal_render($form['merge']);
+  $output .= drupal_render($form['link']);
+  $output .= drupal_render_children($form);
+  return $output;
+
+}
+
+function theme_biblio_admin_author_edit_merge_table($variables) {
+  $form = $variables['form'];
+  $headers = $form['#header'];
+  $rows = array();
+
+  foreach (element_children($form['candidates']) as $key) {
+
+    // Build the table row.
+    $row = array();
+    $row[] = array('data' => drupal_render($form['candidates'][$key]['name']));
+    $row[] = drupal_render($form['candidates'][$key]['link']);
+    $row[] = drupal_render($form['candidates'][$key]['merge']);
+    $row[] = drupal_render($form['candidates'][$key]['retain']);
+    $rows[] = $row;
+  }
+
+  $output = theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => $form['#id'])));
+
+  $row = $rows = array();
+  $row[] = array('data' => drupal_render($form['more_authors_search']) . drupal_render($form['more_authors_add']));
+  $rows[] = $row;
+  $output .= theme('table', array('header' => array(), 'rows' => $rows, 'attributes' => array('id' => $form['#id'])));
+
+  $output .= drupal_render_children($form);
+
+  return $output;
+}
+
+function _biblio_keyword_links($keywords, $base='biblio') {
+  $uri = drupal_parse_url(request_uri());
+  $uri['path'] = variable_get('biblio_base', 'biblio');;
+  $uri['attributes'] = array('rel' => 'nofollow');
+  $html = "";
+  if (!is_array($keywords)) {
+    require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.keywords.inc');
+    $keywords = biblio_explode_keywords($keywords);
+  }
+
+  $sep = variable_get('biblio_keyword_sep', ',');
+  foreach ($keywords as $kid => $keyword ) {
+    $uri['query']['f']['keyword'] = $kid;
+    $linked_keywords [] = l(trim($keyword), $base , $uri);
+  }
+  return implode("$sep ", $linked_keywords);
+}
+
+
+function template_preprocess_biblio_sort_tabs(&$vars) {
+  $vars['tabs_style'] = variable_get('biblio_sort_tabs_style', 0);
+
+  $uri = drupal_parse_url(request_uri());
+  $uri['path'] = $_GET['q'];
+  $uri['path'] = trim($uri['path'], '/');
+
+  $defaults = array(
+    'author' => 'asc',
+    'title' => 'asc',
+    'type' => 'asc',
+    'year' => 'desc',
+    'keyword' => 'asc',
+  );
+
+  if (isset($uri['query']['s'])) {
+    $sort = $uri['query']['s'];
+  }
+  else {
+    $sort = variable_get('biblio_sort', 'year');
+  }
+
+  if (isset($uri['query']['o'])) {
+    $order = strtolower($uri['query']['o']);
+  }
+  else {
+    $order = strtolower(variable_get('biblio_order', 'desc'));
+  }
+  // flip it
+  $order = ($order == 'desc') ? 'asc' : 'desc';
+  $path = drupal_get_path('module', 'biblio');
+  $order_arrow = ($order == 'asc') ? theme('image', array('path' => $path.'/misc/arrow-asc.png', 'alt' => '(Asc)')):
+                                     theme('image', array('path' => $path.'/misc/arrow-desc.png', 'alt' => '(Desc)'));
+
+  $sort_links =  array_filter(variable_get('biblio_sort_tabs', array('author' => 'author', 'title' => 'title', 'type' => 'type', 'year' => 'year', 'keyword' => 'keyword')));
+  ksort($sort_links);
+
+  $links = array();
+  foreach ($sort_links as $key => $title) {
+    $uri_copy = $uri;
+    $uri_copy['attributes'] = array("title" => t("Click a second time to reverse the sort order"));
+    $uri_copy['html'] = TRUE;
+    $uri_copy['text'] = t(ucfirst($title));
+    $uri_copy['query']['s'] = $title;
+    if ($key === $title && $title == $sort) {
+      $uri_copy['query']['o'] = $order;
+      $uri_copy['attributes']['class'][] = "active";
+      $uri_copy['active'] = TRUE;
+      $uri_copy['pfx'] = ' [ ';
+      $uri_copy['sfx'] = '] ';
+      $uri_copy['arrow'] = $order_arrow;
+
+    }
+    elseif ($key === $title ) {
+      $uri_copy['query']['o'] = $defaults[$title];
+      $uri_copy['active'] = FALSE;
+      $uri_copy['pfx'] = ' ';
+      $uri_copy['sfx'] = ' ';
+      $uri_copy['arrow'] = '';
+    }
+    $links[] = $uri_copy;
+  }
+  $vars['links'] = $links;
+}
+
+function theme_biblio_sort_tabs($vars) {
+  $links = $vars['links'];
+  $style = $vars['tabs_style'];
+  $output = '';
+
+  if ($style) {
+    $output = '<ul class="tabs secondary">';
+  }
+  foreach ($links as $l) {
+    $output .= _biblio_sort_tab($l, $style);
+  }
+
+  if ($style) {
+    $output .= '</ul>';
+  }
+
+  return $output;
+}
+
+function _biblio_sort_tab($tab, $tabs = FALSE) {
+  if ($tabs) {
+    $text  = '<span class="a"><span class="b">' . $tab['text'] . $tab['arrow'] . '</span></span>';
+    $class = ($tab['active']) ? 'class="active"':'';
+    $link  = l($text, $tab['path'], $tab);
+    return "<li $class >". $link . '</li>';
+  }
+  else {
+    return $tab['pfx'] . l($tab['text'], $tab['path'], $tab) . $tab['arrow'] . $tab['sfx'];
+  }
+  return;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/includes/biblio_xml.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,68 @@
+<?php
+/**
+ *
+ *   Copyright (C) 2006-2011  Ron Jerome
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License along
+ *   with this program; if not, write to the Free Software Foundation, Inc.,
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ ****************************************************************************/
+
+
+/**
+ * @param $result
+ * @return unknown_type
+ */
+function biblio_xml_export($result) {
+  set_time_limit(300);
+  $nid=0;
+  $dom = new DOMDocument('1.0', 'UTF-8');
+  $biblio_collection = $dom->appendChild(new DOMElement('biblio_collection'));
+  $biblio_collection->setAttribute("Schema", "6010");
+  $comment = $biblio_collection->appendChild(new DOMComment('Generated by the Biblio module from Drupal (http://drupal.org/project/biblio)'));
+  $db_result = db_query("SELECT nr.nid, nr.vid  FROM {node_revision} nr join node n on nr.nid=n.nid where n.type='biblio' order by nr.nid, nr.vid");
+  while($n=db_fetch_object($db_result)) {
+    $node = node_load($n->nid,$n->vid);
+    if ($n->nid == $nid) {
+      $revision = $domnode->appendChild(new DOMElement('revision'));
+      $node = (array)$node;
+      AtoX($node, $dom, $revision);
+    }else{
+      $domnode = $biblio_collection->appendChild(new DOMElement('node'));
+      $node = (array)$node;
+      AtoX($node, $dom, $domnode);
+    }
+    $nid = $n->nid;
+
+  }
+  return $dom->saveXML();
+}
+
+function AtoX($array, $DOM=null, $root=null) {
+  foreach ($array as $key => $value) {
+    if ($key == 'biblio_contributors') $name = 'contributor';
+    if (is_numeric($key)) $key = 'c_' . $key;
+    if (is_array($value ) && count($value)) {
+      $subroot = $root->appendChild($DOM->createElement($key));
+      AtoX($value, $DOM, $subroot);
+    }
+    else {
+      if (!empty($value)) {
+        $root->appendChild($DOM->createElement($key, htmlspecialchars($value, ENT_QUOTES)));
+      }
+    }
+  }
+
+  return $DOM;
+}
Binary file sites/all/modules/biblio/misc/arrow-asc.png has changed
Binary file sites/all/modules/biblio/misc/arrow-desc.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/misc/biblio.field.link.data.csv	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,54 @@
+fid,title,hint, common, autocomplete, required, weight, visible,field name,type,width,maxlength,vtab
+1,Authors,,1,1,1,1,1,biblio_authors,contrib_widget,60,255,1
+2,Secondary Authors,,1,1,1,2,1,biblio_secondary_authors,contrib_widget,60,255,1
+3,Tertiary Authors,,1,1,1,3,1,biblio_tertiary_authors,contrib_widget,60,255,1
+4,Subsidiary Authors,,1,1,1,4,1,biblio_subsidiary_authors,contrib_widget,60,255,1
+5,Corporate Authors,,1,1,1,5,1,biblio_corp_authors,contrib_widget,60,255,1
+6,Secondary Title,,0,0,0,12,0,biblio_secondary_title,textfield,60,255,2
+7,Tertiary Title,,0,0,0,13,0,biblio_tertiary_title,textfield,60,255,8
+8,Accession Number,,1,0,0,151,1,biblio_accession_number,textfield,24,128,4
+9,ISBN Number,,1,0,0,150,1,biblio_isbn,textfield,24,128,4
+10,Call Number,,1,0,0,152,1,biblio_call_number,textfield,24,128,4
+11,Other Numbers,,1,0,0,153,1,biblio_other_number,textfield,10,128,4
+12,Other Author Affiliations,,0,0,0,24,0,biblio_other_author_affiliations,textfield,60,255,9
+13,Publisher,,0,0,0,19,0,biblio_publisher,textfield,60,255,3
+14,Place Published,,0,0,0,20,0,biblio_place_published,textfield,60,255,3
+15,Year of Publication,"Enter YYYY, Submitted or In Press",1,0,1,-45,1,biblio_year,textfield,4,20,2
+16,Edition,,0,0,0,15,0,biblio_edition,textfield,60,255,2
+17,Volume,,0,0,0,14,0,biblio_volume,textfield,10,128,2
+18,Number,,0,0,0,16,0,biblio_number,textfield,10,128,2
+19,Pagination,,0,0,0,17,0,biblio_pages,textfield,24,128,2
+20,Date Published,(mm/yyyy),0,0,0,18,0,biblio_date,textfield,16,16,2
+21,Publication Language,,0,0,0,23,0,biblio_lang,textfield,24,24,2
+22,Abstract,,1,0,0,155,1,biblio_abst_e,text_format,60,65535,1
+23,French Abstract,,0,0,0,156,0,biblio_abst_f,text_format,60,65535,9
+24,Keywords,,1,1,0,154,0,biblio_keywords,textfield,60,1000,6
+25,Type of Work,Masters Thesis,0,0,0,22,0,biblio_type_of_work,textfield,60,255,2
+26,URL,,1,0,0,158,1,biblio_url,textfield,60,255,5
+27,Notes,,0,0,0,157,0,biblio_notes,text_format,60,65535,7
+28,Issue,,0,0,0,15,0,biblio_issue,textfield,10,128,2
+29,Reseach Notes,,0,0,0,160,0,biblio_research_notes,text_format,60,65535,7
+30,Custom 1,,0,0,0,161,0,biblio_custom1,text_format,60,65535,9
+31,Custom 2,,0,0,0,162,0,biblio_custom2,text_format,60,65535,9
+32,Custom 3,,0,0,0,163,0,biblio_custom3,text_format,60,65535,9
+33,Custom 4,,0,0,0,164,0,biblio_custom4,text_format,60,65535,9
+34,Custom 5,,0,0,0,165,0,biblio_custom5,text_format,60,65535,9
+35,Custom 6,,0,0,0,167,0,biblio_custom6,text_format,60,65535,9
+36,Custom 7,,0,0,0,168,0,biblio_custom7,text_format,60,65535,9
+37,Number of Volumes,,0,0,0,15,0,biblio_number_of_volumes,textfield,10,128,2
+38,Short Title,,0,0,0,169,0,biblio_short_title,textfield,60,255,8
+39,Alternate Title,,0,0,0,170,0,biblio_alternate_title,textfield,60,255,8
+40,Translated Title,,0,0,0,170,0,biblio_translated_title,textfield,60,255,8
+41,Original Publication,,0,0,0,171,0,biblio_original_publication,textfield,60,255,8
+42,Reprint Edition,,0,0,0,172,0,biblio_reprint_edition,textfield,120,255,2
+43,Section,,0,0,0,15,0,biblio_section,textfield,10,128,2
+44,Citation Key,,0,0,0,175,0,biblio_citekey,textfield,16,255,4
+45,COinS Data,This will be automatically generated,0,0,0,176,0,biblio_coins,text_format,60,65535,9
+46,ISSN Number,,0,0,0,150,0,biblio_issn,textfield,24,128,4
+47,DOI,,1,0,0,159,1,biblio_doi,textfield,60,255,5
+48,Author Address,,0,0,0,178,0,biblio_auth_address,text_format,60,65535,9
+49,Remote Database Name,,0,0,0,176,0,biblio_remote_db_name,textfield,60,255,9
+50,Remote Database Provider,,0,0,0,177,0,biblio_remote_db_provider,textfield,60,255,9
+51,Label,,0,0,0,178,0,biblio_label,textfield,60,255,9
+52,Access Date,,0,0,0,179,0,biblio_access_date,textfield,60,255,9
+53,Refereed Designation,,0,0,0,180,0,biblio_refereed,select,0,128,9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/misc/biblio.field.type.data.csv	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,40 @@
+,tid,biblio_year,title,biblio_secondary_title,biblio_tertiary_title,biblio_short_title,biblio_secondary_authors,biblio_tertiary_authors,biblio_subsidiary_authors,biblio_corp_authors,biblio_alternate_title,biblio_place_published,biblio_publisher,biblio_volume,biblio_number_of_volumes,biblio_number,biblio_issue,biblio_pages,biblio_section,biblio_edition,biblio_date,biblio_type_of_work,biblio_issn,,biblio_original_publication,biblio_reprint_edition,,biblio_custom1,biblio_custom2,biblio_custom3,biblio_custom4,biblio_custom5,biblio_custom6,biblio_custom7,biblio_abst_e,biblio_refereed
+Generic ,,Year ,Title ,Secondary Title ,Tertiary Title ,Short Title ,Editor ,Tertiary Author ,Subsidiary Author ,Corporate Author,Alternate Title ,Place Published ,Publisher ,Volume ,Number of Volumes ,Number ,Issue,Pages ,Section ,Edition ,Date ,Type of Work ,ISBN/ISSN ,Electronic Resource Number ,Original Publication ,Reprint Edition ,Reviewed Item ,Custom 1 ,Custom 2 ,Custom 3 ,Custom 4 ,Custom 5 ,Custom 6 ,Custom 7 ,Abstract ,Refereed Designation
+Ancient Text ,,,,Publication Title ,Volume Title ,,Editor ,~,Translator ,,Abbreviated Publication ,City ,,,,,~,,~,,,,ISBN ,,,,Reviewed Item ,~,~,~,~,~,~,~,,
+Artwork ,112,,,~,~,,~,~,~,,,City ,,~,~,~,~,Description ,~,~,,,~,,~,~,,~,~,~,~,~,~,~,,
+Audiovisual Material ,114,,,Series Title ,~,,Series Editor ,~,Performers ,,,City ,,~,Extent of Work ,Number ,~,~,~,,,Type ,ISBN ,,Contents ,~,,Cast ,Credits ,~,~,Format ,~,~,,
+Bill ,117,,,Code ,Legislative Body ,,~,~,Sponsor ,,~,~,~,Code Volume ,~,Bill Number ,~,Code Pages ,Code Section ,Session ,,~,~,,History ,~,,~,~,~,~,~,~,~,,
+Book ,100,,,Series Title ,~,,Series Editor ,~,Translator ,,Abbreviation ,City ,,,,Series Volume ,~,Number of Pages ,~,,~,~,ISBN ,,,,~,~,~,~,~,~,~,~,,
+Book Section ,101,,,Book Title ,Series Title ,,Editor ,Series Editor ,Translator ,,Abbreviation ,City ,,,,Series Volume ,~,,Chapter ,,~,~,ISBN ,,,,,~,~,~,~,~,~,~,,
+Case ,116,,Case Name ,Reporter ,~,Abbreviated Case Name ,~,~,Counsel ,,~,~,Court ,Reporter Volume ,Reporter Abbreviation ,~,~,First Page ,Page Cited ,~,Date Decided ,~,~,,History ,~,~,~,~,~,~,~,~,~,,
+Classical Work ,127,,,Series Title ,~,,Series Editor ,~,Translator ,,,City ,,,,Series Volume ,~,Number of Pages ,~,,~,Type ,ISSN/ISBN ,,,,~,~,~,~,~,~,~,~,,
+Computer Program ,113,,,Series Title ,~,,Series Editor ,~,~,,,City ,,~,~,~,~,Description ,~,Version ,~,Type ,ISBN ,,Contents ,~,~,Computer ,~,~,~,~,~,~,,
+Conference Paper ,103,,,Conference Name ,~,~,Editor ,~,~,,~,Conference Location ,,~,~,~,~,~,~,~,,~,~,,~,~,~,~,~,~,~,~,~,~,,
+Conference Proceeding ,104,Year of Conference ,,Conference Name ,Series Title ,,Editor ,Series Editor ,Sponsor ,,~,Conference Location ,,,,~,~,,~,,,~,ISBN ,,~,~,~,~,~,~,~,~,~,~,,
+Chart or Table ,123,,,Image Source Program ,Name of File ,~,~,~,~,,~,City ,,Image Size ,~,,~,Description ,~,Version ,,Type of Image ,~,,~,~,~,~,~,~,~,~,~,~,,
+Dictionary ,,,,Dictionary Title ,~,,Editor ,~,Translator ,,Abbreviation ,City ,,,,,~,,~,,~,~,ISBN ,,,,,~,~,~,~,~,~,~,,
+Edited Book ,,,,Series Title ,~,,Series Editor ,~,Translator ,,,City ,,,,Series Volume ,~,Number of Pages ,~,,~,~,ISBN ,,,,,~,~,~,~,~,~,~,,
+Electronic Article ,,,,Periodical Title ,~,~,,~,~,,,~,~,,~,~,,,~,~,Date Accessed ,~,ISSN ,,~,~,~,~,~,~,~,~,~,~,,
+Electronic Book ,,,,Secondary Title ,~,~,Editor ,~,~,,~,~,,,~,~,~,~,~,~,Date Accessed ,Type of Medium ,ISBN ,,~,~,~,~,~,~,~,~,~,~,,
+Equation ,,,,Image Source Program ,Name of File ,~,~,~,~,,~,City ,,Image Size ,~,,~,Description ,~,Version ,,Type of Image ,~,,~,~,~,~,~,~,~,~,~,~,,
+Encyclopedia ,,,,Encyclopedia Title ,~,,Editor ,~,Translator ,,Abbreviation ,City ,,,,~,~,,~,,,~,ISBN ,,,,,~,~,~,~,~,~,~,,
+Figure ,,,,Image Source Program ,Name of File ,~,~,~,~,,~,City ,,Image Size ,~,,~,Description ,~,Version ,,Type of Image ,~,,~,~,~,~,~,~,~,~,~,~,,
+Film or Broadcast ,110,Year Released ,,Series Title ,~,,Series Director ,Producer ,Performers ,,,Country ,,~,~,~,~,Running Time ,~,,Date Released ,Medium ,~,,~,~,~,Cast ,Credits ,~,Genre ,Format ,~,~,Synopsis ,
+Government Document ,126,,,~,Series Title ,~,Department ,~,~,,~,~,,,~,~,,,Section ,,~,~,Report Number ,,~,~,~,Government Body ,Congress Number ,Congress Session ,~,~,~,~,,
+Grant ,,,Title of Grant ,~,~,,~,~,Translator ,,Abbreviation ,Activity Location ,Sponsoring Agency ,Amount Requested ,Amount Received ,Status ,~,,Duration of Grant ,Requirements ,Deadline ,Funding Type ,~,,Original Grant Number ,Review Date ,,Contact Name ,Contact Address ,Contact Phone ,Contact Fax ,Funding Number ,CFDA Number ,~,,
+Hearing ,115,,,Committee ,Legislative Body ,,~,~,~,,~,City ,,~,,Document Number ,~,,~,Session ,,~,~,,History ,~,~,~,~,~,~,~,~,~,,
+Journal Article ,102,,,Journal ,~,,~,~,~,,Alternate Journal ,~,~,,~,~,,,Start Page ,~,,Type of Article ,ISSN ,,,Reprint Edition ,,~,~,~,~,~,~,~,,
+Legal Rule or Regulation ,128,,,~,~,~,~,~,~,Issuing Organization ,Abbreviation ,~,,Rule Number ,Session Number ,Start Page ,~,,Section Number ,,Date of Code Edition ,,Document Number ,,~,~,~,~,~,~,~,~,~,~,,
+Magazine Article ,106,,,Magazine ,~,,~,~,~,,Alternate Magazine ,~,~,,Frequency ,Issue Number ,Issue Number ,,~,,,Type of Article ,ISSN ,,,,,~,~,~,~,~,~,~,,
+Manuscript ,121,,,Collection Title ,~,,~,~,~,,Abbreviation ,City ,Library/Archive ,Volume/Storage Container ,Manuscript Number ,Folio Number ,~,,~,~,,,~,,~,~,~,~,~,~,~,~,~,~,,
+Map ,122,,,Series Title ,~,,Series Editor ,~,~,,,City ,,~,~,~,~,Description ,~,,,Type ,ISBN ,,~,~,~,Scale ,~,~,~,~,~,~,,
+Newspaper Article ,105,,,Newspaper ,~,,~,~,~,,~,City ,~,,Frequency ,Start Page ,~,,Section ,,Issue Date ,Type of Article ,ISSN ,,Original Publication ,,Reviewed Item ,~,~,~,~,~,~,~,~,
+Online Database ,125,,,~,~,~,~,~,~,,~,~,Publisher ,~,~,~,~,~,~,~,Date Accessed ,~,~,,~,~,~,~,~,~,~,~,~,~,~,
+Online Multimedia ,,,,Series Title ,~,~,Series Editor ,~,~,,~,~,Distributor ,~,~,~,~,~,~,~,Date Accessed ,Type of Work ,~,,~,~,~,~,~,~,~,Format/Length ,,~,~,
+Patent ,119,,,Published Source ,International Title ,,~,International Author ,~,Issuing Organization ,~,Country ,Assignee ,Patent Version Number ,~,Application Number ,~,,International Patent Number ,International Patent Classification ,,Patent Type ,Patent Number ,,Priority Numbers ,~,~,~,Issue Date ,Designated States ,Attorney/Agent ,References ,Legal Status ,~,~,
+Personal Communication ,120,,,~,~,,Recipient ,~,~,,Abbreviation ,City ,,~,Communication Number ,Folio Number ,~,,~,Description ,,Type ,~,,~,~,~,~,~,~,~,~,~,~,,
+Report ,109,,,Series Title ,~,,Series Editor ,~,~,,,City ,Institution ,~,~,Document Number ,~,,~,~,,Type ,Report Number ,,Contents ,~,~,~,~,~,~,~,~,~,,
+Statute ,118,,Name of Act ,Code ,~,,~,~,~,,Abbreviation ,Country ,~,Code Number ,Statute Number ,Public Law Number ,~,,Sections ,Session ,Date Enacted ,~,~,,History ,~,~,~,~,~,~,~,~,~,,
+Thesis ,108,,,Academic Department ,~,,~,Advisor ,~,,~,City ,University ,Degree ,~,~,~,Number of Pages ,~,~,,Thesis Type ,~,,,~,~,,,,,,,,,
+Unpublished Work ,124,,Title of Work ,Series Title ,~,,~,~,~,,Abbreviation ,City ,Institution ,~,~,Number ,~,,~,~,,Type of Work ,~,,~,~,~,~,~,~,~,~,~,~,~,
+Web Page ,107,,,Series Title ,~,,Series Editor ,~,~,,,City ,Publisher ,Access Year ,~,Access Date ,~,Description ,~,,Last Update Date ,Type of Medium ,ISBN ,,Contents ,~,~,~,~,~,~,~,~,~,~,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/misc/biblio.highlight.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,9 @@
+(function ($) {
+  Drupal.behaviors.BiblioHighlight = {
+    attach: function (context, settings) {
+      $('input#biblio-highlight', context).click(function(e) {
+        $("div.suspect").toggleClass('biblio-highlight');
+      });
+    }
+  };
+}(jQuery));
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/misc/biblio.nodeformbuttonhide.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,5 @@
+(function ($, Drupal, window, document, undefined) {
+  $(document).ready(function() {
+    $("#edit-biblio-next").addClass("element-invisible");
+  });
+})(jQuery, Drupal, this, this.document);
\ No newline at end of file
Binary file sites/all/modules/biblio/misc/minus.png has changed
Binary file sites/all/modules/biblio/misc/plus-minus.png has changed
Binary file sites/all/modules/biblio/misc/plus.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/CSL.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1744 @@
+<?php
+/**
+ *   CiteProc-PHP
+ *
+ *   Copyright (C) 2010 - 2011  Ron Jerome, all rights reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License along
+ *   with this program; if not, write to the Free Software Foundation, Inc.,
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+class citeproc {
+  public    $bibliography;
+  public    $citation;
+  public    $style;
+  protected $macros;
+  private   $info;
+  protected $locale;
+  protected $style_locale;
+  public    $quash;
+  private   $mapper;
+
+  function __construct($csl = NULL, $lang = 'en') {
+    if ($csl) {
+      $this->init($csl, $lang);
+    }
+  }
+
+  function init($csl, $lang) {
+    $this->mapper = new csl_mapper();
+    $this->quash = array();
+
+    $csl_doc = new DOMDocument();
+
+    if ($csl_doc->loadXML($csl)) {
+
+      $style_nodes = $csl_doc->getElementsByTagName('style');
+      if ($style_nodes) {
+        foreach ($style_nodes as $style) {
+          $this->style = new csl_style($style);
+        }
+      }
+
+      $info_nodes = $csl_doc->getElementsByTagName('info');
+      if ($info_nodes) {
+        foreach ($info_nodes as $info) {
+          $this->info = new csl_info($info);
+        }
+      }
+
+      $this->locale = new csl_locale($lang);
+      $this->locale->set_style_locale($csl_doc);
+
+
+      $macro_nodes = $csl_doc->getElementsByTagName('macro');
+      if ($macro_nodes) {
+        $this->macros = new csl_macros($macro_nodes, $this);
+      }
+
+      $citation_nodes = $csl_doc->getElementsByTagName('citation');
+      foreach ($citation_nodes as $citation) {
+        $this->citation = new csl_citation($citation, $this);
+      }
+
+      $bibliography_nodes = $csl_doc->getElementsByTagName('bibliography');
+      foreach ($bibliography_nodes as $bibliography) {
+        $this->bibliography = new csl_bibliography($bibliography, $this);
+      }
+    }
+  }
+  function render($data, $mode = NULL) {
+    $text = '';
+    switch ($mode) {
+      case 'citation':
+        $text .=  (isset($this->citation))? $this->citation->render($data) : '';
+        break;
+      case  'bibliography':
+      default:
+        $text .=  (isset($this->bibliography))? $this->bibliography->render($data) : '';
+        break;
+    }
+    return $text;
+  }
+
+  function render_macro($name, $data, $mode) {
+    return $this->macros->render_macro($name, $data, $mode);
+  }
+
+  function get_locale($type, $arg1, $arg2 = NULL, $arg3 = NULL) {
+    return $this->locale->get_locale($type, $arg1, $arg2, $arg3);
+  }
+
+  function map_field($field) {
+    if ($this->mapper) {
+      return $this->mapper->map_field($field);
+    }
+    return ($field);
+  }
+  function map_type($field) {
+    if ($this->mapper) {
+      return $this->mapper->map_type($field);
+    }
+    return ($field);
+  }
+}
+
+class csl_factory {
+  public static function create($dom_node, $citeproc = NULL) {
+    $class_name =  'csl_' . str_replace('-', '_', $dom_node->nodeName);
+    if (class_exists($class_name)) {
+      return new $class_name($dom_node, $citeproc);
+    }
+    else {
+      return NULL;
+    }
+  }
+}
+
+class csl_collection {
+  protected  $elements = array();
+
+  function add_element($elem) {
+    if (isset($elem)) $this->elements[] = $elem;
+  }
+
+  function render($data, $mode = NULL) {}
+
+  function format($text) {return $text;}
+
+}
+
+class csl_element extends csl_collection {
+  protected $attributes = array();
+  protected $citeproc;
+
+  function __construct($dom_node = NULL, $citeproc = NULL) {
+
+    $this->citeproc   = &$citeproc;
+    $this->set_attributes($dom_node);
+    $this->init($dom_node, $citeproc);
+
+  }
+
+  function init($dom_node, $citeproc) {
+    if (!$dom_node) return;
+
+    foreach ($dom_node->childNodes as $node) {
+      if ($node->nodeType == 1) {
+        $this->add_element(csl_factory::create($node, $citeproc));
+      }
+    }
+  }
+
+  function __set($name, $value) {
+    $this->attributes[$name] = $value;
+  }
+
+  function __isset($name) {
+    return isset($this->attributes[$name]);
+  }
+
+  function __unset($name) {
+    unset($this->attributes[$name]);
+  }
+
+  function &__get($name = NULL) {
+    $null = NULL;
+    if (array_key_exists($name, $this->attributes)) {
+      return $this->attributes[$name];
+    }
+    if (isset($this->{$name})) {
+      return $this->{$name};
+    }
+    return $null;
+
+  }
+
+  function set_attributes($dom_node) {
+    $att = array();
+    $element_name = $dom_node->nodeName;
+    if (isset($dom_node->attributes->length)) {
+      for ($i=0; $i < $dom_node->attributes->length; $i++) {
+        $value = $dom_node->attributes->item($i)->value;
+        $name  = str_replace(' ', '_', $dom_node->attributes->item($i)->name);
+        if ($name == 'type' ) {
+          $value = $this->citeproc->map_type($value);
+        }
+
+        if (($name == 'variable'  || $name == 'is-numeric') && $element_name != 'label') {
+          $value = $this->citeproc->map_field($value);
+        }
+        $this->{$name}  = $value;
+      }
+    }
+  }
+
+  function get_attributes() {
+      return $this->attributes;
+  }
+
+  function get_hier_attributes() {
+    $hier_attr = array();
+    $hier_names = array('and', 'delimiter-precedes-last', 'et-al-min', 'et-al-use-first',
+                        'et-al-subsequent-min', 'et-al-subsequent-use-first', 'initialize-with',
+                        'name-as-sort-order', 'sort-separator', 'name-form', 'name-delimiter',
+                        'names-delimiter');
+    foreach ($hier_names as $name) {
+      if (isset($this->attributes[$name])) {
+        $hier_attr[$name] = $this->attributes[$name];
+      }
+    }
+    return $hier_attr;
+  }
+
+  function name($name = NULL) {
+    if ($name) {
+      $this->name = $name;
+    }
+    else {
+      return str_replace(' ', '_', $this->name);
+    }
+  }
+
+}
+
+class csl_rendering_element extends csl_element {
+
+  function render($data, $mode = NULL) {
+    $text = '';
+    $text_parts = array();
+
+    $delim = $this->delimiter;
+    foreach ($this->elements as $element) {
+      $text_parts[] = $element->render($data, $mode);
+    }
+    $text = implode($delim, $text_parts); // insert the delimiter if supplied.
+
+    return $this->format($text);
+  }
+
+}
+
+class csl_format extends csl_rendering_element {
+  protected $no_op;
+  protected $format;
+
+  function __construct($dom_node = NULL, $citeproc = NULL) {
+    parent::__construct($dom_node, $citeproc);
+    $this->init_formatting();
+  }
+
+  function init_formatting() {
+    $this->no_op = TRUE;
+    $this->format  = '';
+    if (isset($this->quotes)  && strtolower($this->quotes) == "true") {
+      $this->quotes = array();
+      $this->quotes['punctuation-in-quote'] = $this->citeproc->get_locale('style_option', 'punctuation-in-quote');
+      $this->quotes['open-quote'] = $this->citeproc->get_locale('term', 'open-quote');
+      $this->quotes['close-quote'] = $this->citeproc->get_locale('term', 'close-quote');
+      $this->quotes['open-inner-quote'] = $this->citeproc->get_locale('term', 'open-inner-quote');
+      $this->quotes['close-inner-quote'] = $this->citeproc->get_locale('term', 'close-inner-quote');
+      $this->no_op = FALSE;
+    }
+    if (isset($this->{'prefix'})) $this->no_op = FALSE;
+    if (isset($this->{'suffix'})) $this->no_op = FALSE;
+    if (isset($this->{'display'})) $this->no_op = FALSE;
+
+    $this->format .= (isset($this->{'font-style'}))      ? 'font-style: ' . $this->{'font-style'} . ';' : '';
+    $this->format .= (isset($this->{'font-family'}))     ? 'font-family: ' . $this->{'font-family'} . ';' : '';
+    $this->format .= (isset($this->{'font-weight'}))     ? 'font-weight: ' . $this->{'font-weight'} . ';' : '';
+    $this->format .= (isset($this->{'font-variant'}))    ? 'font-variant: ' . $this->{'font-variant'} . ';' : '';
+    $this->format .= (isset($this->{'text-decoration'})) ? 'text-decoration: ' . $this->{'text-decoration'} . ';' : '';
+    $this->format .= (isset($this->{'vertical-align'}))  ? 'vertical-align: ' . $this->{'vertical-align'} . ';' : '';
+    // $this->format .= (isset($this->{'display'})  && $this->{'display'}  == 'indent')  ? 'padding-left: 25px;' : '';
+
+    if (isset($this->{'text-case'}) ||
+        !empty($this->format) ||
+        !empty($this->span_class) ||
+        !empty($this->div_class)) {
+          $this->no_op = FALSE;
+        }
+
+  }
+
+  function format($text) {
+
+    if (empty($text) || $this->no_op) return $text;
+    $quotes = $this->quotes;
+    $quotes = is_array($quotes) ? $quotes : array();
+
+    if (isset($this->{'text-case'})) {
+      switch ($this->{'text-case'}) {
+        case 'uppercase':
+          $text =  drupal_strtoupper($text);
+          break;
+        case 'lowercase':
+          $text = drupal_strtolower($text);
+          break;
+        case 'capitalize-all':
+        case 'title':
+          $text = mb_convert_case($text, MB_CASE_TITLE);
+          break;
+        case 'capitalize-first':
+          $text = drupal_ucfirst($text);
+          break;
+      }
+    }
+
+    $prefix = $this->prefix;
+    $prefix .= isset($quotes['open-quote']) ? $quotes['open-quote'] : '';
+    $suffix = $this->suffix;
+    if (isset($quotes['close-quote']) && !empty($suffix) && isset($quotes['punctuation-in-quote'])) {
+      if (strpos($suffix, '.') !== FALSE || strpos($suffix, ',') !== FALSE) {
+        $suffix =  $suffix . $quotes['close-quote'];
+      }
+    }
+    elseif (isset($quotes['close-quote'])) {
+      $suffix =  $quotes['close-quote'] . $suffix;
+    }
+    if (!empty($suffix)) { // gaurd against repeaded suffixes...
+      $no_tags = strip_tags($text);
+      if (strlen($no_tags) && ($no_tags[(strlen($no_tags) - 1)] == $suffix[0]) ) {
+        $suffix = substr($suffix, 1);
+      }
+    }
+
+    if (!empty($this->format) || !empty($this->span_class)) {
+      $style = (!empty($this->format)) ? 'style="' . $this->format . '"' : '';
+      $class = (!empty($this->span_class)) ? 'class="' . $this->span_class . '"' : '';
+      $text = '<span ' . implode(' ', array($class, $style)) . '>' . $text . '</span>';
+    }
+    $div_class = $div_style = '';
+    if (!empty($this->div_class)) {
+       $div_class = (!empty($this->div_class)) ? 'class="' . $this->div_class . '"' : '';
+    }
+    if ($this->display  == 'indent') {
+       $div_style =  'style="text-indent: 0px; padding-left: 45px;"';
+    }
+    if ($div_class || $div_style) {
+      return '<div ' . $div_class . $div_style . '>' . $prefix . $text . $suffix . '</div>';
+    }
+
+    return $prefix . $text . $suffix;
+  }
+
+}
+
+class csl_info {
+  public $title;
+  public $id;
+  public $authors = array();
+  public $links = array();
+
+  function __construct($dom_node) {
+    $name = array();
+    foreach ($dom_node->childNodes as $node) {
+      if ($node->nodeType == 1) {
+        switch ($node->nodeName) {
+          case 'author':
+          case 'contributor':
+            foreach ($node->childNodes as $authnode) {
+              if ($node->nodeType == 1) {
+                $name[$authnode->nodeName] = $authnode->nodeValue;
+              }
+            }
+            $this->authors[] = $name;
+            break;
+          case 'link':
+            foreach ($node->attributes as $attribute) {
+              $this->links[] = $attribute->value;
+            }
+            break;
+          default:
+            $this->{$node->nodeName} = $node->nodeValue;
+        }
+      }
+    }
+
+  }
+}
+
+class csl_terms {
+
+}
+
+class csl_name extends csl_format {
+  private $name_parts = array();
+  private $attr_init = FALSE;
+
+  function __construct($dom_node, $citeproc = NULL) {
+
+    $tags = $dom_node->getElementsByTagName('name-part');
+    if ($tags) {
+      foreach ($tags as $tag) {
+        $name_part = $tag->getAttribute('name');
+        $tag->removeAttribute('name');
+        for ($i=0; $i < $tag->attributes->length; $i++) {
+          $value = $tag->attributes->item($i)->value;
+          $name  = str_replace(' ', '_', $tag->attributes->item($i)->name);
+          $this->name_parts[$name_part][$name]  = $value;
+        }
+      }
+    }
+
+    parent::__construct($dom_node, $citeproc);
+  }
+
+  function init_formatting() {
+    $this->no_op = array();
+    $this->format = array();
+    $this->base = $this->get_attributes();
+    $this->format['base']  = '';
+    $this->format['family']  = '';
+    $this->format['given']  = '';
+    $this->no_op['base'] = TRUE;
+    $this->no_op['family'] = TRUE;
+    $this->no_op['given'] = TRUE;
+
+    if (isset($this->prefix)) {
+      $this->no_op['base'] = FALSE;
+    }
+    if (isset($this->suffix)) {
+      $this->no_op['base'] = FALSE;
+    }
+    $this->init_format($this->base);
+
+
+    if (!empty($this->name_parts)) {
+      foreach ($this->name_parts as $name => $formatting) {
+        $this->init_format($formatting, $name);
+      }
+    }
+  }
+
+  function init_attrs($mode) {
+ //   $and = $this->get_attributes('and');
+    if (isset($this->citeproc)) {
+      $style_attrs = $this->citeproc->style->get_hier_attributes();
+      $mode_attrs = $this->citeproc->{$mode}->get_hier_attributes();
+      $this->attributes = array_merge($style_attrs, $mode_attrs, $this->attributes);
+    }
+    if (isset($this->and)) {
+      if ($this->and == 'text') {
+        $this->and = $this->citeproc->get_locale('term', 'and');
+       }
+       elseif ($this->and == 'symbol') {
+        $this->and = '&';
+       }
+    }
+    if (!isset($this->delimiter)) {
+      $this->delimiter =  $this->{'name-delimiter'} ;
+    }
+    if (!isset($this->alnum)) {
+      list($this->alnum, $this->alpha, $this->cntrl, $this->dash,
+      $this->digit, $this->graph, $this->lower, $this->print,
+      $this->punct, $this->space, $this->upper, $this->word,
+      $this->patternModifiers) = $this->get_regex_patterns();
+    }
+    $this->dpl = $this->{'delimiter-precedes-last'};
+    $this->sort_separator = isset($this->{'sort-separator'}) ? $this->{'sort-separator'} : ', ';
+
+    $this->delimiter = isset($this->{'name-delimiter'}) ? $this->{'name-delimiter'} : (isset($this->delimiter) ? $this->delimiter : ', ');
+
+    $this->form = isset($this->{'name-form'}) ? $this->{'name-form'} : (isset($this->form) ? $this->form : 'long');
+    $this->attr_init = $mode;
+  }
+
+  function init_format($attribs, $part = 'base') {
+    if (!isset($this->{$part})) {
+      $this->{$part} = array();
+    }
+    if (isset($attribs['quotes']) && strtolower($attribs['quotes']) == 'true') {
+      $this->{$part}['open-quote'] = $this->citeproc->get_locale('term', 'open-quote');
+      $this->{$part}['close-quote'] = $this->citeproc->get_locale('term', 'close-quote');
+      $this->{$part}['open-inner-quote'] = $this->citeproc->get_locale('term', 'open-inner-quote');
+      $this->{$part}['close-inner-quote'] = $this->citeproc->get_locale('term', 'close-inner-quote');
+      $this->no_op[$part] = FALSE;
+    }
+
+    if (isset($attribs['prefix']))  $this->{$part}['prefix'] = $attribs['prefix'];
+    if (isset($attribs['suffix']))  $this->{$part}['suffix'] = $attribs['suffix'];
+
+    $this->format[$part] .= (isset($attribs['font-style']))      ? 'font-style: ' . $attribs['font-style'] . ';' : '';
+    $this->format[$part] .= (isset($attribs['font-family']))     ? 'font-family: ' . $attribs['font-family'] . ';' : '';
+    $this->format[$part] .= (isset($attribs['font-weight']))     ? 'font-weight: ' . $attribs['font-weight'] . ';' : '';
+    $this->format[$part] .= (isset($attribs['font-variant']))    ? 'font-variant: ' . $attribs['font-variant'] . ';' : '';
+    $this->format[$part] .= (isset($attribs['text-decoration'])) ? 'text-decoration: ' . $attribs['text-decoration'] . ';' : '';
+    $this->format[$part] .= (isset($attribs['vertical-align']))  ? 'vertical-align: ' . $attribs['vertical-align'] . ';' : '';
+
+    if (isset($attribs['text-case']))  {
+      $this->no_op[$part] = FALSE;
+      $this->{$part}['text-case'] = $attribs['text-case'];
+    }
+    if (!empty($this->format[$part])) $this->no_op[$part] = FALSE;
+
+  }
+
+  function format($text, $part = 'base') {
+
+    if (empty($text) || $this->no_op[$part]) return $text;
+    if (isset($this->{$part}['text-case'])) {
+      switch ($this->{$part}['text-case']) {
+        case 'uppercase':
+          $text =  drupal_strtoupper($text);
+          break;
+        case 'lowercase':
+          $text = drupal_strtolower($text);
+          break;
+        case 'capitalize-all':
+          $text = mb_convert_case($text, MB_CASE_TITLE);
+          break;
+        case 'capitalize-first':
+          $text = drupal_ucfirst($text);
+          break;
+      }
+    }
+    $open_quote = isset($this->{$part}['open-quote']) ? $this->{$part}['open-quote'] : '';
+    $close_quote = isset($this->{$part}['close-quote']) ? $this->{$part}['close-quote'] : '';
+    $prefix =  isset($this->{$part}['prefix']) ? $this->{$part}['prefix'] : '';
+    $suffix = isset($this->{$part}['suffix']) ? $this->{$part}['suffix'] : '';
+    if ($text[(strlen($text) -1)] == $suffix) unset($suffix);
+    if (!empty($this->format[$part])) {
+      $text = '<span style="' . $this->format[$part] . '">' . $text . '</span>';
+    }
+    return $prefix . $open_quote . $text . $close_quote . $suffix;
+  }
+
+  function author_link($author) {
+    $base = variable_get('biblio_base', 'biblio');
+    $options = array();
+
+    if (isset($_GET['sort'])) {
+      $options['query']['sort'] = $_GET['sort'];
+    }
+    if (isset($_GET['order'])) {
+      $options['query']['order'] = $_GET['order'];
+    }
+
+    $html = l(trim($author['name']), "$base/author/" . $author['cid'], $options );
+
+    return $html;
+  }
+
+  function render($names, $mode = NULL) {
+    $text = '';
+    $authors = array();
+    $count = 0;
+    $auth_count = 0;
+    $et_al_triggered = FALSE;
+
+    if (!$this->attr_init || $this->attr_init != $mode) $this->init_attrs($mode);
+
+    $initialize_with = $this->{'initialize-with'};
+    $options = array('html' => FALSE);
+
+    foreach ($names as $rank => $name) {
+      if (empty($name['literal'])) {
+        if (!isset($name['lastname'])) {
+          module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+          $name = biblio_parse_author($name); // this is needed for form preview to fill in all fields
+        }
+        $count++;
+        if (!empty($name['firstname']) && isset($initialize_with)) {
+          $name['firstname'] = preg_replace("/([$this->upper])[$this->lower]+/$this->patternModifiers", '\\1', $name['firstname']);
+          $name['firstname'] = preg_replace("/(?<=[-$this->upper]) +(?=[-$this->upper])/$this->patternModifiers", "", $name['firstname']);
+          $name['initials'] = $name['firstname'] . $name['initials'];
+        }
+        if (isset($name['initials'])) {
+          // within initials, remove any dots:
+          $name['initials'] = preg_replace("/([$this->upper])\.+/$this->patternModifiers", "\\1", $name['initials']);
+          // within initials, remove any spaces *between* initials:
+          $name['initials'] = preg_replace("/(?<=[-$this->upper]) +(?=[-$this->upper])/$this->patternModifiers", "", $name['initials']);
+          if (isset($this->citeproc->style)  && $this->citeproc->style->{'initialize-with-hyphen'} == 'false') {
+            $name['initials'] = preg_replace("/-/", '', $name['initials']);
+          }
+          // within initials, add a space after a hyphen, but only if ...
+          if (preg_match("/ $/", $initialize_with)) {// ... the delimiter that separates initials ends with a space
+            $name['initials'] = preg_replace("/-(?=[$this->upper])/$this->patternModifiers", "- ", $name['initials']);
+          }
+          // then, separate initials with the specified delimiter:
+          $name['initials'] = preg_replace("/([$this->upper])(?=[^$this->lower]+|$)/$this->patternModifiers", "\\1$initialize_with", $name['initials']);
+          //      $shortenInitials = (isset($options['numberOfInitialsToKeep'])) ? $options['numberOfInitialsToKeep'] : FALSE;
+          //      if ($shortenInitials) $given = drupal_substr($given, 0, $shortenInitials);
+          if (isset($initialize_with)) {
+            $name['firstname'] = $name['initials'];
+            // if ($shortenInitials) $name['firstname'] = drupal_substr($name['firstname'], 0, $shortenInitials);
+          }
+          elseif (!empty($name['firstname'])) {
+            $name['firstname'] = $name['firstname'] . ' ' . $name['initials'];
+          }
+          elseif (empty($name['firstname'])) {
+            $name['firstname'] = $name['initials'];
+          }
+        }
+        $given = $this->format($name['firstname'], 'given');
+        if (isset($name['lastname'])) {
+          if (!empty($name['prefix'])) {
+            $name['lastname'] = $name['prefix'] . ' ' . $name['lastname'];
+          }
+          if (!empty($name['suffix'])) {
+            $name['lastname'] = $name['lastname'] . ', ' . $name['suffix'];
+          }
+
+          $name['lastname'] = $this->format($name['lastname'], 'family');
+          if ($this->form == 'short') {
+            $text = $name['lastname'];
+          }
+          else {
+            switch ($this->{'name-as-sort-order'}) {
+              case 'first' && $rank == 0:
+              case 'all':
+                $text = $name['lastname'] . $this->sort_separator . $given;
+                break;
+              default:
+                $text = $given . ' ' . $name['lastname'] ;
+            }
+          }
+          $text = $this->format($text);
+          $name['name'] = $text;
+          if (strstr($text, 'div') || strstr($text, 'span')) {
+            $options = array('html' => TRUE);
+          }
+          else {
+            $options = array('html' => FALSE);
+          }
+        }
+      }
+      if (variable_get('biblio_author_links', 1)) {
+        $text = theme('biblio_author_link', array('author' => $name, 'options' => $options));
+      }
+
+      $authors[] = $text;
+
+      if (isset($this->{'et-al-min'}) && $count >= $this->{'et-al-min'}) break;
+    }
+    if (isset($this->{'et-al-min'}) &&
+      $count >= $this->{'et-al-min'} &&
+      isset($this->{'et-al-use-first'}) &&
+      $count >= $this->{'et-al-use-first'} &&
+      count($names) >  $this->{'et-al-use-first'}) {
+      if ($this->{'et-al-use-first'} < $this->{'et-al-min'}) {
+        for ($i = $this->{'et-al-use-first'}; $i < $count; $i++) {
+          unset($authors[$i]);
+        }
+      }
+      if ($this->etal) {
+        $etal = $this->etal->render();
+      }
+      else {
+        $etal = $this->citeproc->get_locale('term', 'et-al');
+      }
+      $et_al_triggered = TRUE;
+    }
+
+    if (!empty($authors) && !$et_al_triggered) {
+      $auth_count = count($authors);
+      if (isset($this->and) && $auth_count > 1) {
+        $authors[$auth_count-1] = $this->and . ' ' . $authors[$auth_count-1]; //stick an "and" in front of the last author if "and" is defined
+      }
+    }
+
+    $text = implode($this->delimiter, $authors);
+
+    if (!empty($authors) && $et_al_triggered) {
+      switch ($this->{'delimiter-precedes-et-al'}) {
+        case 'never':
+          $text = $text . " $etal";
+          break;
+        case 'always':
+          $text = $text . "$this->delimiter$etal";
+          break;
+        default:
+          $text = count($authors) == 1 ? $text . " $etal" : $text . "$this->delimiter$etal";
+      }
+    }
+
+   if ($this->form == 'count') {
+     if (!$et_al_triggered) {
+       return (int)count($authors);
+     }
+     else {
+       return (int)(count($authors) - 1);
+     }
+   }
+    // strip out the last delimiter if not required
+    if (isset($this->and) && $auth_count > 1) {
+      $last_delim =  strrpos($text, $this->delimiter . $this->and);
+      switch ($this->dpl) { //dpl == delimiter proceeds last
+        case 'always':
+          return $text;
+          break;
+        case 'never':
+          return substr_replace($text, ' ', $last_delim, strlen($this->delimiter));
+          break;
+        case 'contextual':
+        default:
+          if ($auth_count < 3) {
+            return substr_replace($text, ' ', $last_delim, strlen($this->delimiter));
+          }
+      }
+    }
+   return  $text ;
+  }
+
+  function get_regex_patterns() {
+    // Checks if PCRE is compiled with UTF-8 and Unicode support
+    if (!@preg_match('/\pL/u', 'a')) {
+      // probably a broken PCRE library
+      return $this->get_latin1_regex();
+    }
+    else {
+      // Unicode safe filter for the value
+      return $this->get_utf8_regex();
+    }
+  }
+
+  function get_latin1_regex() {
+    $alnum = "[:alnum:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 letters:
+    $alpha = "[:alpha:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 control characters:
+    $cntrl = "[:cntrl:]";
+    // Matches ISO-8859-1 dashes & hyphens:
+    $dash = "-–";
+    // Matches ISO-8859-1 digits:
+    $digit = "[\d]";
+    // Matches ISO-8859-1 printing characters (excluding space):
+    $graph = "[:graph:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 lower case letters:
+    $lower = "[:lower:]äåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 printing characters (including space):
+    $print = "[:print:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 punctuation:
+    $punct = "[:punct:]";
+    // Matches ISO-8859-1 whitespace (separating characters with no visual representation):
+    $space = "[\s]";
+    // Matches ISO-8859-1 upper case letters:
+    $upper = "[:upper:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆ";
+    // Matches ISO-8859-1 "word" characters:
+    $word = "_[:alnum:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Defines the PCRE pattern modifier(s) to be used in conjunction with the above variables:
+    // More info: <http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php>
+    $patternModifiers = "";
+
+    return array($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
+    $print, $punct, $space, $upper, $word, $patternModifiers);
+
+  }
+  function get_utf8_regex() {
+    // Matches Unicode letters & digits:
+    $alnum = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}"; // Unicode-aware equivalent of "[:alnum:]"
+    // Matches Unicode letters:
+    $alpha = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}"; // Unicode-aware equivalent of "[:alpha:]"
+    // Matches Unicode control codes & characters not in other categories:
+    $cntrl = "\p{C}"; // Unicode-aware equivalent of "[:cntrl:]"
+    // Matches Unicode dashes & hyphens:
+    $dash = "\p{Pd}";
+    // Matches Unicode digits:
+    $digit = "\p{Nd}"; // Unicode-aware equivalent of "[:digit:]"
+    // Matches Unicode printing characters (excluding space):
+    $graph = "^\p{C}\t\n\f\r\p{Z}"; // Unicode-aware equivalent of "[:graph:]"
+    // Matches Unicode lower case letters:
+    $lower = "\p{Ll}\p{M}"; // Unicode-aware equivalent of "[:lower:]"
+    // Matches Unicode printing characters (including space):
+    $print = "\P{C}"; // same as "^\p{C}", Unicode-aware equivalent of "[:print:]"
+    // Matches Unicode punctuation (printing characters excluding letters & digits):
+    $punct = "\p{P}"; // Unicode-aware equivalent of "[:punct:]"
+    // Matches Unicode whitespace (separating characters with no visual representation):
+    $space = "\t\n\f\r\p{Z}"; // Unicode-aware equivalent of "[:space:]"
+    // Matches Unicode upper case letters:
+    $upper = "\p{Lu}\p{Lt}"; // Unicode-aware equivalent of "[:upper:]"
+    // Matches Unicode "word" characters:
+    $word = "_\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}"; // Unicode-aware equivalent of "[:word:]" (or "[:alnum:]" plus "_")
+    // Defines the PCRE pattern modifier(s) to be used in conjunction with the above variables:
+    // More info: <http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php>
+    $patternModifiers = "u"; // the "u" (PCRE_UTF8) pattern modifier causes PHP/PCRE to treat pattern strings as UTF-8
+    return array($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
+    $print, $punct, $space, $upper, $word, $patternModifiers);
+  }
+
+}
+
+class csl_names extends csl_format {
+  private $substitutes;
+
+  function init_formatting() {
+    $this->span_class = 'biblio-authors';
+    parent::init_formatting();
+
+  }
+
+  function init($dom_node, $citeproc) {
+    $etal = '';
+    $tag = $dom_node->getElementsByTagName('substitute')->item(0);
+    if ($tag) {
+      $this->substitutes = csl_factory::create($tag, $citeproc);
+      $dom_node->removeChild($tag);
+    }
+
+    $tag = $dom_node->getElementsByTagName('et-al')->item(0);
+    if ($tag) {
+      $etal = csl_factory::create($tag, $citeproc);
+      $dom_node->removeChild($tag);
+    }
+
+    $var = $dom_node->getAttribute('variable');
+    foreach ($dom_node->childNodes as $node) {
+      if ($node->nodeType == 1) {
+        $element = csl_factory::create($node, $citeproc);
+        if (($element instanceof csl_label)) $element->variable = $var;
+        if (($element instanceof csl_name) && $etal) {
+          $element->etal = $etal;
+        }
+        $this->add_element($element);
+      }
+    }
+  }
+
+  function render($data, $mode = NULL) {
+    $matches = array();
+    $variable_parts = array();
+
+    if (!isset($this->delimiter)) {
+      $style_delimiter = $this->citeproc->style->{'names-delimiter'};
+      $mode_delimiter = $this->citeproc->{$mode}->{'names-delimiter'};
+      $this->delimiter = (isset($mode_delimiter)) ? $mode_delimiter : (isset($style_delimiter) ? $style_delimiter : '');
+    }
+
+    $variables  = explode(' ', $this->variable);
+
+    foreach ($variables as $var) {
+      if (in_array($var, $this->citeproc->quash)) continue;
+      list($contributor, $category) = explode(':', $var);
+      if ((isset($data->{$contributor}) && !empty($data->{$contributor})) && $this->_get_category($data->{$contributor}, $category) ) {
+        $matches[] =  $var;
+      }
+    }
+
+    if (empty($matches)) { // we don't have any primary suspects, so lets check the substitutes...
+      if (isset($this->substitutes)) {
+        foreach ($this->substitutes->elements as $element) {
+          if (($element instanceof csl_names)) { //test to see if any of the other names variables has content
+            $sub_variables  = explode(' ', $element->variable);
+            foreach ($sub_variables as $var) {
+              list($contributor, $category) = explode(':', $var);
+              if ((isset($data->{$contributor}) && !empty($data->{$contributor})) && $this->_get_category($data->{$contributor}, $category)) {
+                $matches[] =  $var;
+                $this->citeproc->quash[] = $var;
+              }
+            }
+          }
+          else { // if it's not a "names" element, just render it
+            $text  = $element->render($data, $mode);
+            $this->citeproc->quash[] = isset($element->variable) ? $element->variable : $element->var;
+            if (!empty($text)) $variable_parts[] = $text;
+          }
+          if (!empty($matches)) break;
+        }
+      }
+    }
+
+    foreach ($matches as $var) {
+      if (in_array($var, $this->citeproc->quash) && in_array($var, $variables)) continue;
+      $text = '';
+      list($contributor, $category) = explode(':', $var);
+      if (!empty($contributor) && $authors = $this->_get_category($data->{$contributor}, $category)) {
+        foreach ($this->elements as $element) {
+          if (is_a($element, 'csl_label')) {
+            $element->variable = $this->_get_csl_name_variable($category);
+            $text .= $element->render($authors, $mode);
+          }
+          elseif (is_a($element, 'csl_name')) {
+            $text .= $element->render($authors, $mode);
+          }
+        }
+      }
+      if (!empty($text)) $variable_parts[] = $text;
+    }
+
+    if (!empty($variable_parts)) {
+      $text = implode($this->delimiter, $variable_parts);
+      return $this->format($text);
+    }
+
+    return ;
+  }
+
+  private function _get_category($contributors, $category) {
+    $authors = array();
+    foreach ($contributors as $author) {
+      if ($author['auth_category'] == $category) {
+        $authors[] = $author;
+      }
+    }
+    return count($authors) ? $authors : FALSE;
+  }
+
+  private function _get_csl_name_variable($category) {
+    switch ($category) {
+      case 1:
+        return 'author';
+        break;
+      case 2:
+        return 'editor';
+        break;
+      case 3:
+        return 'translator';
+        break;
+      default:
+    }
+  }
+}
+
+class csl_date extends csl_format {
+
+  function init($dom_node, $citeproc) {
+    $locale_elements = array();
+
+    if ($form = $this->form) {
+      $local_date = $this->citeproc->get_locale('date_options', $form);
+      $dom_elem = dom_import_simplexml($local_date[0]);
+      if ($dom_elem) {
+        foreach ($dom_elem->childNodes as $node) {
+          if ($node->nodeType == 1) {
+            $locale_elements[] = csl_factory::create($node, $citeproc);
+          }
+        }
+      }
+      foreach ($dom_node->childNodes as $node) {
+        if ($node->nodeType == 1) {
+          $element = csl_factory::create($node, $citeproc);
+
+          foreach ($locale_elements as $key => $locale_element) {
+            if ($locale_element->name == $element->name) {
+              $locale_elements[$key]->attributes = array_merge($locale_element->attributes, $element->attributes);
+              $locale_elements[$key]->format =  $element->format;
+              break;
+            }
+
+            else {
+              $locale_elements[] = $element;
+            }
+          }
+        }
+      }
+      if ($date_parts = $this->{'date-parts'}) {
+        $parts = explode('-', $date_parts);
+        foreach ($locale_elements as $key => $element) {
+          if (array_search($element->name, $parts) === FALSE) {
+            unset($locale_elements[$key]);
+          }
+        }
+        if (count($locale_elements) != count($parts)) {
+          foreach ($parts as $part) {
+            $element = new csl_date_part();
+            $element->name = $part;
+            $locale_elements[] = $element;
+          }
+        }
+        // now re-order the elements
+        foreach ($parts as $part) {
+          foreach ($locale_elements as $key => $element)
+          if ($element->name == $part) {
+            $this->elements[] = $element;
+            unset($locale_elements[$key]);
+          }
+        }
+
+      }
+      else {
+        $this->elements = $locale_elements;
+      }
+    }
+    else {
+      parent::init($dom_node, $citeproc);
+    }
+
+
+  }
+
+  function render($data, $mode = NULL) {
+    $date_parts = array();
+    $text = '';
+
+    if (($var = $this->variable) && isset($data->{$var})) {
+      if (is_array($data->{$var})) {
+        $date = $data->{$var};
+      }
+      else {
+        $date = array($data->{$var});
+      }
+      foreach ($this->elements as $element) {
+        $date_parts[] = $element->render($date, $mode);
+      }
+      $text = implode($this->delimiter, $date_parts);
+    }
+//    else {
+//      $text = $this->citeproc->get_locale('term', 'no date');
+//    }
+
+    return $this->format($text);
+  }
+}
+
+class csl_date_part extends csl_format {
+
+  function render($date, $mode = NULL) {
+    $text = '';
+
+    switch ($this->name) {
+      case 'year':
+        $text = (isset($date[0])) ? $date[0] : '';
+        if ($text > 0 && $text < 500) {
+          $text = $text . $this->citeproc->get_locale('term', 'ad');
+        }
+        elseif ($text < 0) {
+          $text = $text * -1;
+          $text = $text . $this->citeproc->get_locale('term', 'bc');
+        }
+        //return ((isset($this->prefix))? $this->prefix : '') . $date[0] . ((isset($this->suffix))? $this->suffix : '');
+        break;
+      case 'month':
+        $text = (isset($date[1])) ? $date[1] : '';
+        if (empty($text) || $text < 1 || $text > 12) return;
+       // $form = $this->form;
+        switch ($this->form) {
+          case 'numeric': break;
+          case 'numeric-leading-zeros':
+            if ($text < 10) {
+              $text = '0' . $text;
+              break;
+            }
+            break;
+          case 'short':
+            $month = 'month-' . sprintf('%02d', $text);
+            $text = $this->citeproc->get_locale('term', $month, 'short');
+            break;
+          default:
+            $month = 'month-' . sprintf('%02d', $text);
+            $text = $this->citeproc->get_locale('term', $month);
+            break;
+        }
+        break;
+      case 'day':
+        $text = (isset($date[2])) ? $date[2] : '';
+        break;
+    }
+
+    return $this->format($text);
+  }
+}
+
+class csl_number extends csl_format {
+
+  function render($data, $mode = NULL) {
+    $var = $this->variable;
+
+    if (!$var || empty($data->$var)) return;
+
+ //   $form = $this->form;
+
+    switch ($this->form) {
+      case 'ordinal':
+        $text = $this->ordinal($data->$var);
+        break;
+      case 'long-ordinal':
+        $text = $this->long_ordinal($data->$var);
+        break;
+      case 'roman':
+        $text = $this->roman($data->$var);
+        break;
+      case 'numeric':
+      default:
+        $text = $data->$var;
+        break;
+    }
+    return $this->format($text);
+  }
+
+  function ordinal($num) {
+    if ( ($num/10)%10 == 1) {
+      $num .= $this->citeproc->get_locale('term', 'ordinal-04');
+    }
+    elseif ( $num%10 == 1) {
+      $num .= $this->citeproc->get_locale('term', 'ordinal-01');
+    }
+    elseif ( $num%10 == 2) {
+      $num .= $this->citeproc->get_locale('term', 'ordinal-02');
+    }
+    elseif ( $num%10 == 3) {
+      $num .= $this->citeproc->get_locale('term', 'ordinal-03');
+    }
+    else {
+      $num .= $this->citeproc->get_locale('term', 'ordinal-04');
+    }
+    return $num;
+
+  }
+
+  function long_ordinal($num) {
+    $num = sprintf("%02d", $num);
+    $ret = $this->citeproc->get_locale('term', 'long-ordinal-' . $num);
+    if (!$ret) {
+      return $this->ordinal($num);
+    }
+    return $ret;
+  }
+
+  function roman($num) {
+    $ret = "";
+    if ($num < 6000) {
+      $ROMAN_NUMERALS = array(
+      array( "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" ),
+      array( "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" ),
+      array( "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" ),
+      array( "", "m", "mm", "mmm", "mmmm", "mmmmm")
+      );
+      $numstr = strrev($num);
+      $len = strlen($numstr);
+      for ($pos = 0; $pos < $len; $pos++) {
+        $n = $numstr[$pos];
+        $ret = $ROMAN_NUMERALS[$pos][$n] . $ret;
+      }
+    }
+
+    return $ret;
+  }
+
+}
+
+class csl_text extends csl_format {
+  public $source;
+  protected $var;
+
+  function init($dom_node, $citeproc) {
+    foreach (array('variable', 'macro', 'term', 'value') as $attr) {
+      if ($dom_node->hasAttribute($attr)) {
+        $this->source = $attr;
+        if ($this->source == 'macro') {
+          $this->var =  str_replace(' ', '_', $dom_node->getAttribute($attr));
+        }
+        else {
+          $this->var =  $dom_node->getAttribute($attr);
+        }
+      }
+    }
+  }
+  function init_formatting() {
+    if ($this->variable == 'title') {
+      $this->span_class = 'biblio-title';
+    }
+    parent::init_formatting();
+
+  }
+
+  function render($data = NULL, $mode = NULL) {
+    $text = '';
+    if (in_array($this->var, $this->citeproc->quash)) return;
+
+    switch ($this->source) {
+      case 'variable':
+        if (!isset($data->{$this->variable}) || empty($data->{$this->variable}) || trim($data->{$this->variable}) == FALSE) return;
+        if ($this->variable == 'biblio_url') {
+          $text = l($data->{$this->variable},  $data->{$this->variable});
+        }
+        else {
+          $text = $data->{$this->variable}; //$this->data[$this->var];  // include the contents of a variable
+        }
+        break;
+      case 'macro':
+        $macro = $this->var;
+        $text = $this->citeproc->render_macro($macro, $data, $mode); //trigger the macro process
+        break;
+      case 'term':
+        $form = (($form = $this->form)) ? $form : '';
+        $text = $this->citeproc->get_locale('term', $this->var, $form);
+        break;
+      case 'value':
+        $text = $this->var; //$this->var;  // dump the text verbatim
+        break;
+    }
+
+    if (empty($text)) return;
+    $text = $this->format($text);
+    if ($this->variable == 'title') {
+      $url = biblio_get_title_url_info($data);
+      $text =  l($text, $url['link'], $url['options']) ;
+    }
+    return $text;
+  }
+}
+
+class csl_et_al extends csl_text {
+
+  function __construct($dom_node = NULL, $citeproc = NULL) {
+    $this->var = 'et-al';
+    $this->source = 'term';
+    parent::__construct($dom_node, $citeproc);
+
+    }
+}
+class csl_label extends csl_format {
+  private $plural;
+
+  function render($data, $mode = NULL) {
+    $text = '';
+
+    $variables = explode(' ', $this->variable);
+    $form = (($form = $this->form)) ? $form : 'long';
+    switch ($this->plural) {
+      case 'never':
+        $plural = 'single';
+        break;
+      case 'always':
+        $plural = 'multiple';
+        break;
+      case 'contextual':
+      default:
+    }
+    foreach ($variables as $variable) {
+      $field = $this->citeproc->map_field($variable);
+      if (isset($data->{$field})  && !empty($data->{$field})) {
+        if (!isset($this->plural) && empty($plural) && is_array($data->{$field})) {
+          $count = count($data->{$field});
+          if ($count == 1) {
+            $plural = 'single';
+          }
+          elseif ($count > 1) {
+            $plural = 'multiple';
+          }
+        }
+        else {
+          $plural = $this->evaluateStringPluralism($data, $variable);
+        }
+        if (($term = $this->citeproc->get_locale('term', $variable, $form, $plural))) {
+          $text = $term;
+          break;
+        }
+      }
+    }
+
+    if (empty($text)) return;
+    if ($this->{'strip-periods'}) $text = str_replace('.', '', $text);
+    return $this->format($text);
+  }
+
+  function evaluateStringPluralism($data, $variable) {
+    $field = $this->citeproc->map_field($variable);
+    $str = $data->{$field};
+    $plural = 'single';
+
+    if (!empty($str)) {
+//      $regex = '/(?:[0-9],\s*[0-9]|\s+and\s+|&|([0-9]+)\s*[\-\x2013]\s*([0-9]+))/';
+      switch ($variable) {
+        case 'page':
+          $page_regex = "/([a-zA-Z]*)([0-9]+)\s*(?:–|-)\s*([a-zA-Z]*)([0-9]+)/";
+          $err = preg_match($page_regex, $str, $m);
+          if ($err !== FALSE && count($m) == 0) {
+            $plural = 'single';
+          }
+          elseif ($err !== FALSE && count($m)) {
+            $plural = 'multiple';
+          }
+          break;
+        default:
+      }
+    }
+    return $plural;
+  }
+}
+
+class csl_macro extends csl_format{
+
+}
+
+class csl_macros extends csl_collection{
+
+  function __construct($macro_nodes, $citeproc) {
+    foreach ($macro_nodes as $macro) {
+      $macro = csl_factory::create($macro, $citeproc);
+      $this->elements[$macro->name()] = $macro;
+    }
+  }
+
+  function render_macro($name, $data, $mode) {
+    return $this->elements[$name]->render($data, $mode);
+  }
+}
+
+class csl_group extends csl_format{
+
+  function render($data, $mode = NULL) {
+    $text = '';
+    $text_parts = array();
+
+    $terms = $variables = $have_variables = $element_count = 0;
+    foreach ($this->elements as $element) {
+      $element_count++;
+      if (($element instanceof csl_text) &&
+          ($element->source == 'term' ||
+           $element->source == 'value' )) {
+        $terms++;
+      }
+      if (($element instanceof csl_label)) $terms++;
+      if ($element->source == 'variable' &&
+          isset($element->variable) &&
+          !empty($data->{$element->variable})
+         ) {
+        $variables++;
+      }
+
+      $text = $element->render($data, $mode);
+
+      $delimiter = $this->delimiter;
+      if (!empty($text)) {
+        if ($delimiter && ($element_count < count($this->elements))) {
+          //check to see if the delimiter is already the last character of the text string
+          //if so, remove it so we don't have two of them when we paste together the group
+          $stext = strip_tags(trim($text));
+          if ((strrpos($stext, $delimiter[0])+1) == drupal_strlen($stext) && drupal_strlen($stext) > 1) {
+            $text = str_replace($stext, '----REPLACE----', $text);
+            $stext = drupal_substr($stext, 0, -1);
+            $text = str_replace('----REPLACE----', $stext, $text);
+          }
+        }
+        $text_parts[] = $text;
+        if ($element->source == 'variable' || isset($element->variable)) $have_variables++;
+        if ($element->source == 'macro') $have_variables++;
+      }
+    }
+
+    if (empty($text_parts)) return;
+    if ($variables  && !$have_variables ) return; // there has to be at least one other none empty value before the term is output
+    if (count($text_parts) == $terms) return; // there has to be at least one other none empty value before the term is output
+
+    $delimiter = $this->delimiter;
+    $text = implode($delimiter, $text_parts); // insert the delimiter if supplied.
+
+
+    return $this->format($text);
+  }
+}
+
+class csl_layout extends csl_format {
+
+  function init_formatting() {
+   // $this->div_class = 'csl-entry';
+    parent::init_formatting();
+  }
+
+  function render($data, $mode = NULL) {
+    $text = '';
+    $parts = array();
+   // $delimiter = $this->delimiter;
+
+    foreach ($this->elements as $element) {
+      $parts[] = $element->render($data, $mode);
+    }
+
+    $text = implode($this->delimiter, $parts);
+
+    if ($mode == 'bibliography') {
+      return $this->format($text);
+    }
+    else {
+      return $text;
+    }
+
+  }
+
+}
+
+class csl_citation extends csl_format{
+  private $layout = NULL;
+
+  function init($dom_node, $citeproc) {
+    $options = $dom_node->getElementsByTagName('option');
+    foreach ($options as $option) {
+      $value = $option->getAttribute('value');
+      $name  = $option->getAttribute('name');
+      $this->attributes[$name]  = $value;
+    }
+
+    $layouts = $dom_node->getElementsByTagName('layout');
+    foreach ($layouts as $layout) {
+      $this->layout = new csl_layout($layout, $citeproc);
+    }
+  }
+
+  function render($data, $mode = NULL) {
+    $this->citeproc->quash = array();
+
+    $text = $this->layout->render($data, 'citation');
+
+    return $this->format($text);
+  }
+
+}
+class csl_bibliography  extends csl_format {
+  private $layout = NULL;
+
+  function init($dom_node, $citeproc) {
+    $hier_name_attr = $this->get_hier_attributes();
+    $options = $dom_node->getElementsByTagName('option');
+    foreach ($options as $option) {
+      $value = $option->getAttribute('value');
+      $name  = $option->getAttribute('name');
+      $this->attributes[$name]  = $value;
+    }
+
+    $layouts = $dom_node->getElementsByTagName('layout');
+    foreach ($layouts as $layout) {
+      $this->layout = new csl_layout($layout, $citeproc);
+    }
+
+  }
+
+  function init_formatting() {
+   // $this->div_class = 'csl-bib-body';
+    parent::init_formatting();
+  }
+
+  function render($data, $mode = NULL) {
+    $this->citeproc->quash = array();
+    $text = $this->layout->render($data, 'bibliography');
+    if ($this->{'hanging-indent'} == 'true') {
+      $text = '<div style="  text-indent: -25px; padding-left: 25px;">' . $text . '</div>';
+    }
+    $text = str_replace('?.', '?', str_replace('..', '.', $text));
+    return $this->format($text);
+  }
+}
+
+class csl_option  {
+  private $name;
+  private $value;
+
+  function get() {
+    return array($this->name => $this->value);
+  }
+}
+
+class csl_options extends csl_element{
+
+}
+
+class csl_sort extends csl_element{
+
+}
+class csl_style extends csl_element{
+
+  function __construct($dom_node = NULL, $citeproc = NULL) {
+    if ($dom_node) {
+      $this->set_attributes($dom_node);
+    }
+  }
+}
+
+class csl_choose extends csl_element{
+
+  function render($data, $mode = NULL) {
+    foreach ($this->elements as $choice) {
+      if ($choice->evaluate($data)) {
+        return $choice->render($data, $mode);
+      }
+    }
+  }
+}
+
+class csl_if extends csl_rendering_element {
+
+  function evaluate($data) {
+    $match = (($match = $this->match)) ? $match : 'all';
+    if (($types = $this->type)) {
+      $types  = explode(' ', $types);
+      $matches = 0;
+      foreach ($types as $type) {
+        if (isset($data->biblio_type)) {
+          if ($data->biblio_type == $type && $match == 'any') return TRUE;
+          if ($data->biblio_type != $type && $match == 'all') return FALSE;
+          if ($data->biblio_type == $type) $matches++;
+        }
+      }
+      if ($match == 'all' && $matches == count($types)) return TRUE;
+      if ($match == 'none' && $matches == 0) return TRUE;
+      return FALSE;
+    }
+    if (($variables = $this->variable)) {
+      $variables  = explode(' ', $variables);
+      $matches = 0;
+      foreach ($variables as $var) {
+        if (isset($data->$var) && !empty($data->$var) && $match == 'any') return TRUE;
+        if ((!isset($data->$var) || empty($data->$var)) && $match == 'all') return FALSE;
+        if (isset($data->$var) && !empty($data->$var)) $matches++;
+      }
+      if ($match == 'all' && $matches == count($variables)) return TRUE;
+      if ($match == 'none' && $matches == 0) return TRUE;
+      return FALSE;
+    }
+    if (($is_numeric = $this->{'is-numeric'})) {
+      $variables  = explode(' ', $is_numeric);
+      $matches = 0;
+      foreach ($variables as $var) {
+        if (isset($data->$var)) {
+          if (is_numeric($data->$var) && $match == 'any') return TRUE;
+          if (!is_numeric($data->$var)) {
+            if (preg_match('/(?:^\d+|\d+$)/', $data->$var)) {
+              $matches++;
+            }
+            elseif ($match == 'all') {
+              return FALSE;
+            }
+          }
+          if (is_numeric($data->$var)) $matches++;
+        }
+      }
+      if ($match == 'all' && $matches == count($variables)) return TRUE;
+      if ($match == 'none' && $matches == 0) return TRUE;
+      return FALSE;
+    }
+    if (isset($this->locator))  $test  = explode(' ', $this->type);
+
+    return FALSE;
+  }
+}
+
+class csl_else_if extends csl_if {
+
+}
+
+class csl_else extends csl_if {
+
+  function evaluate($data = NULL) {
+    return TRUE; // the last else always returns TRUE
+  }
+}
+
+class csl_substitute extends csl_element{
+
+}
+
+class csl_locale  {
+  protected $locale_xmlstring = NULL;
+  protected $style_locale_xmlstring = NULL;
+  protected $locale = NULL;
+  protected $style_locale = NULL;
+  private   $module_path;
+
+  function __construct($lang = 'en') {
+    $this->module_path = drupal_get_path('module', 'biblio_citeproc');
+    $this->locale = new SimpleXMLElement($this->get_locales_file_name($lang));
+    if ($this->locale) {
+      $this->locale->registerXPathNamespace('cs', 'http://purl.org/net/xbiblio/csl');
+    }
+  }
+
+  // SimpleXML objects cannot be serialized, so we must convert to an XML string prior to serialization
+  function __sleep() {
+    $this->locale_xmlstring       = ($this->locale)       ? $this->locale->asXML()       : '';
+    $this->style_locale_xmlstring = ($this->style_locale) ? $this->style_locale->asXML() : '';
+    return array('locale_xmlstring', 'style_locale_xmlstring');
+  }
+
+  // SimpleXML objects cannot be serialized, so when un-serializing them, they must rebuild from the serialized XML string.
+  function __wakeup() {
+    $this->style_locale = (!empty($this->style_locale_xmlstring)) ? new SimpleXMLElement($this->style_locale_xmlstring) : NULL;
+    $this->locale       = (!empty($this->locale_xmlstring))       ? new SimpleXMLElement($this->locale_xmlstring)       : NULL;
+    if ($this->locale) {
+      $this->locale->registerXPathNamespace('cs', 'http://purl.org/net/xbiblio/csl');
+    }
+  }
+
+  function get_locales_file_name($lang) {
+    $lang_bases = array(
+        "af" => "af-ZA",
+        "ar" => "ar-AR",
+        "bg" => "bg-BG",
+        "ca" => "ca-AD",
+        "cs" => "cs-CZ",
+        "da" => "da-DK",
+        "de" => "de-DE",
+        "el" => "el-GR",
+        "en" => "en-US",
+        "es" => "es-ES",
+        "et" => "et-EE",
+        "fa" => "fa-IR",
+        "fi" => "fi-FI",
+        "fr" => "fr-FR",
+        "he" => "he-IL",
+        "hu" => "hu-HU",
+        "is" => "is-IS",
+        "it" => "it-IT",
+        "ja" => "ja-JP",
+        "km" => "km-KH",
+        "ko" => "ko-KR",
+        "mn" => "mn-MN",
+        "nb" => "nb-NO",
+        "nl" => "nl-NL",
+        "nn" => "nn-NO",
+        "pl" => "pl-PL",
+        "pt" => "pt-PT",
+        "ro" => "ro-RO",
+        "ru" => "ru-RU",
+        "sk" => "sk-SK",
+        "sl" => "sl-SI",
+        "sr" => "sr-RS",
+        "sv" => "sv-SE",
+        "th" => "th-TH",
+        "tr" => "tr-TR",
+        "uk" => "uk-UA",
+        "vi" => "vi-VN",
+        "zh" => "zh-CN",
+    );
+    return (isset($lang_bases[$lang])) ? file_get_contents($this->module_path . '/locale/locales-' . $lang_bases[$lang] . '.xml') : file_get_contents($this->module_path . '/locale/locales-en-US.xml');
+  }
+
+  function get_locale($type, $arg1, $arg2 = NULL, $arg3 = NULL) {
+    switch ($type) {
+      case 'term':
+        $term = '';
+        $form = $arg2 ? " and @form='$arg2'" : '';
+        $plural = $arg3 ? "/cs:$arg3" : '';
+        if ($arg2 == 'verb' || $arg2 == 'verb-short') $plural = '';
+        if ($this->style_locale) {
+          $term = @$this->style_locale->xpath("//locale[@xml:lang='en']/terms/term[@name='$arg1'$form]$plural");
+          if (!$term) {
+            $term = @$this->style_locale->xpath("//locale/terms/term[@name='$arg1'$form]$plural");
+          }
+        }
+        if (!$term) {
+          $term = $this->locale->xpath("//cs:term[@name='$arg1'$form]$plural");
+        }
+        if (isset($term[0])) {
+          if (isset($arg3) && isset($term[0]->{$arg3})) return (string)$term[0]->{$arg3};
+          if (!isset($arg3) && isset($term[0]->single)) return (string)$term[0]->single;
+          return (string)$term[0];
+        }
+        break;
+      case 'date_option':
+        $attribs = array();
+        if ($this->style_locale) {
+          $date_part = $this->style_locale->xpath("//date[@form='$arg1']/date-part[@name='$arg2']");
+        }
+        if (!isset($date_part)) {
+          $date_part = $this->locale->xpath("//cs:date[@form='$arg1']/cs:date-part[@name='$arg2']");
+        }
+        if (isset($date_part)) {
+          foreach ($$date_part->attributes()  as $name => $value) {
+            $attribs[$name] = (string)$value;
+          }
+        }
+        return $attribs;
+        break;
+      case 'date_options':
+        $options = array();
+        if ($this->style_locale) {
+          $options = $this->style_locale->xpath("//locale[@xml:lang='en']/date[@form='$arg1']");
+          if (!$options) {
+            $options = $this->style_locale->xpath("//locale/date[@form='$arg1']");
+          }
+        }
+        if (!$options) {
+          $options = $this->locale->xpath("//cs:date[@form='$arg1']");
+        }
+        if (isset($options[0]))return $options[0];
+        break;
+      case 'style_option':
+        $attribs = array();
+        if ($this->style_locale) {
+          $option = $this->style_locale->xpath("//locale[@xml:lang='en']/style-options[@$arg1]");
+          if (!$option) {
+            $option = $this->style_locale->xpath("//locale/style-options[@$arg1]");
+          }
+        }
+        if (isset($option) && !empty($option)) {
+          $attribs = $option[0]->attributes();
+        }
+        if (empty($attribs)) {
+          $option = $this->locale->xpath("//cs:style-options[@$arg1]");
+        }
+        foreach ($option[0]->attributes()  as $name => $value) {
+          if ($name == $arg1) return (string)$value;
+        }
+        break;
+    }
+  }
+
+  public function set_style_locale($csl_doc) {
+    $xml = '';
+    $locale_nodes = $csl_doc->getElementsByTagName('locale');
+    if ($locale_nodes) {
+      $xml_open = '<style-locale>';
+      $xml_close = '</style-locale>';
+      foreach ($locale_nodes as $key => $locale_node) {
+        $xml .= $csl_doc->saveXML($locale_node);
+      }
+      if (!empty($xml)) {
+        $this->style_locale = new SimpleXMLElement($xml_open . $xml . $xml_close);
+      }
+    }
+  }
+
+}
+
+class csl_mapper {
+
+  function map_field($field) {
+    if (!isset($this->field_map)) {
+      $this->field_map = biblio_get_map('field_map', 'csl');
+    }
+
+    $vars = explode(' ', $field);
+    foreach ($vars as $key => $value) {
+      $vars[$key] = (!empty($this->field_map[$value])) ? $this->field_map[$value] : '';
+    }
+
+    return implode(' ', $vars);
+  }
+
+  function map_type($types) {
+    if (!isset($this->type_map)) {
+      $this->type_map = biblio_get_map('type_map', 'csl');
+    }
+    $vars = explode(' ', $types);
+    foreach ($vars as $key => $value) {
+      $vars[$key] = (!empty($this->type_map[$value])) ? $this->type_map[$value] : '';
+    }
+
+    return implode(' ', $vars);
+
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/biblio_citeproc.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,710 @@
+<?php
+function biblio_citeproc_style_manager_form($form, &$form_state) {
+  $form = array();
+  $options = array();
+
+  $cache = cache_get('biblio_citeproc_styles');
+
+  if (!$cache || $cache->expire < time()) {
+    if (!($style_zip_file = variable_get('biblio_citeproc_styles_zip_file', FALSE))) {
+      $style_zip_file = _get_zip_from_github();
+    }
+
+    if ($style_zip_file) {
+      $file = drupal_realpath($style_zip_file->uri);
+      $options = _get_csl_list_from_zip($file);
+    }
+
+    if (!empty($options)) {
+      //expire 30 days from now
+      $expire = time() + 2592000;
+      cache_set('biblio_citeproc_styles', $options, 'cache', $expire);
+    }
+  }
+  else {
+    $options = $cache->data;
+  }
+
+
+  $form['available_styles'] = array(
+    '#type' => 'select',
+    '#title' => t('Available styles'),
+    '#size' => 15,
+    '#multiple' => TRUE,
+    '#description' => t('Choose the styles you would like to download and install.'),
+  );
+
+  $form['install'] = array(
+    '#type'        => 'submit',
+    '#value'       => '<--',
+    '#description' => t('Install the selected styles from GitHub'),
+  );
+  $form['remove'] = array(
+    '#type'        => 'submit',
+    '#value'       => '-->',
+    '#description' => t('Un-install the selected styles'),
+  );
+  $form['default'] = array(
+    '#type'  => 'submit',
+    '#value' => t('Set as site default'),
+    '#submit' => array('biblio_citeproc_set_site_default'),
+  );
+  $form['update_installed'] = array(
+    '#type'  => 'submit',
+    '#value' => t('Update installed styles'),
+    '#submit' => array('biblio_citeproc_update_installed'),
+  );
+  $form['update_available'] = array(
+    '#type'  => 'submit',
+    '#value' => t('Update available styles'),
+    '#submit' => array('biblio_citeproc_update_available'),
+  );
+  $form['edit'] = array(
+    '#type'  => 'submit',
+    '#value' => t('Edit selected'),
+    '#submit' => array('biblio_citeproc_edit_selected'),
+  );
+//   $form['install_all'] = array(
+//     '#type'     => 'submit',
+//     '#value'    => t('Install all')
+//   );
+
+  $form['#attributes']['enctype'] = 'multipart/form-data';
+
+  $form['import_csl_file'] = array(
+        '#type' => 'file',
+        '#title' => t('Import Local CSL file'),
+        '#default_value' => '',
+        '#size' => 60
+  );
+  $form['import'] = array(
+      '#type'   => 'submit',
+      '#value'  => t('Import'),
+      '#submit' => array('biblio_citeproc_csl_file_import_submit'),
+  );
+
+  $result = db_select('biblio_citeproc_styles', 'csl')
+    ->fields('csl', array('filename', 'title', 'id', 'sha1', 'title', 'summary', 'changed', 'updated'))
+    ->orderBy('filename', 'ASC')
+    ->execute();
+
+  $details = array();
+  $titles = array();
+  foreach ($result as $style) {
+    $details[$style->filename] = $style;
+    $titles[] = $style->title;
+  }
+
+  // now remove the installed titles from the available titles list
+  $options = array_diff($options, $titles);
+  $form['available_styles']['#options'] = $options;
+
+  $form['installed_styles'] = array(
+    '#type' => 'select',
+    '#title' => t('Installed styles'),
+    '#size' => 15,
+    '#options' => biblio_get_styles(),
+    '#multiple' => TRUE,
+    '#description' => t('Currently installed styles.'),
+  );
+
+  $form['current_default'] = array(
+    '#markup' => empty($details) ? '' : $details[variable_get('biblio_citeproc_style', 'ieee.csl')]->title,
+  );
+
+  $form['current_summary'] = array(
+    '#markup' => empty($details) ? '' : $details[variable_get('biblio_citeproc_style', 'ieee.csl')]->summary,
+  );
+
+  $timestamp = $details[variable_get('biblio_citeproc_style', 'ieee.csl')]->updated;
+  $updated = $timestamp ? ' ('. t('Last updated:') . ' ' . format_date($timestamp, 'medium') . ')' : '';
+
+  $form['current_update'] = array(
+    '#markup' => $updated,
+  );
+
+  return $form;
+}
+
+function theme_biblio_citeproc_style_manager_form($variables) {
+  $form = $variables['form'];
+  $rows = array();
+  $updated = drupal_render($form['current_update']);
+  $updated = empty($updated) ? $updated : '</br>' . $updated;
+  $rows[] = array(
+            array('data' => t('Current default style:')),
+            array('data' => '<b>' . drupal_render($form['current_default']) . '</b>'  .
+                '</br><i>' . drupal_render($form['current_summary']) . '</i>' . $updated
+                ),
+  );
+  $rows[] = array(
+            array('data' => t('Example citation:')),
+            array('data' => biblio_citeproc_example_citation()));
+  $output = theme('table', array('rows' => $rows));
+  $rows = array();
+  $rows[] = array(
+              array('data' => drupal_render($form['installed_styles']) ),
+              array('data' => drupal_render($form['install']) . '<br>' . drupal_render($form['remove'])),
+              array('data' => drupal_render($form['available_styles'])),
+            );
+  $rows[] = array(
+              array('data' =>  drupal_render($form['default'])  . drupal_render($form['edit']) .drupal_render($form['update_installed'])),
+              array('data' => ''),
+              array('data' => drupal_render($form['update_available'])),
+            );
+  $rows[] = array(array('data' => drupal_render($form['import_csl_file']) . drupal_render($form['import']), 'colspan' => 3) );
+  $output .= theme('table', array('rows' => $rows));
+
+  $output .= drupal_render_children($form);
+  return $output;
+
+}
+function biblio_citeproc_style_manager_form_validate($form, &$form_state) {
+  if ($form_state['clicked_button']['#value'] == '<--' && count( $form_state['values']['available_styles'])) {
+    if (count($form_state['values']['available_styles']) > 60) {
+      form_error($form['available_styles'], t('You may not select more than 60 styles for installation at one time'));
+    }
+  }
+ if ($form_state['clicked_button']['#value'] ==  t('Set as site default') && !count( $form_state['values']['installed_styles'])) {
+   form_error($form['installed_styles'], t('You must select an installed style to set as the default.'));
+ }
+
+}
+function biblio_citeproc_style_manager_form_submit($form, &$form_state) {
+  if ($form_state['clicked_button']['#value'] == '<--' && count( $form_state['values']['available_styles'])) {
+    if (!($style_zip_file = variable_get('biblio_citeproc_styles_zip_file', FALSE))) {
+      $style_zip_file = _get_zip_from_github();
+    }
+
+    if (!$style_zip_file) {
+      form_set_error('<--', t('Could not get the style files from GitHub'));
+    }
+
+    $file = drupal_realpath($style_zip_file->uri);
+    $selected = $form_state['values']['available_styles'];
+    _install_selected_from_zip($file, $selected);
+  }
+
+  if ($form_state['clicked_button']['#value'] == '-->' && count( $form_state['values']['installed_styles'])) {
+    $selected = $form_state['values']['installed_styles'];
+    _uninstall_selected($selected);
+  }
+}
+
+function biblio_citeproc_edit_selected($form, &$form_state) {
+  if (count( $form_state['values']['installed_styles'])) {
+    $style = array_shift($form_state['values']['installed_styles']);
+    $dest = drupal_get_destination();
+    drupal_goto('admin/config/content/biblio/citeproc/styles/' . $style . '/edit');
+  }
+}
+
+function biblio_citeproc_set_site_default($form, &$form_state) {
+  if (count( $form_state['values']['installed_styles']) == 1) {
+    $def = array_shift($form_state['values']['installed_styles']);
+    variable_set('biblio_citeproc_style', $def);
+  }
+  else {
+    form_set_error('installed_styles', t('You may only select one style when setting the default'));
+  }
+}
+
+function biblio_citeproc_update_installed($form, &$form_state) {
+  $batch_op = array(
+      'title' => t('Updating all installed styles from the main GitHub repository'),
+      'operations' => array(
+          array('_get_zip_from_github', array()),
+          array('biblio_citeproc_update_installed_batch', array()),
+      ),
+      'progressive' => TRUE,
+      'finished' => 'biblio_citeproc_update_installed_finished',
+      'init_message' => t('Downloading file...'),
+      'progress_message' => t('Updating styles...'),
+      'file' => './' . drupal_get_path('module', 'biblio_citeproc') . '/biblio_citeproc.admin.inc'
+  );
+  batch_set($batch_op);
+}
+
+function biblio_citeproc_update_available($form, &$form_state) {
+  _get_zip_from_github();
+}
+
+function biblio_citeproc_csl_file_import_submit($form, &$form_state) {
+  $validators = array(
+      'file_validate_extensions' => array('csl xml'),
+      'biblio_citeproc_validate_csl_file' => array()
+  );
+
+  if ($import_file = file_save_upload('import_csl_file', $validators)) {
+    $csl = file_get_contents($import_file->uri);
+//    if (biblio_citeproc_validate_csl($csl)) {
+    _install_csl($import_file->filename, $csl);
+//    }
+  }
+
+}
+function _get_github_repo_tree($path = '') {
+  $options = array();
+    $tree_url = 'https://api.github.com/repos/citation-style-language/styles/contents';
+    if (!empty($path)) {
+      $tree_url .= '/' . $path;
+    }
+
+    $result=  drupal_http_request($tree_url);
+    if ($result->code == 200) {
+      $tree = json_decode($result->data);
+    }
+    else {
+      $message = t('Attempt to get list of styles from GitHub resulted in an HTTP error: !code.', array('!code' => $result->code));
+
+      $cache = cache_get('github_csl_repo');
+
+      if ($cache) {
+        $message .= ' ' . t('I will use cached data instead.');
+        $mess_type = 'warning';
+        $options = $cache->data;
+      }
+      else {
+        $message .= ' ' . t('I have no cached data, so you will not be able to install new styles at this time.');
+        $mess_type = 'error';
+      }
+      drupal_set_message(check_plain($message), $mess_type);
+      return $options;
+    }
+
+    foreach ($tree as $file) {
+      if ($file->type == 'file' && strstr($file->name, '.csl')) {
+        $options[$file->path] =  basename($file->name);
+      }
+      elseif ($file->type == 'dir') {
+        $options = array_merge($options, _get_github_repo_tree($file->name));
+      }
+    }
+  return $options;
+}
+
+function _install_csl($name = NULL, $csl = NULL, $sha = NULL, $all = FALSE, $update = FALSE) {
+  static  $installed = array();
+
+  if (empty($installed)) {
+    $result = db_select('biblio_citeproc_styles', 'csl')
+    ->fields('csl', array('filename', 'id', 'sha1', 'title'))
+    ->orderBy('filename', 'ASC')
+    ->execute();
+
+    $installed = array();
+    foreach ($result as $style) {
+      $installed[$style->id] = $style;
+    }
+  }
+
+  $xml = simplexml_load_string($csl);
+
+  if ($xml) {
+    $parent = '';
+    foreach ($xml->info->link as $link) {
+      $attrs = $link->attributes();
+      if (isset($attrs['rel']) && $attrs['rel'] == 'independent-parent') {
+        $parent = (string)$attrs['href'];
+      }
+    }
+    if (!$all && !$update && !empty($parent)) {
+      $csl_file_contents = db_query("SELECT csl FROM {biblio_citeproc_styles} WHERE id = :parent", array(':parent' => $parent))->fetchField();
+      if (!$csl_file_contents) {
+        _install_csl_from_github(basename($parent) . '.csl');
+      }
+    }
+
+    $sha1 = (isset($sha)) ? $sha : sha1($csl);
+
+    $record  = array(
+        'filename' => $name,
+        'parent'   => $parent,
+        'title'    => trim((string)$xml->info->title),
+        'summary'  => (string)$xml->info->summary,
+        'csl'      => $csl,
+        'sha1'     => $sha1,
+        'id'       => (string)$xml->info->id,
+        'updated'  => time(),
+        'changed'  => 0,
+    );
+
+    if (!array_key_exists($record['id'], $installed)) {
+      db_insert('biblio_citeproc_styles')->fields($record)->execute();
+      $installed[$record['id']] = TRUE;
+      return 1;
+    }
+    elseif ($record['sha1'] != $installed[$record['id']]->sha1) {
+      db_update('biblio_citeproc_styles')->condition('id', $record['id'])->fields($record)->execute();
+      return 2;
+    }
+    elseif (($record['sha1'] == $installed[$record['id']]->sha1 && $update == FALSE)) {
+      $message = t('The CSL file you supplied: !name, is already installed', array('!name' => $name));
+      drupal_set_message(check_plain($message), 'warning');
+    }
+  }
+  else {
+    drupal_set_message(t('I could not parse the CSL provided as valid XML', 'error'));
+  }
+}
+
+function _get_zip_from_github() {
+  $zip_url = 'https://github.com/citation-style-language/styles/zipball/master';
+  $destination = file_build_uri('Biblio-CiteProc-Styles.zip');
+  $zip_file = system_retrieve_file($zip_url, $destination, TRUE, FILE_EXISTS_REPLACE);
+  $usage = file_usage_list($zip_file);
+  if (empty($usage)) {
+    file_usage_add($zip_file, 'biblio_citeproc', 'csl', 0);
+  }
+  variable_set('biblio_citeproc_styles_zip_file', $zip_file);
+  cache_clear_all('biblio_citeproc_styles', 'cache');
+  return $zip_file;
+}
+
+function _install_csl_from_github($path, $update = FALSE) {
+  $csl = '';
+  $github_url = 'https://api.github.com/repos/citation-style-language/styles/contents/';
+  $URL = $github_url . $path;
+  $result = drupal_http_request($URL);
+  if ($result->code == 200) {
+    $file  = json_decode($result->data);
+    switch ($file->encoding) {
+      case 'base64':
+        $csl = base64_decode($file->content);
+        break;
+    }
+    _install_csl($file->name, $csl, $file->sha, FALSE, $update);
+  }
+  else {
+    $message = t('Attempt to get style: %name from GitHub resulted in an HTTP error: !code.', array('%name' => $path, '!code' => $result->code));
+    $mess_type = 'error';
+    drupal_set_message(check_plain($message), $mess_type);
+  }
+  return;
+}
+
+function _get_csl_list_from_zip($filename) {
+  $options = array();
+  $za      = new ZipArchive();
+
+  if ($za->open($filename) !== TRUE) {
+    $message = t('Could not open zip file containing styles: @file', array('@file' => realpath($filename)));
+    $message = check_plain($message);
+    drupal_set_message($message, 'error');
+    return $options;
+  }
+
+  $num_files = $za->numFiles;
+
+  for ($i = 0; $i < $num_files; $i++) {
+    $name = $za->getNameIndex($i);
+    $name = basename($name);
+    if (strstr($name, '.csl')) {
+      $csl = $za->getFromIndex($i);
+      $xml = simplexml_load_string($csl);
+      if ($xml) {
+        $options[$i] = trim((string)$xml->info->title);
+      }
+    }
+  }
+
+  $za->close();
+  asort($options);
+  return $options;
+}
+
+function _install_selected_from_zip($filename = '', $ids = array()) {
+  $za = new ZipArchive();
+  if ($za->open($filename) == TRUE) {
+    foreach ($ids as $id) {
+      $name = $za->getNameIndex($id);
+      $name = basename($name);
+      if (strstr($name, '.csl')) {
+        $csl = $za->getFromIndex($id);
+        _install_csl($name, $csl);
+      }
+    }
+    $za->close();
+  }
+}
+
+function _uninstall_selected($ids = array()) {
+  $result = db_select('biblio_citeproc_styles', 'csl')
+    ->fields('csl', array('id', 'filename', 'parent'))
+    ->orderBy('filename', 'ASC')
+    ->execute();
+
+  foreach ($result as $csl) {
+    $fp[$csl->filename] = $csl->parent;
+    $fi[$csl->filename] = $csl->id;
+  }
+
+  foreach ($ids as $id) {
+      db_delete('biblio_citeproc_styles')->condition('filename', $id)->execute();
+      //if this is a dependent style, delete the parent style if no others are using it
+      if (!empty($fp[$id])) {
+        $parent = array_keys($fp, $fp[$id]);
+        if ( count($parent) == 1) {
+          db_delete('biblio_citeproc_styles')->condition('id', $fp[$id])->execute();
+        }
+      }
+      //delete all the dependents
+      $children = array_keys($fp, $fi[$id]);
+      if (!empty($children)) {
+         db_delete('biblio_citeproc_styles')->condition('filename', $children, 'IN')->execute();
+      }
+      if (variable_get('biblio_citeproc_style', 'ieee.csl') == $id) {
+        variable_del('biblio_citeproc_style');
+      }
+    }
+
+}
+
+function _install_all_from_zip(&$context = NULL) {
+
+   $zipname = $context['results']['zipname'];
+
+  if (!empty($zipname)) {
+    //variable_del('github_zip');
+    $zip = zip_open($zipname);
+    $za = new ZipArchive();
+
+    if ($za->open($zipname) !== TRUE) {
+      $message = t('Could not open zip file containing styles: @file', array('@file' => realpath($zipname)));
+      $message = check_plain($message);
+      drupal_set_message($message, 'error');
+      return;
+    }
+    if (empty($context['sandbox'])) {
+     $context['sandbox']['progress'] = 0;
+     $context['results']['install_count'] = 0;
+    }
+
+    $num_files = $za->numFiles;
+    $start = $context['sandbox']['progress'];
+    $end = min(($start+50), $num_files);
+
+    for ($i = $start; $i < $end; $i++) {
+      $name = $za->getNameIndex($i);
+      $name = basename($name);
+      if (strstr($name, '.csl')) {
+        $csl = $za->getFromIndex($i);
+        _install_csl($name, $csl, NULL, TRUE);
+        $context['results']['install_count']++;
+      }
+      $context['sandbox']['progress']++;
+    }
+    $za->close();
+
+    if ($context['sandbox']['progress'] != $num_files) {
+      $context['finished'] = $context['sandbox']['progress'] / $num_files;
+    }
+  }
+}
+
+function _csl_import_batch_finished($success, $results, $operations) {
+  $zipname = variable_get('github_zip', '');
+  file_unmanaged_delete($zipname);
+  variable_del('github_zip');
+}
+
+function biblio_citeproc_example_citation() {
+  global $language;
+  $contributors = array(
+    0 => array(
+      'lastname' => 'Oneauth',
+      'firstname' => 'Joe',
+      'initials' => 'A',
+      'auth_category' => 1,
+      'cid' => -1),
+    1 => array(
+      'lastname' => 'Twoauth',
+      'firstname' => 'John',
+      'initials' => 'B',
+      'auth_category' => 1,
+      'cid' => -2),
+  );
+  $node = new stdClass();
+  $node->nid = -1;
+  $node->title                  = 'This is a fantastic title.';
+  $node->biblio_contributors    = $contributors;
+  $node->biblio_type            = 102;
+  $node->biblio_year            = 2010;
+  $node->biblio_volume          = 1;
+  $node->biblio_issue           = 2;
+  $node->biblio_secondary_title = 'Journal of Fantastic Articles';
+  $node->biblio_pages           = '424-31';
+  $node->biblio_coins           = '';
+  return theme_biblio_citeproc_style(array('node' => $node));
+
+}
+
+function biblio_citeproc_csl_editor($form, &$form_state, $style) {
+
+  $csl = db_query('SELECT id,parent,csl FROM {biblio_citeproc_styles} WHERE filename = :id', array(':id' => $style))->fetchObject();
+  if (!isset($csl->csl)) {
+    drupal_set_message(t('Biblio-CiteProc could not fetch the style file: @csl_id from the database. Check your CiteProc settings.', array('@csl_id' => $style)), 'error');
+    return;
+  }
+  if (!empty($csl->parent)) {
+    $csl = db_query("SELECT id,csl FROM {biblio_citeproc_styles} WHERE id = :id", array(':id' => $csl->parent))->fetchObject();
+
+  }
+  if (isset($csl->csl)) {
+    $csl_file_contents = $csl->csl;
+  }
+
+  $form['editor'] = array(
+      '#title'         => t('Editing %style', array('%style' => $style)),
+      '#type'          => 'text_format',
+      '#rows'          => 40,
+      '#format'        => 'csl',
+      '#default_value' => $csl_file_contents,
+  );
+  $form['save'] = array(
+      '#value' => t('Save'),
+      '#type'  => 'submit',
+  );
+  $form['cancel'] = array(
+      '#value' => t('Cancel'),
+      '#type'  => 'submit',
+  );
+  $form['style'] = array(
+      '#value' => $style,
+      '#type'  => 'hidden',
+  );
+  $form['id'] = array(
+      '#value' => $csl->id,
+      '#type'  => 'hidden',
+  );
+
+  return $form;
+}
+function biblio_citeproc_csl_editor_validate($form, &$form_state) {
+  if ($form_state['triggering_element']['#value'] == t('Save')) {
+    $csl = $form_state['values']['editor']['value'];
+    $valid = biblio_citeproc_validate_csl($csl);
+    if (!empty($valid)) {
+      form_set_error('editor', $valid[0]);
+    }
+    else {
+      $form_state['values']['editor']['value'] = $csl;
+    }
+  }
+}
+function biblio_citeproc_csl_editor_submit($form, &$form_state) {
+  $form_state['redirect'] = 'admin/config/content/biblio/citeproc/styles';
+
+  if ($form_state['triggering_element']['#value'] == t('Save')) {
+    $csl = $form_state['values']['editor']['value'];
+    $id  = $form_state['values']['id'];
+
+    $record = array(
+        'id'      => $id,
+        'csl'     => $csl,
+        'sha1'    => sha1($csl),
+        'changed' => time(),
+        'updated' => time(),
+    );
+    drupal_write_record('biblio_citeproc_styles', $record, 'id');
+  }
+
+}
+
+function biblio_citeproc_validate_csl_file($file) {
+  if ($file->source == 'import_csl_file') {
+    $csl = file_get_contents($file->uri);
+    return biblio_citeproc_validate_csl($csl);
+  }
+}
+
+function biblio_citeproc_validate_csl($csl) {
+  $rng_schema = drupal_get_path('module', 'biblio_citeproc') . '/schema/csl.rng';
+  $doc = new DOMDocument();
+  $doc->loadXML($csl);
+  $updated = $doc->getElementsByTagName('updated')->item(0);
+  $updated->nodeValue = date(DATE_ATOM, time());
+  $valid = $doc->relaxNGValidate($rng_schema);
+  $csl = $doc->saveXML();
+  return ($valid) ? array() : array(t('The supplied CSL file did not pass CSL 1.0 validation'));
+
+}
+
+function biblio_citeproc_update_installed_batch(&$context = NULL) {
+  $style_zip_file = variable_get('biblio_citeproc_styles_zip_file', FALSE);
+  $zipname = $style_zip_file ? drupal_realpath($style_zip_file->uri) : FALSE;
+
+  if (empty($context['sandbox']['installed'])) {
+    $context['sandbox']['installed'] = array();
+
+    $result = db_select('biblio_citeproc_styles', 'csl')
+    ->fields('csl', array('filename', 'id', 'sha1', 'title', 'parent', 'changed', 'updated'))
+    ->orderBy('filename', 'ASC')
+    ->execute();
+
+    foreach ($result as $style) {
+      $context['sandbox']['installed'][] = $style;
+    }
+
+    $context['sandbox']['progress'] = 0;
+    $context['results']['update_count'] = 0;
+    $context['results']['updated'] = array();
+  }
+
+  if (!empty($zipname)) {
+    //variable_del('github_zip');
+    $zip = zip_open($zipname);
+    $za = new ZipArchive();
+
+    if ($za->open($zipname) !== TRUE) {
+      $message = t('Could not open zip file containing styles: @file', array('@file' => realpath($zipname)));
+      $message = check_plain($message);
+      drupal_set_message($message, 'error');
+      $context['finished'] = 1;
+      return;
+    }
+
+    $num_files = count($context['sandbox']['installed']);
+    $start = $context['sandbox']['progress'];
+    $end = min(($start+10), $num_files);
+
+    for ($i = $start; $i < $end; $i++) {
+      $name = $context['sandbox']['installed'][$i]->filename;
+      $changed = $context['sandbox']['installed'][$i]->changed;
+      if (($index = $za->locateName($name, ZIPARCHIVE::FL_NOCASE|ZIPARCHIVE::FL_NODIR))  !== FALSE) {
+        if ($csl = $za->getFromIndex($index) && !$changed) {
+          $ret = _install_csl($name, $csl, NULL, NULL, TRUE);
+          if ($ret == 2) {
+            $context['results']['updated'][] = $name;
+            $context['message'] = t('Updated') . ': ' . $name;
+          }
+        }
+      }
+      $context['sandbox']['progress']++;
+    }
+    $za->close();
+
+    if ($context['sandbox']['progress'] != $num_files) {
+      $context['finished'] = $context['sandbox']['progress'] / $num_files;
+    }
+  }
+}
+
+function biblio_citeproc_update_installed_finished($success, $results, $operations) {
+  if ($success) {
+    if (count($results['updated'])) {
+      $message = format_plural(count($results['updated']), 'The following style was updated.', 'The following @count styles were updated.');
+      drupal_set_message($message);
+      foreach ($results['updated'] as $style) {
+        drupal_set_message($style);
+      }
+    }
+    else {
+      $message = t('No updates were found, all styles are current.');
+      drupal_set_message($message);
+    }
+  }
+  else {
+    drupal_set_message(t('Finished with an error.'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/biblio_citeproc.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Biblio - CiteProc
+description = Adds Citation Style Language (CSL) citation processing 
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = CSL.inc
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/biblio_citeproc.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,343 @@
+<?php
+function biblio_citeproc_install() {
+  biblio_citeproc_install_default_styles();
+  _save_csl_maps();
+}
+
+function biblio_citeproc_requirements($phase) {
+  $requirements = array();
+  // Ensure translations don't break at install time
+  $t = get_t();
+
+  if ($phase == 'install') {
+
+    if (function_exists('mb_strtoupper')) {
+      $mbs_severity = REQUIREMENT_OK;
+      $mbs_desc = $t('PHP "Multibyte String" extension is enabled');
+    }
+    else {
+      $mbs_severity = REQUIREMENT_ERROR;
+      $mbs_desc = $t('Your PHP installation does not have the "Multibyte String" extension enabled, Biblio - CiteProc requires the Multibyte String extension');
+    }
+    $requirements['mbs'] = array(
+          'title' => $t('PHP Multibyte String'),
+          'severity' => $mbs_severity,
+          'description' => $mbs_desc,
+    );
+  }
+  return $requirements;
+}
+
+function biblio_citeproc_uninstall() {
+  if (db_table_exists('biblio_type_maps')) {
+    db_delete('biblio_type_maps')
+      ->condition('format', 'csl')
+      ->execute();
+  }
+  if ($file = variable_get('biblio_citeproc_styles_zip_file', NULL)) {
+    file_usage_delete($file, 'biblio_citeproc');
+    file_delete($file);
+  }
+  cache_clear_all('biblio_citeproc_styles', 'cache');
+  variable_del('biblio_citeproc_styles_zip_file');
+  variable_del('biblio_citeproc_style');
+}
+
+function biblio_citeproc_schema() {
+  $schema['biblio_citeproc_styles'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+       ),
+      'title' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+       ),
+      'filename' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+       ),
+      'parent' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'default' => ''
+       ),
+       'summary' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        ),
+       'csl' => array(
+        'type' => 'blob',
+        'not null' => TRUE
+       ),
+       'sha1' => array(
+        'type' => 'varchar',
+        'length' => 40,
+        'not null' => TRUE,
+        'default' => ''
+       ),
+       'changed' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+       ),
+       'updated' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+       ),
+    ),
+    'primary key' => array('id')
+  );
+
+  return $schema;
+}
+
+function biblio_citeproc_install_default_styles() {
+  $record = array();
+  $dir = drupal_get_path('module', 'biblio_citeproc') . '/style';
+  $files = file_scan_directory($dir, '/..*.csl$/');
+
+  foreach ($files as $file) {
+    $csl = file_get_contents($file->uri);
+    $name = basename($file->filename);
+    biblio_citeproc_install_style($name, $csl);
+  }
+}
+
+function biblio_citeproc_update_default_styles() {
+  biblio_citeproc_install_default_styles();
+}
+
+function _get_csl_type_map() {
+  $map['type_map'] = serialize(
+        array(
+              'article'                 => '',
+              'article-magazine'        => 106,
+              'article-newspaper'       => 105,
+              'article-journal'         => 102,
+              'bill'                    => 117,
+              'book'                    => 100,
+              'broadcast'               => 111,
+              'chapter'                 => 101,
+              'entry'                   => '',
+              'entry-dictionary'        => '',
+              'entry-encyclopedia'      => '',
+              'figure'                  => '',
+              'graphic'                 => '',
+              'interview'               => '',
+              'legislation'             => 118,
+              'legal_case'              => 128,
+              'manuscript'              => 121,
+              'map'                     => 122,
+              'motion_picture'          => 110,
+              'musical_score'           => '',
+              'pamphlet'                => '',
+              'paper-conference'        => 103,
+              'patent'                  => 119,
+              'post'                    => '',
+              'post-weblog'             => '',
+              'personal\_communication' => 120,
+              'report'                  => 109,
+              'review'                  => '',
+              'review-book'             => '',
+              'song'                    => '',
+              'speech'                  => '',
+              'thesis'                  => 108,
+              'treaty'                  => '',
+              'webpage'                 => 107,
+        )
+  );
+  $map['format'] = 'csl';
+  return $map;
+}
+function _get_csl_type_names() {
+  $map['type_names'] =  serialize(
+        array(
+              'article'                 => '',
+              'article-magazine'        => "Magazine Article",
+              'article-newspaper'       => "Newspaper Article",
+              'article-journal'         => "Journal Article",
+              'bill'                    => 'Bill',
+              'book'                    => "Book",
+              'broadcast'               => 'Broadcast',
+              'chapter'                 => "Book Section",
+              'entry'                   => '',
+              'entry-dictionary'        => '',
+              'entry-encyclopedia'      => '',
+              'figure'                  => '',
+              'graphic'                 => '',
+              'interview'               => '',
+              'legislation'             => 'Legislation',
+              'legal_case'              => 'Legal Ruling',
+              'manuscript'              => 'Manuscript',
+              'map'                     => 'Map',
+              'motion_picture'          => "Film or Broadcast",
+              'musical_score'           => '',
+              'pamphlet'                => '',
+              'paper-conference'        => "Conference Paper",
+              'patent'                  => "Patent",
+              'post'                    => '',
+              'post-weblog'             => '',
+              'personal\_communication' => 'Personal Communication',
+              'report'                  => "Report",
+              'review'                  => '',
+              'review-book'             => '',
+              'song'                    => '',
+              'speech'                  => '',
+              'thesis'                  => "Thesis",
+              'treaty'                  => '',
+              'webpage'                 => "Web Page",
+         )
+  );
+
+  $map['format'] = 'csl';
+  return $map;
+}
+
+function _get_csl_field_map() {
+  $map['field_map'] =  serialize(
+        array(
+          'title'                       => 'title',
+          'container-title'             => 'biblio_secondary_title',
+          'collection-title'            => 'biblio_secondary_title',
+          'original-title'              => 'biblio_alternate_title',
+          'publisher'                   => 'biblio_publisher',
+          'publisher-place'             => 'biblio_place_published',
+          'original-publisher'          => '',
+          'original-publisher-place'    => '',
+          'archive'                     => '',
+          'archive-place'               => '',
+          'authority'                   => '',
+          'archive_location'            => '',
+          'event'                       => 'biblio_secondary_title',
+          'event-place'                 => 'biblio_place_published',
+          'page'                        => 'biblio_pages',
+          'page-first'                  => '',
+          'locator'                     => '',
+          'version'                     => 'biblio_edition',
+          'volume'                      => 'biblio_volume',
+          'number-of-volumes'           => 'biblio_number_of_volumes',
+          'number-of-pages'             => '',
+          'issue'                       => 'biblio_issue',
+          'chapter-number'              => 'biblio_section',
+          'medium'                      => '',
+          'status'                      => '',
+          'edition'                     => 'biblio_edition',
+          'section'                     => 'biblio_section',
+          'genre'                       => '',
+          'note'                        => 'biblio_notes',
+          'annote'                      => '',
+          'abstract'                    => 'biblio_abst_e',
+          'keyword'                     => 'biblio_keywords',
+          'number'                      => 'biblio_number',
+          'references'                  => '',
+          'URL'                         => 'biblio_url',
+          'DOI'                         => 'biblio_doi',
+          'ISBN'                        => 'biblio_isbn',
+          'call-number'                 => 'biblio_call_number',
+          'citation-number'             => '',
+          'citation-label'              => 'biblio_citekey',
+          'first-reference-note-number' => '',
+          'year-suffix'                 => '',
+          'jurisdiction'                => '',
+
+        //Date Variables'
+
+          'issued'                      => 'biblio_year',
+          'event'                       => 'biblio_date',
+          'accessed'                    => 'biblio_access_date',
+          'container'                   => 'biblio_date',
+          'original-date'               => 'biblio_date',
+
+        //Name Variables'
+
+          'author'                      => 'biblio_contributors:1',
+          'editor'                      => 'biblio_contributors:2',
+          'translator'                  => 'biblio_contributors:3',
+          'recipient'                   => '',
+          'interviewer'                 => 'biblio_contributors:1',
+          'publisher'                   => 'biblio_publisher',
+          'composer'                    => 'biblio_contributors:1',
+          'original-publisher'          => '',
+          'original-author'             => '',
+          'container-author'            => '',
+          'collection-editor'           => '',
+         )
+        );
+  $map['format'] = 'csl';
+  return $map;
+}
+
+function _save_csl_maps() {
+  $typemap = _get_csl_type_map();
+  $typenames = _get_csl_type_names();
+  $fieldmap = _get_csl_field_map();
+  $maps = array_merge($typemap, $typenames, $fieldmap);
+  biblio_save_map($maps);
+}
+
+function _reset_csl_map($type = NULL) {
+  $count = db_query("SELECT COUNT(*) FROM {biblio_type_maps} WHERE format='csl'")->fetchField();
+  if ($count && $type) { //update
+    $function = '_get_csl_' . $type;
+    if (!function_exists($function)) return;
+    $map = $function();
+    db_update('biblio_type_maps')
+      ->fields($map)
+      ->condition('format', 'csl')
+      ->execute();
+  }
+  else { // install
+    db_delete('biblio_type_maps')
+      ->condition('format', 'csl')
+      ->execute();
+    _save_csl_maps();
+  }
+}
+/**
+ *
+ * Adds CSL field and type maps to biblio_type_maps table
+ */
+function biblio_citeproc_update_7001() {
+  _reset_csl_map();
+}
+/**
+ *
+ * Updates the default CSL styles
+ */
+function biblio_citeproc_update_7002() {
+  biblio_citeproc_update_default_styles();
+}
+/**
+ * Adds "changed" and "updated" columns
+ *
+ */
+function biblio_citeproc_update_7003() {
+  $spec = array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+       );
+   db_add_field('biblio_citeproc_styles', 'changed', $spec);
+   db_add_field('biblio_citeproc_styles', 'updated', $spec);
+}
+/**
+ * Corrects an error in the field_map
+ *
+ */
+function biblio_citeproc_update_7004() {
+  $map = biblio_get_map('field_map', 'csl');
+  if ($map['accessed'] == 'biblio_accessed') {
+    $map['accessed'] = 'biblio_access_date';
+    biblio_set_map('field_map', 'csl', $map);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/biblio_citeproc.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,191 @@
+<?php
+function biblio_citeproc_menu() {
+  global $user;
+  $items = array();
+  $items['admin/config/content/biblio/citeproc'] = array(
+    'title'             => 'CiteProc',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_citeproc_style_manager_form'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => 'biblio_citeproc.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => 12
+  );
+  $items['admin/config/content/biblio/citeproc/styles'] = array(
+    'title'             => 'CiteProc Style Manager',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_citeproc_style_manager_form'),
+    'access arguments'  => array('administer biblio'),
+    'file'              => 'biblio_citeproc.admin.inc',
+    'type'              => MENU_DEFAULT_LOCAL_TASK,
+    'weight'            => 12
+  );
+  $items['admin/config/content/biblio/citeproc/styles/%/edit'] = array(
+    'title'             => 'CiteProc Style Editor',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_citeproc_csl_editor', 6),
+    'access arguments'  => array('administer biblio'),
+    'file'              => 'biblio_citeproc.admin.inc',
+    'type'              => MENU_CALLBACK,
+    'weight'            => 12
+  );
+  $items['admin/config/content/biblio/citeproc/map'] = array(
+    'title'             => 'CSL Field Mapper',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('biblio_admin_io_mapper_form', 'csl', FALSE),
+    'access arguments'  => array('administer biblio'),
+    'file'              =>  '../../includes/biblio.admin.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => 12
+  );
+  return $items;
+}
+function biblio_citeproc_theme() {
+  return array(
+    'biblio_citeproc_style' => array(
+      'file' => 'biblio_citeproc.module',
+      'variables' => array(
+        'node' => '',
+        'style_name' => 'cse',
+      ),
+    ),
+    'biblio_citeproc_style_manager_form' => array(
+      'render element' => 'form',
+    ),
+  );
+}
+
+/**
+ * Implements hook_biblio_map_alter().
+ */
+function biblio_citeproc_biblio_map_alter(&$map, $type, $format) {
+  if ($type == 'field_map' && $format == 'csl') {
+    $map = array_merge($map, array(
+      'author'                      => 'biblio_contributors:1',
+      'editor'                      => 'biblio_contributors:2',
+      'translator'                  => 'biblio_contributors:3',
+      'recipient'                   => ':',
+      'interviewer'                 => ':',
+      'composer'                    => ':',
+    ));
+  }
+}
+
+function biblio_citeproc_theme_registry_alter(&$theme_registry) {
+  $theme_registry['biblio_style'] = $theme_registry['biblio_citeproc_style'];
+}
+
+function biblio_citeproc_load_csl($csl_id) {
+  $csl_file_contents = '';
+  if (strpos($csl_id, '.csl') === FALSE) {// try to convert old style names to csl...
+    if (in_array($csl_id, array('ama', 'apa', 'cse', 'ieee', 'mla', 'vancouver'))) {
+      $csl_id .= '.csl';
+    }
+    elseif ($csl_id == 'chicago') {
+      $csl_id = 'chicago-fullnote-bibliography.csl';
+    }
+    else {
+      $csl_id = '';
+      $message = t('An invalid style "@style" was selected, please check your "CiteProc" style settings.', array('@style' => $csl_id));
+      drupal_set_message($message, 'error');
+    }
+  }
+  if (!empty($csl_id)) {
+    $csl = db_query('SELECT parent,csl FROM {biblio_citeproc_styles} WHERE filename = :id', array(':id' => $csl_id))->fetchObject();
+    if (!isset($csl->csl)) {
+      drupal_set_message(t('Biblio-CiteProc could not fetch the style file: @csl_id from the database. Check your CiteProc settings.', array('@csl_id' => $csl_id)), 'error');
+      return;
+    }
+    if (!empty($csl->parent)) {
+      $csl_file_contents = db_query("SELECT csl FROM {biblio_citeproc_styles} WHERE id = :id", array(':id' => $csl->parent))->fetchField();
+
+    }
+    else {
+      $csl_file_contents = $csl->csl;
+    }
+  }
+  return $csl_file_contents;
+}
+
+function theme_biblio_citeproc_style($variables) {
+  static $citeproc;
+  global $language;
+  $cached = NULL;
+  $node = $variables['node'];
+  $style = isset($variables['style_name']) ? $variables['style_name'] : NULL;
+
+  module_load_include('inc', 'biblio_citeproc', 'CSL');
+
+  if (!$citeproc) {
+    $csl_id = ($style) ? $style : biblio_get_style();
+    if ($csl_file_contents = biblio_citeproc_load_csl($csl_id)) {
+      //    $cslid = $csl_file_name . '-' . $language->language;
+      //    $cached = cache_get($cslid, 'cache_biblio_csl_object');
+      if (!$cached) {
+        $citeproc = new citeproc($csl_file_contents, $language->language);
+        //      cache_set($cslid, $citeproc, 'cache_biblio_csl_object');
+      }
+      else {
+        $citeproc = $cached->data;
+      }
+    }
+  }
+
+  $output = '';
+  if ($citeproc) {
+    $styled_node = $citeproc->render($node);
+    $coins_data = isset($node->biblio_coins) ? filter_xss($node->biblio_coins, array('span')) : '';
+    $output = $styled_node . $coins_data;
+  }
+
+  return $output;
+}
+
+function biblio_citeproc_csl_map_reset($type = NULL) {
+  module_load_include('install', 'biblio_citeproc', 'biblio_citeproc');
+  _reset_csl_map($type);
+}
+
+function biblio_citeproc_install_style($name, $csl) {
+
+  $xml = simplexml_load_string($csl);
+
+  $parent = '';
+  foreach ($xml->info->link as $link) {
+    $attrs = $link->attributes();
+    if (isset($attrs['rel']) && $attrs['rel'] == 'independent-parent') {
+      $parent = (string)$attrs['href'];
+    }
+  }
+
+  $old_sha1 = NULL;
+
+  $old_sha1 = db_query('SELECT sha1 FROM {biblio_citeproc_styles} WHERE id = :id', array(':id' => (string)$xml->info->id))->fetchField();
+
+  $record  = array(
+          'filename' => $name,
+          'parent'   => $parent,
+          'title'    => (string)$xml->info->title,
+          'summary'  => (string)$xml->info->summary,
+          'csl'      => $csl,
+          'sha1'     => sha1($csl),
+          'id'       => (string)$xml->info->id,
+  );
+
+  if ($old_sha1 && $old_sha1 == sha1($csl)) {     //style exists and has not changed
+    return;
+  }
+  elseif ($old_sha1 && $old_sha1 != sha1($csl)) { // update an existing style
+     $query = db_update('biblio_citeproc_styles')
+        ->fields($record)
+        ->condition('id', $record['id']);
+  }
+  elseif (!$old_sha1) {                           //install new style
+    $query = db_insert('biblio_citeproc_styles')
+           ->fields(array('id', 'title', 'filename', 'summary', 'csl', 'sha1'));
+
+    $query->values($record);
+  }
+  $query->execute();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-af-ZA.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="af-ZA">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric-leading-zeros" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="/"/>
+  </date>
+  <terms>
+    <term name="accessed">toegang verkry</term>
+    <term name="and">en</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">voorhande</term>
+    <term name="from">van</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">opgehaal</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>reël</single>
+      <multiple>reëls</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>bladsy</single>
+      <multiple>bladsye</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraaf</single>
+      <multiple>paragrawe</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk</term>
+    <term name="chapter" form="short">chap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">no</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>bl</single>
+      <multiple>bll</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>redakteur</single>
+      <multiple>redakteurs</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>vertaler</single>
+      <multiple>vertalers</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>red</single>
+      <multiple>reds</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>vert</single>
+      <multiple>verts</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">onder redaksie van</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">vertaal deur</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">red</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">verts</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Januarie</term>
+    <term name="month-02">Februarie</term>
+    <term name="month-03">Maart</term>
+    <term name="month-04">April</term>
+    <term name="month-05">Mei</term>
+    <term name="month-06">Junie</term>
+    <term name="month-07">Julie</term>
+    <term name="month-08">Augustus</term>
+    <term name="month-09">September</term>
+    <term name="month-10">Oktober</term>
+    <term name="month-11">November</term>
+    <term name="month-12">Desember</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan</term>
+    <term name="month-02" form="short">Feb</term>
+    <term name="month-03" form="short">Mrt</term>
+    <term name="month-04" form="short">Apr</term>
+    <term name="month-05" form="short">Mei</term>
+    <term name="month-06" form="short">Jun</term>
+    <term name="month-07" form="short">Jul</term>
+    <term name="month-08" form="short">Aug</term>
+    <term name="month-09" form="short">Sep</term>
+    <term name="month-10" form="short">Okt</term>
+    <term name="month-11" form="short">Nov</term>
+    <term name="month-12" form="short">Des</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-ar-AR.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="ar-AR">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=", "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" suffix="/"/>
+    <date-part name="month" form="numeric" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">تاريخ الوصول</term>
+    <term name="and">Ùˆ</term>
+    <term name="and others">وآخرون</term>
+    <term name="anonymous">مجهول</term>
+    <term name="anonymous" form="short">مجهول</term>
+    <term name="at">عند</term>
+    <term name="by">عن طريق</term>
+    <term name="circa">حوالي</term>
+    <term name="circa" form="short">حو.</term>
+    <term name="cited">وثق</term>
+    <term name="edition">
+      <single>الطبعة</single>
+      <multiple>الطبعات</multiple>
+    </term>
+    <term name="edition" form="short">Ø·.</term>
+    <term name="et-al">وآخ.</term>
+    <term name="forthcoming">التالي</term>
+    <term name="from">من</term>
+    <term name="ibid">المرجع السابق</term>
+    <term name="in">ÙÙŠ</term>
+    <term name="in press">قيد النشر</term>
+    <term name="internet">انترنت</term>
+    <term name="interview">مقابلة</term>
+    <term name="letter">خطاب</term>
+    <term name="no date">دون تاريخ</term>
+    <term name="no date" form="short">د.ت</term>
+    <term name="online">على الخط المباشر</term>
+    <term name="presented at">Ù‚ÙØ¯Ù‘ÙŽÙ… ÙÙŠ</term>
+    <term name="reference">
+      <single>مرجع</single>
+      <multiple>مراجع</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>مرجع</single>
+      <multiple>مراجع</multiple>
+    </term>
+    <term name="retrieved">استرجع ÙÙŠ</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">ب.م.</term>
+    <term name="bc">Ù‚.Ù….</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://www.w3.org/International/tutorials/bidi-xhtml/ -->
+    <!-- Use of single straight quote for inner is a guess -->
+    <term name="open-quote">"</term>
+    <term name="close-quote">"</term>
+    <term name="open-inner-quote">'</term>
+    <term name="close-inner-quote">'</term>
+
+    <!-- ORDINALS st., nd., rd.-->
+    <term name="ordinal-01"/>
+    <term name="ordinal-02"/>
+    <term name="ordinal-03"/>
+    <term name="ordinal-04"/>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">الاول</term>
+    <term name="long-ordinal-02">الثاني</term>
+    <term name="long-ordinal-03">الثالث</term>
+    <term name="long-ordinal-04">الرابع</term>
+    <term name="long-ordinal-05">الخامس</term>
+    <term name="long-ordinal-06">السادس</term>
+    <term name="long-ordinal-07">السابع</term>
+    <term name="long-ordinal-08">الثامن</term>
+    <term name="long-ordinal-09">التاسع</term>
+    <term name="long-ordinal-10">العاشر</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">الاناسة</term>
+    <term name="astronomy">الÙلك</term>
+    <term name="biology">الأحياء</term>
+    <term name="botany">النبات</term>
+    <term name="chemistry">الكيمياء</term>
+    <term name="engineering">الهندسة</term>
+    <term name="generic-base">العلوم العامة</term>
+    <term name="geography">الجغراÙيا</term>
+    <term name="geology">الجيولوجيا</term>
+    <term name="history">التاريخ</term>
+    <term name="humanities">الإنسانيات</term>
+    <term name="linguistics">اللغويات</term>
+    <term name="literature">الأدب</term>
+    <term name="math">الرياضيات</term>
+    <term name="medicine">الطب</term>
+    <term name="philosophy">الÙÙ„Ø³ÙØ©</term>
+    <term name="physics">الÙيزياء</term>
+    <term name="psychology">علم Ø§Ù„Ù†ÙØ³</term>
+    <term name="sociology">علم الإجتماع</term>
+    <term name="science">العلوم البحتة</term>
+    <term name="political_science">العلوم السياسية</term>
+    <term name="social_science">العلوم الإجتماعية</term>
+    <term name="theology">الإلهيات</term>
+    <term name="zoology">علم الحيوان</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>كتاب</single>
+      <multiple>كتب</multiple>
+    </term>
+    <term name="chapter">
+      <single>ÙØµÙ„</single>
+      <multiple>ÙØµÙˆÙ„</multiple>
+    </term>
+    <term name="column">
+      <single>عمود</single>
+      <multiple>أعمدة</multiple>
+    </term>
+    <term name="figure">
+      <single>رسم توضيحي</single>
+      <multiple>رسوم توضيحية</multiple>
+    </term>
+    <term name="folio">
+      <single>ورقة</single>
+      <multiple>أوراق</multiple>
+    </term>
+    <term name="issue">
+      <single>عدد</single>
+      <multiple>أعداد</multiple>
+    </term>
+    <term name="line">
+      <single>سطر</single>
+      <multiple>أسطر</multiple>
+    </term>
+    <term name="note">
+      <single>ملاحظة</single>
+      <multiple>ملاحظات</multiple>
+    </term>
+    <term name="opus">
+      <single>نوته موسيقية</single>
+      <multiple>نوت موسيقية</multiple>
+    </term>
+    <term name="page">
+      <single>ØµÙØ­Ø©</single>
+      <multiple>ØµÙØ­Ø§Øª</multiple>
+    </term>
+    <term name="paragraph">
+      <single>Ùقرة</single>
+      <multiple>Ùقرات</multiple>
+    </term>
+    <term name="part">
+      <single>جزء</single>
+      <multiple>أجزاء</multiple>
+    </term>
+    <term name="section">
+      <single>قسم</single>
+      <multiple>أقسام</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>ØªÙØ³ÙŠØ± ÙØ±Ø¹ÙŠ</single>
+      <multiple>ØªÙØ³ÙŠØ±Ø§Øª ÙØ±Ø¹ÙŠØ©</multiple>
+    </term>
+    <term name="verse">
+      <single>بيت شعر</single>
+      <multiple>أبيات شعر</multiple>
+    </term>
+    <term name="volume">
+      <single>مجلد</single>
+      <multiple>مجلدات</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">كتاب</term>
+    <term name="chapter" form="short">ÙØµÙ„</term>
+    <term name="column" form="short">عمود</term>
+    <term name="figure" form="short">رسم توضيحي</term>
+    <term name="folio" form="short">مطوية</term>
+    <term name="issue" form="short">عدد</term>
+    <term name="opus" form="short">نوتة موسيقية</term>
+    <term name="page" form="short">
+      <single>ص</single>
+      <multiple>ص.ص.</multiple>
+    </term>
+    <term name="paragraph" form="short">Ùقرة</term>
+    <term name="part" form="short">ج.</term>
+    <term name="section" form="short">قسم</term>
+    <term name="sub verbo" form="short">
+      <single>ØªÙØ³ÙŠØ± ÙØ±Ø¹ÙŠ</single>
+      <multiple>ØªÙØ³ÙŠØ±Ø§Øª ÙØ±Ø¹ÙŠØ©</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>بيت شعر</single>
+      <multiple>أبيات شعر</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>مج.</single>
+      <multiple>مج.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single>مؤلÙ</single>
+      <multiple>مؤلÙين</multiple>
+    </term>
+    <term name="editor">
+      <single>محرر</single>
+      <multiple>محررين</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>رئيس التحرير</single>
+      <multiple>رؤساء التحرير</multiple>
+    </term>
+    <term name="translator">
+      <single>مترجم</single>
+      <multiple>مترجمين</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>مترجم ومحرر</single>
+      <multiple>مترجمين ومحررين</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single>مؤلÙ</single>
+      <multiple>مؤلÙين</multiple>
+    </term>
+    <term name="editor" form="short">
+      <single>محرر</single>
+      <multiple>محررين</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>مشر٠على الطبعة</single>
+      <multiple>مشرÙين على الطبعة</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>مترجم</single>
+      <multiple>مترجمين</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>مترجم ومشر٠على الطباعه</single>
+      <multiple>مترجمين ومشرÙين على الطباعه</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">تحرير</term>
+    <term name="editorial-director" form="verb">اعداد</term>
+    <term name="translator" form="verb">ترجمة</term>
+    <term name="editortranslator" form="verb">اعداد وترجمة</term>
+    <term name="recipient" form="verb">مرسل الى</term>
+    <term name="interviewer" form="verb">مقابلة بواسطة</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short"></term>
+    <term name="editor" form="verb-short">تحرير</term>
+    <term name="editorial-director" form="verb-short">اشر٠على الطبعة</term>
+    <term name="translator" form="verb-short">ترجمة</term>
+    <term name="editortranslator" form="verb-short">ترجمه واشر٠على الطباعه</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">يناير</term>
+    <term name="month-02">ÙØ¨Ø±Ø§ÙŠØ±</term>
+    <term name="month-03">مارس</term>
+    <term name="month-04">ابريل</term>
+    <term name="month-05">مايو</term>
+    <term name="month-06">يونيو</term>
+    <term name="month-07">يوليو</term>
+    <term name="month-08">اغسطس</term>
+    <term name="month-09">سبتمبر</term>
+    <term name="month-10">اكتوبر</term>
+    <term name="month-11">نوÙمبر</term>
+    <term name="month-12">ديسمبر</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">يناير</term>
+    <term name="month-02" form="short">ÙØ¨Ø±Ø§ÙŠØ±</term>
+    <term name="month-03" form="short">مارس</term>
+    <term name="month-04" form="short">ابريل</term>
+    <term name="month-05" form="short">مايو</term>
+    <term name="month-06" form="short">يونيو</term>
+    <term name="month-07" form="short">يوليو</term>
+    <term name="month-08" form="short">اغسطس</term>
+    <term name="month-09" form="short">سبتمبر</term>
+    <term name="month-10" form="short">اكتوبر</term>
+    <term name="month-11" form="short">نوÙمبر</term>
+    <term name="month-12" form="short">ديسمبر</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">الربيع</term>
+    <term name="season-02">الصيÙ</term>
+    <term name="season-03">الخريÙ</term>
+    <term name="season-04">الشتاء</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-bg-BG.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="bg-BG">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric-leading-zeros" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">отворен на</term>
+    <term name="and">и</term>
+    <term name="and others">и други</term>
+    <term name="anonymous">анонимен</term>
+    <term name="anonymous" form="short">анон</term>
+    <term name="at">в</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">цитиран</term>
+    <term name="edition">
+      <single>издание</single>
+      <multiple>изданиÑ</multiple>
+    </term>
+    <term name="edition" form="short">изд</term>
+    <term name="et-al">и Ñъавт.</term>
+    <term name="forthcoming">предÑтоÑщ</term>
+    <term name="from">от</term>
+    <term name="ibid">пак там</term>
+    <term name="in">в</term>
+    <term name="in press">под печат</term>
+    <term name="internet">интернет</term>
+    <term name="interview">интервю</term>
+    <term name="letter">пиÑмо</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">без дата</term>
+    <term name="online">онлайн</term>
+    <term name="presented at">предÑтавен на</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">изтеглен на</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">„</term>
+    <term name="close-inner-quote">“</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">антропологиÑ</term>
+    <term name="astronomy">аÑтрономиÑ</term>
+    <term name="biology">биологиÑ</term>
+    <term name="botany">ботаника</term>
+    <term name="chemistry">химиÑ</term>
+    <term name="engineering">инженерÑтво</term>
+    <term name="generic-base">обща база</term>
+    <term name="geography">географиÑ</term>
+    <term name="geology">геологиÑ</term>
+    <term name="history">иÑториÑ</term>
+    <term name="humanities">хуманитарни науки</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">литература</term>
+    <term name="math">математика</term>
+    <term name="medicine">медицина</term>
+    <term name="philosophy">филоÑофиÑ</term>
+    <term name="physics">физика</term>
+    <term name="psychology">физиологиÑ</term>
+    <term name="sociology">ÑоциологиÑ</term>
+    <term name="science">наука</term>
+    <term name="political_science">политичеÑки науки</term>
+    <term name="social_science">общеÑтвени науки</term>
+    <term name="theology">теологиÑ</term>
+    <term name="zoology">зоологиÑ</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>книга</single>
+      <multiple>книги</multiple>
+    </term>
+    <term name="chapter">
+      <single>глава</single>
+      <multiple>глави</multiple>
+    </term>
+    <term name="column">
+      <single>колона</single>
+      <multiple>колони</multiple>
+    </term>
+    <term name="figure">
+      <single>фигура</single>
+      <multiple>фигури</multiple>
+    </term>
+    <term name="folio">
+      <single>фолио</single>
+      <multiple>фолиÑ</multiple>
+    </term>
+    <term name="issue">
+      <single>брой</single>
+      <multiple>броеве</multiple>
+    </term>
+    <term name="line">
+      <single>ред</single>
+      <multiple>редове</multiple>
+    </term>
+    <term name="note">
+      <single>бележка</single>
+      <multiple>бележки</multiple>
+    </term>
+    <term name="opus">
+      <single>опуÑ</single>
+      <multiple>опуÑи</multiple>
+    </term>
+    <term name="page">
+      <single>Ñтраница</single>
+      <multiple>Ñтраници</multiple>
+    </term>
+    <term name="paragraph">
+      <single>параграф</single>
+      <multiple>параграфи</multiple>
+    </term>
+    <term name="part">
+      <single>чаÑÑ‚</single>
+      <multiple>чаÑти</multiple>
+    </term>
+    <term name="section">
+      <single>раздел</single>
+      <multiple>раздели</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>Ñтих</single>
+      <multiple>Ñтихове</multiple>
+    </term>
+    <term name="volume">
+      <single>том</single>
+      <multiple>томове</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">кн</term>
+    <term name="chapter" form="short">гл</term>
+    <term name="column" form="short">кол</term>
+    <term name="figure" form="short">фиг</term>
+    <term name="folio" form="short">фол</term>
+    <term name="issue" form="short">бр</term>
+    <term name="opus" form="short">оп</term>
+    <term name="page" form="short">
+      <single>Ñ</single>
+      <multiple>Ñ-ци</multiple>
+    </term>
+    <term name="paragraph" form="short">п</term>
+    <term name="part" form="short">ч</term>
+    <term name="section" form="short">разд</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>ÑÑ‚</single>
+      <multiple>ÑÑ‚-ове</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>том</single>
+      <multiple>т-ове</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single>автор</single>
+      <multiple>автори</multiple>
+    </term>
+    <term name="editor">
+      <single>редактор</single>
+      <multiple>редактори</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>преводач</single>
+      <multiple>преводачи</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single>авт</single>
+      <multiple>авт-ри</multiple>
+    </term>
+    <term name="editor" form="short">
+      <single>ред</single>
+      <multiple>ред-ри</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>прев</single>
+      <multiple>прев-чи</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">редактиран от</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">преведен от</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">до</term>
+    <term name="interviewer" form="verb">интервюиран от</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ред</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">прев</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Януари</term>
+    <term name="month-02">Февруари</term>
+    <term name="month-03">Март</term>
+    <term name="month-04">Ðприл</term>
+    <term name="month-05">Май</term>
+    <term name="month-06">Юни</term>
+    <term name="month-07">Юли</term>
+    <term name="month-08">ÐвгуÑÑ‚</term>
+    <term name="month-09">Септември</term>
+    <term name="month-10">Октомври</term>
+    <term name="month-11">Ðоември</term>
+    <term name="month-12">Декември</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Яну</term>
+    <term name="month-02" form="short">Фев</term>
+    <term name="month-03" form="short">Мар</term>
+    <term name="month-04" form="short">Ðпр</term>
+    <term name="month-05" form="short">Май</term>
+    <term name="month-06" form="short">Юни</term>
+    <term name="month-07" form="short">Юли</term>
+    <term name="month-08" form="short">Ðвг</term>
+    <term name="month-09" form="short">Сеп</term>
+    <term name="month-10" form="short">Окт</term>
+    <term name="month-11" form="short">Ðое</term>
+    <term name="month-12" form="short">Дек</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-ca-AD.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="ca-AD">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">accedit</term>
+    <term name="and">i</term>
+    <term name="and others">i altres</term>
+    <term name="anonymous">anònim</term>
+    <term name="anonymous" form="short">anòn.</term>
+    <term name="at">a</term>
+    <term name="by">per</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">citat</term>
+    <term name="edition">
+      <single>edició</single>
+      <multiple>edicions</multiple>
+    </term>
+    <term name="edition" form="short">ed.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">previst</term>
+    <term name="from">de</term>
+    <term name="ibid">ibíd.</term>
+    <term name="in">en</term>
+    <term name="in press">en impremta</term>
+    <term name="internet">internet</term>
+    <term name="interview">entrevista</term>
+    <term name="letter">carta</term>
+    <term name="no date">sense data</term>
+    <term name="no date" form="short">s.d.</term>
+    <term name="online">en línia</term>
+    <term name="presented at">presentat a</term>
+    <term name="reference">
+      <single>referència</single>
+      <multiple>referències</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>ref.</multiple>
+    </term>
+    <term name="retrieved">recuperat</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">dC</term>
+    <term name="bc">aC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">“</term>
+    <term name="close-inner-quote">â€</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">a</term>
+    <term name="ordinal-02">a</term>
+    <term name="ordinal-03">a</term>
+    <term name="ordinal-04">a</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">primera</term>
+    <term name="long-ordinal-02">segona</term>
+    <term name="long-ordinal-03">tercera</term>
+    <term name="long-ordinal-04">quarta</term>
+    <term name="long-ordinal-05">cinquena</term>
+    <term name="long-ordinal-06">sisena</term>
+    <term name="long-ordinal-07">setena</term>
+    <term name="long-ordinal-08">vuitena</term>
+    <term name="long-ordinal-09">novena</term>
+    <term name="long-ordinal-10">desena</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologia</term>
+    <term name="astronomy">astronomia</term>
+    <term name="biology">biologia</term>
+    <term name="botany">botànica</term>
+    <term name="chemistry">química</term>
+    <term name="engineering">enginyeria</term>
+    <term name="generic-base">base genèrica</term>
+    <term name="geography">geografia</term>
+    <term name="geology">geologia</term>
+    <term name="history">història</term>
+    <term name="humanities">humanitats</term>
+    <term name="linguistics">lingüística</term>
+    <term name="literature">literatura</term>
+    <term name="math">matemàtiques</term>
+    <term name="medicine">medicina</term>
+    <term name="philosophy">filosofia</term>
+    <term name="physics">física</term>
+    <term name="psychology">psicologia</term>
+    <term name="sociology">sociologia</term>
+    <term name="science">ciències</term>
+    <term name="political_science">ciències polítiques</term>
+    <term name="social_science">ciències socials</term>
+    <term name="theology">teologia</term>
+    <term name="zoology">zoologia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>llibre</single>
+      <multiple>llibres</multiple>
+    </term>
+    <term name="chapter">
+      <single>capítol</single>
+      <multiple>capítols</multiple>
+    </term>
+    <term name="column">
+      <single>columna</single>
+      <multiple>columnes</multiple>
+    </term>
+    <term name="figure">
+      <single>figura</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>foli</single>
+      <multiple>folis</multiple>
+    </term>
+    <term name="issue">
+      <single>número</single>
+      <multiple>números</multiple>
+    </term>
+    <term name="line">
+      <single>línia</single>
+      <multiple>línies</multiple>
+    </term>
+    <term name="note">
+      <single>nota</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>pàgina</single>
+      <multiple>pàgines</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paràgraf</single>
+      <multiple>paràgrafs</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>secció</single>
+      <multiple>seccions</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub voce</single>
+      <multiple>sub vocibus</multiple>
+    </term>
+    <term name="verse">
+      <single>vers</single>
+      <multiple>versos</multiple>
+    </term>
+    <term name="volume">
+      <single>volum</single>
+      <multiple>volums</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">llib.</term>
+    <term name="chapter" form="short">cap.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">f.</term>
+    <term name="issue" form="short">núm.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>p.</multiple>
+    </term>
+    <term name="paragraph" form="short">par.</term>
+    <term name="part" form="short">pt.</term>
+    <term name="section" form="short">sec.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.v.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>v.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vol.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>§</single>
+      <multiple>§</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>traductor</single>
+      <multiple>traductors</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor i traductor</single>
+      <multiple>editors i traductors</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed.</single>
+      <multiple>ed.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>ed.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>trad.</single>
+      <multiple>trad.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. i trad.</single>
+      <multiple>ed. i trad.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">editat per</term>
+    <term name="editorial-director" form="verb">editat per</term>
+    <term name="translator" form="verb">traduït per</term>
+    <term name="editortranslator" form="verb">editat i traduït per</term>
+    <term name="recipient" form="verb">a</term>
+    <term name="interviewer" form="verb">entrevistat per</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">per</term>
+    <term name="editor" form="verb-short">ed.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trad.</term>
+    <term name="editortranslator" form="verb-short">ed. i trad. per</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">gener</term>
+    <term name="month-02">febrer</term>
+    <term name="month-03">març</term>
+    <term name="month-04">abril</term>
+    <term name="month-05">maig</term>
+    <term name="month-06">juny</term>
+    <term name="month-07">juliol</term>
+    <term name="month-08">agost</term>
+    <term name="month-09">setembre</term>
+    <term name="month-10">octubre</term>
+    <term name="month-11">novembre</term>
+    <term name="month-12">desembre</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">gen.</term>
+    <term name="month-02" form="short">febr.</term>
+    <term name="month-03" form="short">març</term>
+    <term name="month-04" form="short">abr.</term>
+    <term name="month-05" form="short">maig</term>
+    <term name="month-06" form="short">juny</term>
+    <term name="month-07" form="short">jul.</term>
+    <term name="month-08" form="short">ag.</term>
+    <term name="month-09" form="short">set.</term>
+    <term name="month-10" form="short">oct.</term>
+    <term name="month-11" form="short">nov.</term>
+    <term name="month-12" form="short">des.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">primavera</term>
+    <term name="season-02">estiu</term>
+    <term name="season-03">tardor</term>
+    <term name="season-04">hivern</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-cs-CZ.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="cs-CZ">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+  </date>
+  <terms>
+    <term name="accessed">přístup</term>
+    <term name="and">a</term>
+    <term name="and others">a další</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">v</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">citován</term>
+    <term name="edition">
+      <single>vydání</single>
+      <multiple>vydání</multiple>
+    </term>
+    <term name="edition" form="short">vyd.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">nadcházející</term>
+    <term name="from">z</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">v</term>
+    <term name="in press">v tisku</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">dopis</term>
+    <term name="no date">bez data</term>
+    <term name="no date" form="short">nedatováno</term>
+    <term name="online">online</term>
+    <term name="presented at">prezentován v</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">získáno</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">n. l.</term>
+    <term name="bc">pÅ™. n. l.</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">‚</term>
+    <term name="close-inner-quote">‘</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">první</term>
+    <term name="long-ordinal-02">druhé</term>
+    <term name="long-ordinal-03">třetí</term>
+    <term name="long-ordinal-04">Ätvrté</term>
+    <term name="long-ordinal-05">páté</term>
+    <term name="long-ordinal-06">šesté</term>
+    <term name="long-ordinal-07">sedmé</term>
+    <term name="long-ordinal-08">osmé</term>
+    <term name="long-ordinal-09">deváté</term>
+    <term name="long-ordinal-10">desáté</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologie</term>
+    <term name="astronomy">astronomie</term>
+    <term name="biology">biologie</term>
+    <term name="botany">botanika</term>
+    <term name="chemistry">chemie</term>
+    <term name="engineering">technika</term>
+    <term name="generic-base">všeobecný základ</term>
+    <term name="geography">geografie</term>
+    <term name="geology">geologie</term>
+    <term name="history">historie</term>
+    <term name="humanities">humanitní</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literatura</term>
+    <term name="math">matematika</term>
+    <term name="medicine">medicína</term>
+    <term name="philosophy">filosofie</term>
+    <term name="physics">fyzika</term>
+    <term name="psychology">psychologie</term>
+    <term name="sociology">sociologie</term>
+    <term name="science">věda</term>
+    <term name="political_science">politologie</term>
+    <term name="social_science">sociální věda</term>
+    <term name="theology">teologie</term>
+    <term name="zoology">zoologie</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>kniha</single>
+      <multiple>knihy</multiple>
+    </term>
+    <term name="chapter">
+      <single>kapitola</single>
+      <multiple>kapitoly</multiple>
+    </term>
+    <term name="column">
+      <single>sloupec</single>
+      <multiple>sloupce</multiple>
+    </term>
+    <term name="figure">
+      <single>obrázek</single>
+      <multiple>obrázky</multiple>
+    </term>
+    <term name="folio">
+      <single>list</single>
+      <multiple>listy</multiple>
+    </term>
+    <term name="issue">
+      <single>Äíslo</single>
+      <multiple>Äíslo</multiple>
+    </term>
+    <term name="line">
+      <single>řádek</single>
+      <multiple>řádky</multiple>
+    </term>
+    <term name="note">
+      <single>poznámka</single>
+      <multiple>poznámky</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>strana</single>
+      <multiple>strany</multiple>
+    </term>
+    <term name="paragraph">
+      <single>odstavec</single>
+      <multiple>odstavce</multiple>
+    </term>
+    <term name="part">
+      <single>Äást</single>
+      <multiple>Äásti</multiple>
+    </term>
+    <term name="section">
+      <single>sekce</single>
+      <multiple>sekce</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verš</single>
+      <multiple>verše</multiple>
+    </term>
+    <term name="volume">
+      <single>roÄník</single>
+      <multiple>roÄníky</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">kn.</term>
+    <term name="chapter" form="short">kap.</term>
+    <term name="column" form="short">sl.</term>
+    <term name="figure" form="short">obr.</term>
+    <term name="folio" form="short">l.</term>
+    <term name="issue" form="short">Äís.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>s.</single>
+      <multiple>s.</multiple>
+    </term>
+    <term name="paragraph" form="short">odst.</term>
+    <term name="part" form="short">Ä.</term>
+    <term name="section" form="short">sek.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>v.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>roÄ.</single>
+      <multiple>roÄ.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single>autor</single>
+      <multiple>autoři</multiple>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editoři</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>překladatel</single>
+      <multiple>překladatelé</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor a překladatel</single>
+      <multiple>editoři a překladatelé</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed.</single>
+      <multiple>ed.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>ed.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>překl.</single>
+      <multiple>překl.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. a překl.</single>
+      <multiple>ed. a překl.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">editoval</term>
+    <term name="editorial-director" form="verb">editoval</term>
+    <term name="translator" form="verb">přeložil</term>
+    <term name="editortranslator" form="verb">editoval a přeložil</term>
+    <term name="recipient" form="verb">pro</term>
+    <term name="interviewer" form="verb">rozhovor vedl</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">překl.</term>
+    <term name="editortranslator" form="verb-short">ed. a přel.</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">leden</term>
+    <term name="month-02">únor</term>
+    <term name="month-03">březen</term>
+    <term name="month-04">duben</term>
+    <term name="month-05">květen</term>
+    <term name="month-06">Äerven</term>
+    <term name="month-07">Äervenec</term>
+    <term name="month-08">srpen</term>
+    <term name="month-09">září</term>
+    <term name="month-10">říjen</term>
+    <term name="month-11">listopad</term>
+    <term name="month-12">prosinec</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">led.</term>
+    <term name="month-02" form="short">úno.</term>
+    <term name="month-03" form="short">bře.</term>
+    <term name="month-04" form="short">dub.</term>
+    <term name="month-05" form="short">kvÄ›.</term>
+    <term name="month-06" form="short">Äer.</term>
+    <term name="month-07" form="short">Ävc.</term>
+    <term name="month-08" form="short">srp.</term>
+    <term name="month-09" form="short">zář.</term>
+    <term name="month-10" form="short">říj.</term>
+    <term name="month-11" form="short">lis.</term>
+    <term name="month-12" form="short">pro.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">jaro</term>
+    <term name="season-02">léto</term>
+    <term name="season-03">podzim</term>
+    <term name="season-04">zima</term>
+  </terms>
+</locale>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-da-DK.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="da-DK">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="-" range-delimiter="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="-" range-delimiter="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">Ã¥bnet</term>
+    <term name="and">og</term>
+    <term name="and others">med flere</term>
+    <term name="anonymous">anonym</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">på</term>
+    <term name="by">af</term>
+    <term name="circa">cirka</term>
+    <term name="circa" form="short">ca.</term>
+    <term name="cited">citeret</term>
+    <term name="edition">
+      <single>udgave</single>
+      <multiple>udgaver</multiple>
+    </term>
+    <term name="edition" form="short">udg.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">kommende</term>
+    <term name="from">fra</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">i</term>
+    <term name="in press">i tryk</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">brev</term>
+    <term name="no date">ingen dato</term>
+    <term name="no date" form="short">udateret</term>
+    <term name="online">online</term>
+    <term name="presented at">præsenteret ved</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>referencer</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refr.</multiple>
+    </term>
+    <term name="retrieved">hentet</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">e.Kr</term>
+    <term name="bc">f.Kr</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">første</term>
+    <term name="long-ordinal-02">anden</term>
+    <term name="long-ordinal-03">tredje</term>
+    <term name="long-ordinal-04">fjerde</term>
+    <term name="long-ordinal-05">femte</term>
+    <term name="long-ordinal-06">sjette</term>
+    <term name="long-ordinal-07">syvende</term>
+    <term name="long-ordinal-08">ottende</term>
+    <term name="long-ordinal-09">niende</term>
+    <term name="long-ordinal-10">tiende</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologi</term>
+    <term name="astronomy">astronomi</term>
+    <term name="biology">biologi</term>
+    <term name="botany">botanik</term>
+    <term name="chemistry">kemi</term>
+    <term name="engineering">ingeniørvidenskab</term>
+    <term name="generic-base">generel</term>
+    <term name="geography">geografi</term>
+    <term name="geology">geologi</term>
+    <term name="history">historie</term>
+    <term name="humanities">humanistiske fag</term>
+    <term name="linguistics">lingvistik</term>
+    <term name="literature">litteratur</term>
+    <term name="math">matematik</term>
+    <term name="medicine">medicin</term>
+    <term name="philosophy">filosofi</term>
+    <term name="physics">fysik</term>
+    <term name="psychology">fysiologi</term>
+    <term name="sociology">sociologi</term>
+    <term name="science">naturvidenskab</term>
+    <term name="political_science">statskundskab</term>
+    <term name="social_science">samfundsvidenskab</term>
+    <term name="theology">teologi</term>
+    <term name="zoology">zoologi</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>bog</single>
+      <multiple>bøger</multiple>
+    </term>
+    <term name="chapter">
+      <single>kapitel</single>
+      <multiple>kapitler</multiple>
+    </term>
+    <term name="column">
+      <single>kolonne</single>
+      <multiple>kolonner</multiple>
+    </term>
+    <term name="figure">
+      <single>figur</single>
+      <multiple>figurer</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folier</multiple>
+    </term>
+    <term name="issue">
+      <single>nummer</single>
+      <multiple>numre</multiple>
+    </term>
+    <term name="line">
+      <single>linje</single>
+      <multiple>linjer</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>noter</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opuser</multiple>
+    </term>
+    <term name="page">
+      <single>side</single>
+      <multiple>sider</multiple>
+    </term>
+    <term name="paragraph">
+      <single>afsnit</single>
+      <multiple>afsnit</multiple>
+    </term>
+    <term name="part">
+      <single>del</single>
+      <multiple>dele</multiple>
+    </term>
+    <term name="section">
+      <single>sektion</single>
+      <multiple>sektionerne</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>vers</single>
+      <multiple>vers</multiple>
+    </term>
+    <term name="volume">
+      <single>bind</single>
+      <multiple>bind</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">b.</term>
+    <term name="chapter" form="short">kap.</term>
+    <term name="column" form="short">kol.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">fol.</term>
+    <term name="issue" form="short">nr.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>s.</single>
+      <multiple>s.</multiple>
+    </term>
+    <term name="paragraph" form="short">afs.</term>
+    <term name="part" form="short">d.</term>
+    <term name="section" form="short">sekt.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>v.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>bd.</single>
+      <multiple>bd.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>redaktør</single>
+      <multiple>redaktører</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>redaktør</single>
+      <multiple>redaktører</multiple>
+    </term>
+    <term name="translator">
+      <single>oversætter</single>
+      <multiple>oversættere</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>redaktør &amp; oversætter</single>
+      <multiple>redaktører &amp; oversættere</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>overs.</single>
+      <multiple>overs.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>red. &amp; overs.</single>
+      <multiple>red. &amp; overs.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">redigeret af</term>
+    <term name="editorial-director" form="verb">redigeret af</term>
+    <term name="translator" form="verb">oversat af</term>
+    <term name="editortranslator" form="verb">redigeret &amp; oversat af</term>
+    <term name="recipient" form="verb">modtaget af</term>
+    <term name="interviewer" form="verb">interviewet af</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">af</term>
+    <term name="editor" form="verb-short">red.</term>
+    <term name="editorial-director" form="verb-short">red.</term>
+    <term name="translator" form="verb-short">overs.</term>
+    <term name="editortranslator" form="verb-short">red. &amp; overs. af</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Januar</term>
+    <term name="month-02">Februar</term>
+    <term name="month-03">Marts</term>
+    <term name="month-04">April</term>
+    <term name="month-05">Maj</term>
+    <term name="month-06">Juni</term>
+    <term name="month-07">Juli</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">Oktober</term>
+    <term name="month-11">November</term>
+    <term name="month-12">December</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan.</term>
+    <term name="month-02" form="short">Feb.</term>
+    <term name="month-03" form="short">Mar.</term>
+    <term name="month-04" form="short">Apr.</term>
+    <term name="month-05" form="short">Maj</term>
+    <term name="month-06" form="short">Jun.</term>
+    <term name="month-07" form="short">Jul.</term>
+    <term name="month-08" form="short">Aug.</term>
+    <term name="month-09" form="short">Sep.</term>
+    <term name="month-10" form="short">Okt.</term>
+    <term name="month-11" form="short">Nov.</term>
+    <term name="month-12" form="short">Dec.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Forår</term>
+    <term name="season-02">Sommer</term>
+    <term name="season-03">Efterår</term>
+    <term name="season-04">vinter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-de-AT.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="de-DE">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">zugegriffen</term>
+    <term name="and">und</term>
+    <term name="and others">und andere</term>
+    <term name="anonymous">ohne Autor</term>
+    <term name="anonymous" form="short">o. A.</term>
+    <term name="at">auf</term>
+    <term name="by">von</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">ca.</term>
+    <term name="cited">zitiert</term>
+    <term name="edition">
+      <single>Auflage</single>
+      <multiple>Auflagen</multiple>
+    </term>
+    <term name="edition" form="short">Aufl.</term>
+    <term name="et-al">u. a.</term>
+    <term name="forthcoming">i. E.</term>
+    <term name="from">von</term>
+    <term name="ibid">ebd.</term>
+    <term name="in">in</term>
+    <term name="in press">im Druck</term>
+    <term name="internet">Internet</term>
+    <term name="interview">Interview</term>
+    <term name="letter">Brief</term>
+    <term name="no date">ohne Datum</term>
+    <term name="no date" form="short">o. J.</term>
+    <term name="online">online</term>
+    <term name="presented at">gehalten auf der</term>
+    <term name="reference">
+      <single>Referenz</single>
+      <multiple>Referenzen</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>Ref.</single>
+      <multiple>Ref.</multiple>
+    </term>
+    <term name="retrieved">abgerufen</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">v. Chr.</term>
+    <term name="bc">n. Chr.</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">‚</term>
+    <term name="close-inner-quote">‘</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">erster</term>
+    <term name="long-ordinal-02">zweiter</term>
+    <term name="long-ordinal-03">dritter</term>
+    <term name="long-ordinal-04">vierter</term>
+    <term name="long-ordinal-05">fünfter</term>
+    <term name="long-ordinal-06">sechster</term>
+    <term name="long-ordinal-07">siebter</term>
+    <term name="long-ordinal-08">achter</term>
+    <term name="long-ordinal-09">neunter</term>
+    <term name="long-ordinal-10">zehnter</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">Anthropologie</term>
+    <term name="astronomy">Astronomie</term>
+    <term name="biology">Biologie</term>
+    <term name="botany">Botanik</term>
+    <term name="chemistry">Chemie</term>
+    <term name="engineering">Ingenieurswissenschaften</term>
+    <term name="generic-base">generischer Stil</term>
+    <term name="geography">Geographie</term>
+    <term name="geology">Geologie</term>
+    <term name="history">Geschichte</term>
+    <term name="humanities">Geisteswissenschaften</term>
+    <term name="linguistics">Linguistik</term>
+    <term name="literature">Literatur</term>
+    <term name="math">Mathematik</term>
+    <term name="medicine">Medizin</term>
+    <term name="philosophy">Philosophie</term>
+    <term name="physics">Physik</term>
+    <term name="psychology">Psychologie</term>
+    <term name="sociology">Soziologie</term>
+    <term name="science">Naturwissenschaften</term>
+    <term name="political_science">Politikwissenschaft</term>
+    <term name="social_science">Sozialwissenschaften</term>
+    <term name="theology">Theologie</term>
+    <term name="zoology">Zoologie</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>Buch</single>
+      <multiple>Bücher</multiple>
+    </term>
+    <term name="chapter">
+      <single>Kapitel</single>
+      <multiple>Kapitel</multiple>
+    </term>
+    <term name="column">
+      <single>Spalte</single>
+      <multiple>Spalten</multiple>
+    </term>
+    <term name="figure">
+      <single>Abbildung</single>
+      <multiple>Abbildungen</multiple>
+    </term>
+    <term name="folio">
+      <single>Blatt</single>
+      <multiple>Blätter</multiple>
+    </term>
+    <term name="issue">
+      <single>Nummer</single>
+      <multiple>Nummern</multiple>
+    </term>
+    <term name="line">
+      <single>Zeile</single>
+      <multiple>Zeilen</multiple>
+    </term>
+    <term name="note">
+      <single>Note</single>
+      <multiple>Noten</multiple>
+    </term>
+    <term name="opus">
+      <single>Opus</single>
+      <multiple>Opera</multiple>
+    </term>
+    <term name="page">
+      <single>Seite</single>
+      <multiple>Seiten</multiple>
+    </term>
+    <term name="paragraph">
+      <single>Absatz</single>
+      <multiple>Absätze</multiple>
+    </term>
+    <term name="part">
+      <single>Teil</single>
+      <multiple>Teile</multiple>
+    </term>
+    <term name="section">
+      <single>Abschnitt</single>
+      <multiple>Abschnitte</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>Vers</single>
+      <multiple>Verse</multiple>
+    </term>
+    <term name="volume">
+      <single>Band</single>
+      <multiple>Bände</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">B.</term>
+    <term name="chapter" form="short">Kap.</term>
+    <term name="column" form="short">Sp.</term>
+    <term name="figure" form="short">Abb.</term>
+    <term name="folio" form="short">Fol.</term>
+    <term name="issue" form="short">Nr.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>S.</single>
+      <multiple>S.</multiple>
+    </term>
+    <term name="paragraph" form="short">Abs.</term>
+    <term name="part" form="short">Teil</term>
+    <term name="section" form="short">Abschn.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>V.</single>
+      <multiple>V.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>Bd.</single>
+      <multiple>Bd.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>Herausgeber</single>
+      <multiple>Herausgeber</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>Herausgeber</single>
+      <multiple>Herausgeber</multiple>
+    </term>
+    <term name="translator">
+      <single>Übersetzer</single>
+      <multiple>Übersetzer</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>Herausgeber &amp; Übersetzer</single>
+      <multiple>Herausgeber &amp; Übersetzer</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>Hrsg.</single>
+      <multiple>Hrsg.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>Hrsg.</single>
+      <multiple>Hrsg.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>Übers.</single>
+      <multiple>Übers.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>Hrsg. &amp; Übers.</single>
+      <multiple>Hrsg. &amp; Übers</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">herausgegeben von</term>
+    <term name="editorial-director" form="verb">herausgegeben von</term>
+    <term name="translator" form="verb">übersetzt von</term>
+    <term name="editortranslator" form="verb">herausgegeben und übersetzt von</term>
+    <term name="recipient" form="verb">an</term>
+    <term name="interviewer" form="verb">interviewt von</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">von</term>
+    <term name="editor" form="verb-short">hg. von</term>
+    <term name="editorial-director" form="verb-short">hg. von</term>
+    <term name="translator" form="verb-short">übers. von</term>
+    <term name="editortranslator" form="verb-short">hg. &amp; übers. von</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Januar</term>
+    <term name="month-02">Februar</term>
+    <term name="month-03">März</term>
+    <term name="month-04">April</term>
+    <term name="month-05">Mai</term>
+    <term name="month-06">Juni</term>
+    <term name="month-07">Juli</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">Oktober</term>
+    <term name="month-11">November</term>
+    <term name="month-12">Dezember</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan.</term>
+    <term name="month-02" form="short">Feb.</term>
+    <term name="month-03" form="short">März</term>
+    <term name="month-04" form="short">Apr.</term>
+    <term name="month-05" form="short">Mai</term>
+    <term name="month-06" form="short">Juni</term>
+    <term name="month-07" form="short">Juli</term>
+    <term name="month-08" form="short">Aug.</term>
+    <term name="month-09" form="short">Sep.</term>
+    <term name="month-10" form="short">Okt.</term>
+    <term name="month-11" form="short">Nov.</term>
+    <term name="month-12" form="short">Dez.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Frühjahr</term>
+    <term name="season-02">Sommer</term>
+    <term name="season-03">Herbst</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-de-CH.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="de-DE">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">zugegriffen</term>
+    <term name="and">und</term>
+    <term name="and others">und andere</term>
+    <term name="anonymous">ohne Autor</term>
+    <term name="anonymous" form="short">o. A.</term>
+    <term name="at">auf</term>
+    <term name="by">von</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">ca.</term>
+    <term name="cited">zitiert</term>
+    <term name="edition">
+      <single>Auflage</single>
+      <multiple>Auflagen</multiple>
+    </term>
+    <term name="edition" form="short">Aufl.</term>
+    <term name="et-al">u. a.</term>
+    <term name="forthcoming">i. E.</term>
+    <term name="from">von</term>
+    <term name="ibid">ebd.</term>
+    <term name="in">in</term>
+    <term name="in press">im Druck</term>
+    <term name="internet">Internet</term>
+    <term name="interview">Interview</term>
+    <term name="letter">Brief</term>
+    <term name="no date">ohne Datum</term>
+    <term name="no date" form="short">o. J.</term>
+    <term name="online">online</term>
+    <term name="presented at">gehalten auf der</term>
+    <term name="reference">
+      <single>Referenz</single>
+      <multiple>Referenzen</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>Ref.</single>
+      <multiple>Ref.</multiple>
+    </term>
+    <term name="retrieved">abgerufen</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">v. Chr.</term>
+    <term name="bc">n. Chr.</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">‚</term>
+    <term name="close-inner-quote">‘</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">erster</term>
+    <term name="long-ordinal-02">zweiter</term>
+    <term name="long-ordinal-03">dritter</term>
+    <term name="long-ordinal-04">vierter</term>
+    <term name="long-ordinal-05">fünfter</term>
+    <term name="long-ordinal-06">sechster</term>
+    <term name="long-ordinal-07">siebter</term>
+    <term name="long-ordinal-08">achter</term>
+    <term name="long-ordinal-09">neunter</term>
+    <term name="long-ordinal-10">zehnter</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">Anthropologie</term>
+    <term name="astronomy">Astronomie</term>
+    <term name="biology">Biologie</term>
+    <term name="botany">Botanik</term>
+    <term name="chemistry">Chemie</term>
+    <term name="engineering">Ingenieurswissenschaften</term>
+    <term name="generic-base">generischer Stil</term>
+    <term name="geography">Geographie</term>
+    <term name="geology">Geologie</term>
+    <term name="history">Geschichte</term>
+    <term name="humanities">Geisteswissenschaften</term>
+    <term name="linguistics">Linguistik</term>
+    <term name="literature">Literatur</term>
+    <term name="math">Mathematik</term>
+    <term name="medicine">Medizin</term>
+    <term name="philosophy">Philosophie</term>
+    <term name="physics">Physik</term>
+    <term name="psychology">Psychologie</term>
+    <term name="sociology">Soziologie</term>
+    <term name="science">Naturwissenschaften</term>
+    <term name="political_science">Politikwissenschaft</term>
+    <term name="social_science">Sozialwissenschaften</term>
+    <term name="theology">Theologie</term>
+    <term name="zoology">Zoologie</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>Buch</single>
+      <multiple>Bücher</multiple>
+    </term>
+    <term name="chapter">
+      <single>Kapitel</single>
+      <multiple>Kapitel</multiple>
+    </term>
+    <term name="column">
+      <single>Spalte</single>
+      <multiple>Spalten</multiple>
+    </term>
+    <term name="figure">
+      <single>Abbildung</single>
+      <multiple>Abbildungen</multiple>
+    </term>
+    <term name="folio">
+      <single>Blatt</single>
+      <multiple>Blätter</multiple>
+    </term>
+    <term name="issue">
+      <single>Nummer</single>
+      <multiple>Nummern</multiple>
+    </term>
+    <term name="line">
+      <single>Zeile</single>
+      <multiple>Zeilen</multiple>
+    </term>
+    <term name="note">
+      <single>Note</single>
+      <multiple>Noten</multiple>
+    </term>
+    <term name="opus">
+      <single>Opus</single>
+      <multiple>Opera</multiple>
+    </term>
+    <term name="page">
+      <single>Seite</single>
+      <multiple>Seiten</multiple>
+    </term>
+    <term name="paragraph">
+      <single>Absatz</single>
+      <multiple>Absätze</multiple>
+    </term>
+    <term name="part">
+      <single>Teil</single>
+      <multiple>Teile</multiple>
+    </term>
+    <term name="section">
+      <single>Abschnitt</single>
+      <multiple>Abschnitte</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>Vers</single>
+      <multiple>Verse</multiple>
+    </term>
+    <term name="volume">
+      <single>Band</single>
+      <multiple>Bände</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">B.</term>
+    <term name="chapter" form="short">Kap.</term>
+    <term name="column" form="short">Sp.</term>
+    <term name="figure" form="short">Abb.</term>
+    <term name="folio" form="short">Fol.</term>
+    <term name="issue" form="short">Nr.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>S.</single>
+      <multiple>S.</multiple>
+    </term>
+    <term name="paragraph" form="short">Abs.</term>
+    <term name="part" form="short">Teil</term>
+    <term name="section" form="short">Abschn.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>V.</single>
+      <multiple>V.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>Bd.</single>
+      <multiple>Bd.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>Herausgeber</single>
+      <multiple>Herausgeber</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>Herausgeber</single>
+      <multiple>Herausgeber</multiple>
+    </term>
+    <term name="translator">
+      <single>Übersetzer</single>
+      <multiple>Übersetzer</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>Herausgeber &amp; Übersetzer</single>
+      <multiple>Herausgeber &amp; Übersetzer</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>Hrsg.</single>
+      <multiple>Hrsg.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>Hrsg.</single>
+      <multiple>Hrsg.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>Übers.</single>
+      <multiple>Übers.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>Hrsg. &amp; Übers.</single>
+      <multiple>Hrsg. &amp; Übers</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">herausgegeben von</term>
+    <term name="editorial-director" form="verb">herausgegeben von</term>
+    <term name="translator" form="verb">übersetzt von</term>
+    <term name="editortranslator" form="verb">herausgegeben und übersetzt von</term>
+    <term name="recipient" form="verb">an</term>
+    <term name="interviewer" form="verb">interviewt von</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">von</term>
+    <term name="editor" form="verb-short">hg. von</term>
+    <term name="editorial-director" form="verb-short">hg. von</term>
+    <term name="translator" form="verb-short">übers. von</term>
+    <term name="editortranslator" form="verb-short">hg. &amp; übers. von</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Januar</term>
+    <term name="month-02">Februar</term>
+    <term name="month-03">März</term>
+    <term name="month-04">April</term>
+    <term name="month-05">Mai</term>
+    <term name="month-06">Juni</term>
+    <term name="month-07">Juli</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">Oktober</term>
+    <term name="month-11">November</term>
+    <term name="month-12">Dezember</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan.</term>
+    <term name="month-02" form="short">Feb.</term>
+    <term name="month-03" form="short">März</term>
+    <term name="month-04" form="short">Apr.</term>
+    <term name="month-05" form="short">Mai</term>
+    <term name="month-06" form="short">Juni</term>
+    <term name="month-07" form="short">Juli</term>
+    <term name="month-08" form="short">Aug.</term>
+    <term name="month-09" form="short">Sep.</term>
+    <term name="month-10" form="short">Okt.</term>
+    <term name="month-11" form="short">Nov.</term>
+    <term name="month-12" form="short">Dez.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Frühjahr</term>
+    <term name="season-02">Sommer</term>
+    <term name="season-03">Herbst</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-de-DE.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="de-DE">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">zugegriffen</term>
+    <term name="and">und</term>
+    <term name="and others">und andere</term>
+    <term name="anonymous">ohne Autor</term>
+    <term name="anonymous" form="short">o. A.</term>
+    <term name="at">auf</term>
+    <term name="by">von</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">ca.</term>
+    <term name="cited">zitiert</term>
+    <term name="edition">
+      <single>Auflage</single>
+      <multiple>Auflagen</multiple>
+    </term>
+    <term name="edition" form="short">Aufl.</term>
+    <term name="et-al">u. a.</term>
+    <term name="forthcoming">i. E.</term>
+    <term name="from">von</term>
+    <term name="ibid">ebd.</term>
+    <term name="in">in</term>
+    <term name="in press">im Druck</term>
+    <term name="internet">Internet</term>
+    <term name="interview">Interview</term>
+    <term name="letter">Brief</term>
+    <term name="no date">ohne Datum</term>
+    <term name="no date" form="short">o. J.</term>
+    <term name="online">online</term>
+    <term name="presented at">gehalten auf der</term>
+    <term name="reference">
+      <single>Referenz</single>
+      <multiple>Referenzen</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>Ref.</single>
+      <multiple>Ref.</multiple>
+    </term>
+    <term name="retrieved">abgerufen</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">v. Chr.</term>
+    <term name="bc">n. Chr.</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">‚</term>
+    <term name="close-inner-quote">‘</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">erster</term>
+    <term name="long-ordinal-02">zweiter</term>
+    <term name="long-ordinal-03">dritter</term>
+    <term name="long-ordinal-04">vierter</term>
+    <term name="long-ordinal-05">fünfter</term>
+    <term name="long-ordinal-06">sechster</term>
+    <term name="long-ordinal-07">siebter</term>
+    <term name="long-ordinal-08">achter</term>
+    <term name="long-ordinal-09">neunter</term>
+    <term name="long-ordinal-10">zehnter</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">Anthropologie</term>
+    <term name="astronomy">Astronomie</term>
+    <term name="biology">Biologie</term>
+    <term name="botany">Botanik</term>
+    <term name="chemistry">Chemie</term>
+    <term name="engineering">Ingenieurswissenschaften</term>
+    <term name="generic-base">generischer Stil</term>
+    <term name="geography">Geographie</term>
+    <term name="geology">Geologie</term>
+    <term name="history">Geschichte</term>
+    <term name="humanities">Geisteswissenschaften</term>
+    <term name="linguistics">Linguistik</term>
+    <term name="literature">Literatur</term>
+    <term name="math">Mathematik</term>
+    <term name="medicine">Medizin</term>
+    <term name="philosophy">Philosophie</term>
+    <term name="physics">Physik</term>
+    <term name="psychology">Psychologie</term>
+    <term name="sociology">Soziologie</term>
+    <term name="science">Naturwissenschaften</term>
+    <term name="political_science">Politikwissenschaft</term>
+    <term name="social_science">Sozialwissenschaften</term>
+    <term name="theology">Theologie</term>
+    <term name="zoology">Zoologie</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>Buch</single>
+      <multiple>Bücher</multiple>
+    </term>
+    <term name="chapter">
+      <single>Kapitel</single>
+      <multiple>Kapitel</multiple>
+    </term>
+    <term name="column">
+      <single>Spalte</single>
+      <multiple>Spalten</multiple>
+    </term>
+    <term name="figure">
+      <single>Abbildung</single>
+      <multiple>Abbildungen</multiple>
+    </term>
+    <term name="folio">
+      <single>Blatt</single>
+      <multiple>Blätter</multiple>
+    </term>
+    <term name="issue">
+      <single>Nummer</single>
+      <multiple>Nummern</multiple>
+    </term>
+    <term name="line">
+      <single>Zeile</single>
+      <multiple>Zeilen</multiple>
+    </term>
+    <term name="note">
+      <single>Note</single>
+      <multiple>Noten</multiple>
+    </term>
+    <term name="opus">
+      <single>Opus</single>
+      <multiple>Opera</multiple>
+    </term>
+    <term name="page">
+      <single>Seite</single>
+      <multiple>Seiten</multiple>
+    </term>
+    <term name="paragraph">
+      <single>Absatz</single>
+      <multiple>Absätze</multiple>
+    </term>
+    <term name="part">
+      <single>Teil</single>
+      <multiple>Teile</multiple>
+    </term>
+    <term name="section">
+      <single>Abschnitt</single>
+      <multiple>Abschnitte</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>Vers</single>
+      <multiple>Verse</multiple>
+    </term>
+    <term name="volume">
+      <single>Band</single>
+      <multiple>Bände</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">B.</term>
+    <term name="chapter" form="short">Kap.</term>
+    <term name="column" form="short">Sp.</term>
+    <term name="figure" form="short">Abb.</term>
+    <term name="folio" form="short">Fol.</term>
+    <term name="issue" form="short">Nr.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>S.</single>
+      <multiple>S.</multiple>
+    </term>
+    <term name="paragraph" form="short">Abs.</term>
+    <term name="part" form="short">Teil</term>
+    <term name="section" form="short">Abschn.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>V.</single>
+      <multiple>V.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>Bd.</single>
+      <multiple>Bd.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>Herausgeber</single>
+      <multiple>Herausgeber</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>Herausgeber</single>
+      <multiple>Herausgeber</multiple>
+    </term>
+    <term name="translator">
+      <single>Übersetzer</single>
+      <multiple>Übersetzer</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>Herausgeber &amp; Übersetzer</single>
+      <multiple>Herausgeber &amp; Übersetzer</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>Hrsg.</single>
+      <multiple>Hrsg.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>Hrsg.</single>
+      <multiple>Hrsg.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>Übers.</single>
+      <multiple>Übers.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>Hrsg. &amp; Übers.</single>
+      <multiple>Hrsg. &amp; Übers</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">herausgegeben von</term>
+    <term name="editorial-director" form="verb">herausgegeben von</term>
+    <term name="translator" form="verb">übersetzt von</term>
+    <term name="editortranslator" form="verb">herausgegeben und übersetzt von</term>
+    <term name="recipient" form="verb">an</term>
+    <term name="interviewer" form="verb">interviewt von</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">von</term>
+    <term name="editor" form="verb-short">hg. von</term>
+    <term name="editorial-director" form="verb-short">hg. von</term>
+    <term name="translator" form="verb-short">übers. von</term>
+    <term name="editortranslator" form="verb-short">hg. &amp; übers. von</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Januar</term>
+    <term name="month-02">Februar</term>
+    <term name="month-03">März</term>
+    <term name="month-04">April</term>
+    <term name="month-05">Mai</term>
+    <term name="month-06">Juni</term>
+    <term name="month-07">Juli</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">Oktober</term>
+    <term name="month-11">November</term>
+    <term name="month-12">Dezember</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan.</term>
+    <term name="month-02" form="short">Feb.</term>
+    <term name="month-03" form="short">März</term>
+    <term name="month-04" form="short">Apr.</term>
+    <term name="month-05" form="short">Mai</term>
+    <term name="month-06" form="short">Juni</term>
+    <term name="month-07" form="short">Juli</term>
+    <term name="month-08" form="short">Aug.</term>
+    <term name="month-09" form="short">Sep.</term>
+    <term name="month-10" form="short">Okt.</term>
+    <term name="month-11" form="short">Nov.</term>
+    <term name="month-12" form="short">Dez.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Frühjahr</term>
+    <term name="season-02">Sommer</term>
+    <term name="season-03">Herbst</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-el-GR.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="el-GR">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">ημεÏομηνία Ï€Ïόσβασης</term>
+    <term name="and">και</term>
+    <term name="and others">και άλλοι</term>
+    <term name="anonymous">ανώνυμο</term>
+    <term name="anonymous" form="short">ανών.</term>
+    <term name="at">εφ.</term>
+    <term name="by">από</term>
+    <term name="circa">πεÏίπου</term>
+    <term name="circa" form="short">πεÏ.</term>
+    <term name="cited">παÏατίθεται</term>
+    <term name="edition">
+      <single>έκδοση</single>
+      <multiple>εκδόσεις</multiple>
+    </term>
+    <term name="edition" form="short">έκδ.</term>
+    <term name="et-al">κ.ά.</term>
+    <term name="forthcoming">Ï€Ïοσεχές</term>
+    <term name="from">από</term>
+    <term name="ibid">στο ίδιο</term>
+    <term name="in">στο</term>
+    <term name="in press">υπό έκδοση</term>
+    <term name="internet">διαδίκτυο</term>
+    <term name="interview">συνέντευξη</term>
+    <term name="letter">επιστολή</term>
+    <term name="no date">χωÏίς χÏονολογία</term>
+    <term name="no date" form="short">χ.χ.</term>
+    <term name="online">έκδοση σε ψηφιακή μοÏφή</term>
+    <term name="presented at">παÏουσιάστηκε στο</term>
+    <term name="reference">
+      <single>παÏαπομπή</single>
+      <multiple>παÏαπομπές</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>παÏ.</single>
+      <multiple>παÏ.</multiple>
+    </term>
+    <term name="retrieved">ανακτήθηκε</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">μ.Χ.</term>
+    <term name="bc">π.Χ.</term>
+
+    <!-- QUOTES -->
+    <!-- http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks differs,
+           but the characters below are directly from a Greek-speaking style author -->
+    <term name="open-quote">‘</term>
+    <term name="close-quote">’</term>
+    <term name="open-inner-quote">'</term>
+    <term name="close-inner-quote">'</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">ος</term>
+    <term name="ordinal-02">ος</term>
+    <term name="ordinal-03">ος</term>
+    <term name="ordinal-04">ος</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">Ï€Ïώτος</term>
+    <term name="long-ordinal-02">δεÏτεÏος</term>
+    <term name="long-ordinal-03">Ï„Ïίτος</term>
+    <term name="long-ordinal-04">τέταÏτος</term>
+    <term name="long-ordinal-05">πέμπτος</term>
+    <term name="long-ordinal-06">έκτος</term>
+    <term name="long-ordinal-07">έβδομος</term>
+    <term name="long-ordinal-08">όγδοος</term>
+    <term name="long-ordinal-09">ένατος</term>
+    <term name="long-ordinal-10">δέκατος</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">ανθÏωπολογία</term>
+    <term name="astronomy">αστÏονομία</term>
+    <term name="biology">βιολογία</term>
+    <term name="botany">βοτανική</term>
+    <term name="chemistry">χημεία</term>
+    <term name="engineering">μηχανική</term>
+    <term name="generic-base">γενική βιβλιογÏαφία</term>
+    <term name="geography">γεωγÏαφία</term>
+    <term name="geology">γεωλογία</term>
+    <term name="history">ιστοÏία</term>
+    <term name="humanities">ανθÏωπιστικές σπουδές</term>
+    <term name="literature">λογοτεχνία</term>
+    <term name="math">μαθηματικά</term>
+    <term name="medicine">ιατÏική</term>
+    <term name="philosophy">φιλοσοφία</term>
+    <term name="physics">φυσική</term>
+    <term name="psychology">ψυχολογία</term>
+    <term name="sociology">κοινωνιολογία</term>
+    <term name="science">θετικές επιστήμες</term>
+    <term name="political_science">πολιτικές επιστήμες</term>
+    <term name="social_science">κοινωνικές επιστήμες</term>
+    <term name="theology">θεολογία</term>
+    <term name="zoology">ζωολογία</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>βιβλίο</single>
+      <multiple>βιβλίο</multiple>
+    </term>
+    <term name="chapter">
+      <single>κεφάλαιο</single>
+      <multiple>κεφάλαια</multiple>
+    </term>
+    <term name="column">
+      <single>στήλη</single>
+      <multiple>στήλες</multiple>
+    </term>
+    <term name="figure">
+      <single>εικόνα</single>
+      <multiple>εικόνες</multiple>
+    </term>
+    <term name="folio">
+      <single>φάκελος</single>
+      <multiple>φάκελοι</multiple>
+    </term>
+    <term name="issue">
+      <single>τεÏχος</single>
+      <multiple>τεÏχη</multiple>
+    </term>
+    <term name="line">
+      <single>σειÏά</single>
+      <multiple>σειÏές</multiple>
+    </term>
+    <term name="note">
+      <single>σημείωση</single>
+      <multiple>σημειώσεις</multiple>
+    </term>
+    <term name="opus">
+      <single>έÏγο</single>
+      <multiple>έÏγα</multiple>
+    </term>
+    <term name="page">
+      <single>σελίδα</single>
+      <multiple>σελίδες</multiple>
+    </term>
+    <term name="paragraph">
+      <single>παÏάγÏαφος</single>
+      <multiple>παÏάγÏαφοι</multiple>
+    </term>
+    <term name="part">
+      <single>μέÏος</single>
+      <multiple>μέÏη</multiple>
+    </term>
+    <term name="section">
+      <single>τμήμα</single>
+      <multiple>τμήματα</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>λήμμα</single>
+      <multiple>λήμματα</multiple>
+    </term>
+    <term name="verse">
+      <single>στίχος</single>
+      <multiple>στίχοι</multiple>
+    </term>
+    <term name="volume">
+      <single>τόμος</single>
+      <multiple>τόμοι</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">βιβ.</term>
+    <term name="chapter" form="short">κεφ.</term>
+    <term name="column" form="short">στ.</term>
+    <term name="figure" form="short">εικ.</term>
+    <term name="folio" form="short">φάκ</term>
+    <term name="issue" form="short">τχ.</term>
+    <term name="opus" form="short">έÏγ.</term>
+    <term name="page" form="short">
+      <single>σ</single>
+      <multiple>σσ</multiple>
+    </term>
+    <term name="paragraph" form="short">παÏ.</term>
+    <term name="part" form="short">μέÏ.</term>
+    <term name="section" form="short">τμ.</term>
+    <term name="sub verbo" form="short">
+      <single>λήμ.</single>
+      <multiple>λήμ.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>στ.</single>
+      <multiple>στ.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>Ï„.</single>
+      <multiple>Ï„.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single>συγγÏαφέας</single>
+      <multiple>συγγÏαφείς</multiple>
+    </term>
+    <term name="editor">
+      <single>επιμελητής</single>
+      <multiple>επιμελητές</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>διευθυντής σειÏάς</single>
+      <multiple>διευθυντές σειÏάς</multiple>
+    </term>
+    <term name="translator">
+      <single>μεταφÏαστής</single>
+      <multiple>μεταφÏαστές</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>μεταφÏαστής και επιμελητής</single>
+      <multiple>μεταφÏαστές και επιμελητές</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single>συγγÏ.</single>
+      <multiple>συγγÏ.</multiple>
+    </term>
+    <term name="editor" form="short">
+      <single>επιμ.</single>
+      <multiple>επιμ.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>δ/ντής σειÏάς</single>
+      <multiple>δ/ντές σειÏας</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>μτφ.</single>
+      <multiple>μτφ.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>μτφ. και επιμ.</single>
+      <multiple>μτφ. και επιμ.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">επιμέλεια</term>
+    <term name="editorial-director" form="verb">διεÏθυνση σειÏάς</term>
+    <term name="translator" form="verb">μετάφÏαση</term>
+    <term name="editortranslator" form="verb">μετάφÏαση και επιμέλεια</term>
+    <term name="recipient" form="verb">παÏαλήπτης</term>
+    <term name="interviewer" form="verb">συνέντευξη</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">στον συλλ. τόμο</term>
+    <term name="editor" form="verb-short">επιμέλ.</term>
+    <term name="editorial-director" form="verb-short">δ/νση σειÏάς</term>
+    <term name="translator" form="verb-short">μετάφÏ.</term>
+    <term name="editortranslator" form="verb-short">μετάφÏ. και επιμέλ.</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">ΙανουάÏιος</term>
+    <term name="month-02">ΦεβÏουάÏιος</term>
+    <term name="month-03">ΜάÏτιος</term>
+    <term name="month-04">ΑπÏίλιος</term>
+    <term name="month-05">Μάιος</term>
+    <term name="month-06">ΙοÏνιος</term>
+    <term name="month-07">ΙοÏλιος</term>
+    <term name="month-08">ΑÏγουστος</term>
+    <term name="month-09">ΣεπτέμβÏιος</term>
+    <term name="month-10">ΟκτώβÏιος</term>
+    <term name="month-11">ÎοέμβÏιος</term>
+    <term name="month-12">ΔεκέμβÏιος</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">ΙανουαÏίου</term>
+    <term name="month-02" form="short">ΦεβÏουαÏίου</term>
+    <term name="month-03" form="short">ΜαÏτίου</term>
+    <term name="month-04" form="short">ΑπÏιλίου</term>
+    <term name="month-05" form="short">ΜαÎου</term>
+    <term name="month-06" form="short">Ιουνίου</term>
+    <term name="month-07" form="short">Ιουλίου</term>
+    <term name="month-08" form="short">ΑυγοÏστου</term>
+    <term name="month-09" form="short">ΣεπτεμβÏίου</term>
+    <term name="month-10" form="short">ΟκτωβÏίου</term>
+    <term name="month-11" form="short">ÎοεμβÏίου</term>
+    <term name="month-12" form="short">ΔεκεμβÏίου</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Άνοιξη</term>
+    <term name="season-02">ΚαλοκαίÏι</term>
+    <term name="season-03">ΦθινόπωÏο</term>
+    <term name="season-04">Χειμώνας</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-en-GB.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="en-GB">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">accessed</term>
+    <term name="and">and</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">from</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">‘</term>
+    <term name="close-quote">’</term>
+    <term name="open-inner-quote">“</term>
+    <term name="close-inner-quote">â€</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>line</single>
+      <multiple>lines</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>page</single>
+      <multiple>pages</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraph</single>
+      <multiple>paragraph</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk.</term>
+    <term name="chapter" form="short">chap.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">f.</term>
+    <term name="issue" form="short">no.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>pp.</multiple>
+    </term>
+    <term name="paragraph" form="short">para.</term>
+    <term name="part" form="short">pt.</term>
+    <term name="section" form="short">sec.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>vv.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vols.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>translator</single>
+      <multiple>translators</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tran.</single>
+      <multiple>trans.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">edited by</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">translated by</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans.</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">January</term>
+    <term name="month-02">February</term>
+    <term name="month-03">March</term>
+    <term name="month-04">April</term>
+    <term name="month-05">May</term>
+    <term name="month-06">June</term>
+    <term name="month-07">July</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">October</term>
+    <term name="month-11">November</term>
+    <term name="month-12">December</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan.</term>
+    <term name="month-02" form="short">Feb.</term>
+    <term name="month-03" form="short">Mar.</term>
+    <term name="month-04" form="short">Apr.</term>
+    <term name="month-05" form="short">May</term>
+    <term name="month-06" form="short">Jun.</term>
+    <term name="month-07" form="short">Jul.</term>
+    <term name="month-08" form="short">Aug.</term>
+    <term name="month-09" form="short">Sep.</term>
+    <term name="month-10" form="short">Oct.</term>
+    <term name="month-11" form="short">Nov.</term>
+    <term name="month-12" form="short">Dec.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-en-US.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="en-US">
+  <style-options punctuation-in-quote="true"/>
+  <date form="text">
+    <date-part name="month" suffix=" "/>
+    <date-part name="day" form="numeric-leading-zeros" suffix=", "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">accessed</term>
+    <term name="and">and</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">from</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>line</single>
+      <multiple>lines</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>page</single>
+      <multiple>pages</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraph</single>
+      <multiple>paragraph</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk.</term>
+    <term name="chapter" form="short">chap.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">f.</term>
+    <term name="issue" form="short">no.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>pp.</multiple>
+    </term>
+    <term name="paragraph" form="short">para.</term>
+    <term name="part" form="short">pt.</term>
+    <term name="section" form="short">sec.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>vv.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vols.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>translator</single>
+      <multiple>translators</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tran.</single>
+      <multiple>trans.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">edited by</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">translated by</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans.</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">January</term>
+    <term name="month-02">February</term>
+    <term name="month-03">March</term>
+    <term name="month-04">April</term>
+    <term name="month-05">May</term>
+    <term name="month-06">June</term>
+    <term name="month-07">July</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">October</term>
+    <term name="month-11">November</term>
+    <term name="month-12">December</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan.</term>
+    <term name="month-02" form="short">Feb.</term>
+    <term name="month-03" form="short">Mar.</term>
+    <term name="month-04" form="short">Apr.</term>
+    <term name="month-05" form="short">May</term>
+    <term name="month-06" form="short">Jun.</term>
+    <term name="month-07" form="short">Jul.</term>
+    <term name="month-08" form="short">Aug.</term>
+    <term name="month-09" form="short">Sep.</term>
+    <term name="month-10" form="short">Oct.</term>
+    <term name="month-11" form="short">Nov.</term>
+    <term name="month-12" form="short">Dec.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-es-ES.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="es-ES">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" de "/>
+    <date-part name="month" suffix=" de "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">accedido</term>
+    <term name="and">y</term>
+    <term name="and others">y otros</term>
+    <term name="anonymous">anónimo</term>
+    <term name="anonymous" form="short">anón.</term>
+    <term name="at">en</term>
+    <term name="by">de</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">citado</term>
+    <term name="edition">
+      <single>edición</single>
+      <multiple>ediciones</multiple>
+    </term>
+    <term name="edition" form="short">ed.</term>
+    <term name="et-al">et&#xA0;al.</term>
+    <term name="forthcoming">previsto</term>
+    <term name="from">a partir de</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">en</term>
+    <term name="in press">en imprenta</term>
+    <term name="internet">internet</term>
+    <term name="interview">entrevista</term>
+    <term name="letter">carta</term>
+    <term name="no date">sin fecha</term>
+    <term name="no date" form="short">s.&#xA0;f.</term>
+    <term name="online">en línea</term>
+    <term name="presented at">presentado en</term>
+    <term name="reference">
+      <single>referencia</single>
+      <multiple>referencias</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">recuperado</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">d.&#xA0;C.</term>
+    <term name="bc">a.&#xA0;C.</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">“</term>
+    <term name="close-inner-quote">â€</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.&#xAA;</term>
+    <term name="ordinal-02">.&#xAA;</term>
+    <term name="ordinal-03">.&#xAA;</term>
+    <term name="ordinal-04">.&#xAA;</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">primera</term>
+    <term name="long-ordinal-02">segunda</term>
+    <term name="long-ordinal-03">tercera</term>
+    <term name="long-ordinal-04">cuarta</term>
+    <term name="long-ordinal-05">quinta</term>
+    <term name="long-ordinal-06">sexta</term>
+    <term name="long-ordinal-07">séptima</term>
+    <term name="long-ordinal-08">octava</term>
+    <term name="long-ordinal-09">novena</term>
+    <term name="long-ordinal-10">décima</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropología</term>
+    <term name="astronomy">astronomía</term>
+    <term name="biology">biología</term>
+    <term name="botany">botánica</term>
+    <term name="chemistry">química</term>
+    <term name="engineering">ingeniería</term>
+    <term name="generic-base">base genérica</term>
+    <term name="geography">geografía</term>
+    <term name="geology">geología</term>
+    <term name="history">historia</term>
+    <term name="humanities">humanidades</term>
+    <term name="linguistics">lingüística</term>
+    <term name="literature">literatura</term>
+    <term name="math">matemáticas</term>
+    <term name="medicine">medicina</term>
+    <term name="philosophy">filosofía</term>
+    <term name="physics">física</term>
+    <term name="psychology">psicología</term>
+    <term name="sociology">sociología</term>
+    <term name="science">ciencias</term>
+    <term name="political_science">ciencias políticas</term>
+    <term name="social_science">ciencias sociales</term>
+    <term name="theology">teología</term>
+    <term name="zoology">zoología</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>libro</single>
+      <multiple>libros</multiple>
+    </term>
+    <term name="chapter">
+      <single>capítulo</single>
+      <multiple>capítulos</multiple>
+    </term>
+    <term name="column">
+      <single>columna</single>
+      <multiple>columnas</multiple>
+    </term>
+    <term name="figure">
+      <single>figura</single>
+      <multiple>figuras</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>número</single>
+      <multiple>números</multiple>
+    </term>
+    <term name="line">
+      <single>línea</single>
+      <multiple>líneas</multiple>
+    </term>
+    <term name="note">
+      <single>nota</single>
+      <multiple>notas</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>página</single>
+      <multiple>páginas</multiple>
+    </term>
+    <term name="paragraph">
+      <single>párrafo</single>
+      <multiple>párrafos</multiple>
+    </term>
+    <term name="part">
+      <single>parte</single>
+      <multiple>partes</multiple>
+    </term>
+    <term name="section">
+      <single>sección</single>
+      <multiple>secciones</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub voce</single>
+      <multiple>sub vocibus</multiple>
+    </term>
+    <term name="verse">
+      <single>verso</single>
+      <multiple>versos</multiple>
+    </term>
+    <term name="volume">
+      <single>volumen</single>
+      <multiple>volúmenes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">lib.</term>
+    <term name="chapter" form="short">cap.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">f.</term>
+    <term name="issue" form="short">n.º</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>pp.</multiple>
+    </term>
+    <term name="paragraph" form="short">párr.</term>
+    <term name="part" form="short">pt.</term>
+    <term name="section" form="short">sec.</term>
+    <term name="sub verbo" form="short">
+      <single>s.&#xA0;v.</single>
+      <multiple>s.&#xA0;vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>vv.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vols.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>§</single>
+      <multiple>§</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editores</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editores</multiple>
+    </term>
+    <term name="translator">
+      <single>traductor</single>
+      <multiple>traductores</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor y traductor</single>
+      <multiple>editores y traductores</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>trad.</single>
+      <multiple>trads.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. y trad.</single>
+      <multiple>eds. y trads.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">editado por</term>
+    <term name="editorial-director" form="verb">editado por</term>
+    <term name="translator" form="verb">traducido por</term>
+    <term name="editortranslator" form="verb">editado y traducido por</term>
+    <term name="recipient" form="verb">a</term>
+    <term name="interviewer" form="verb">entrevistado por</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">de</term>
+    <term name="editor" form="verb-short">ed.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trad.</term>
+    <term name="editortranslator" form="verb-short">ed. y trad.</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">enero</term>
+    <term name="month-02">febrero</term>
+    <term name="month-03">marzo</term>
+    <term name="month-04">abril</term>
+    <term name="month-05">mayo</term>
+    <term name="month-06">junio</term>
+    <term name="month-07">julio</term>
+    <term name="month-08">agosto</term>
+    <term name="month-09">septiembre</term>
+    <term name="month-10">octubre</term>
+    <term name="month-11">noviembre</term>
+    <term name="month-12">diciembre</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">ene.</term>
+    <term name="month-02" form="short">feb.</term>
+    <term name="month-03" form="short">mar.</term>
+    <term name="month-04" form="short">abr.</term>
+    <term name="month-05" form="short">may</term>
+    <term name="month-06" form="short">jun.</term>
+    <term name="month-07" form="short">jul.</term>
+    <term name="month-08" form="short">ago.</term>
+    <term name="month-09" form="short">sep.</term>
+    <term name="month-10" form="short">oct.</term>
+    <term name="month-11" form="short">nov.</term>
+    <term name="month-12" form="short">dic.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">primavera</term>
+    <term name="season-02">verano</term>
+    <term name="season-03">otoño</term>
+    <term name="season-04">invierno</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-et-EE.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="et-EE">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">vaadatud</term>
+    <term name="and">ja</term>
+    <term name="and others">ja teised</term>
+    <term name="anonymous">anonüümne</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at"/>
+    <term name="by"/>
+    <term name="circa">umbes</term>
+    <term name="circa" form="short">u</term>
+    <term name="cited">tsiteeritud</term>
+    <term name="edition">
+      <single>väljaanne</single>
+      <multiple>väljaanded</multiple>
+    </term>
+    <term name="edition" form="short">tr</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">ilmumisel</term>
+    <term name="from"/>
+    <term name="ibid">ibid.</term>
+    <term name="in"/>
+    <term name="in press">trükis</term>
+    <term name="internet">internet</term>
+    <term name="interview">intervjuu</term>
+    <term name="letter">kiri</term>
+    <term name="no date">s.a.</term>
+    <term name="no date" form="short">s.a.</term>
+    <term name="online">online</term>
+    <term name="presented at">esitatud</term>
+    <term name="reference">
+      <single>viide</single>
+      <multiple>viited</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>viide</single>
+      <multiple>viited</multiple>
+    </term>
+    <term name="retrieved">salvestatud</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">pKr</term>
+    <term name="bc">eKr</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01"/>
+    <term name="ordinal-02"/>
+    <term name="ordinal-03"/>
+    <term name="ordinal-04"/>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">esimene</term>
+    <term name="long-ordinal-02">teine</term>
+    <term name="long-ordinal-03">kolmas</term>
+    <term name="long-ordinal-04">neljas</term>
+    <term name="long-ordinal-05">viies</term>
+    <term name="long-ordinal-06">kuues</term>
+    <term name="long-ordinal-07">seitsmes</term>
+    <term name="long-ordinal-08">kaheksas</term>
+    <term name="long-ordinal-09">üheksas</term>
+    <term name="long-ordinal-10">kümnes</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropoloogia</term>
+    <term name="astronomy">astronoomia</term>
+    <term name="biology">bioloogia</term>
+    <term name="botany">botaanika</term>
+    <term name="chemistry">keemia</term>
+    <term name="engineering">tehnikateadus</term>
+    <term name="generic-base">määratlemata</term>
+    <term name="geography">geograafia</term>
+    <term name="geology">geoloogia</term>
+    <term name="history">ajalugu</term>
+    <term name="humanities">humanitaarteadus</term>
+    <term name="linguistics">lingvistika</term>
+    <term name="literature">kirjandusteadus</term>
+    <term name="math">matemaatika</term>
+    <term name="medicine">meditsiin</term>
+    <term name="philosophy">filosoofia</term>
+    <term name="physics">füüsika</term>
+    <term name="psychology">psühholoogia</term>
+    <term name="sociology">sotsioloogia</term>
+    <term name="science">reaalteadus</term>
+    <term name="political_science">politoloogia</term>
+    <term name="social_science">sotsiaalteadus</term>
+    <term name="theology">teoloogia</term>
+    <term name="zoology">zooloogia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>raamat</single>
+      <multiple>raamatud</multiple>
+    </term>
+    <term name="chapter">
+      <single>peatükk</single>
+      <multiple>peatükid</multiple>
+    </term>
+    <term name="column">
+      <single>veerg</single>
+      <multiple>veerud</multiple>
+    </term>
+    <term name="figure">
+      <single>joonis</single>
+      <multiple>joonised</multiple>
+    </term>
+    <term name="folio">
+      <single>foolio</single>
+      <multiple>fooliod</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbrid</multiple>
+    </term>
+    <term name="line">
+      <single>rida</single>
+      <multiple>read</multiple>
+    </term>
+    <term name="note">
+      <single>viide</single>
+      <multiple>viited</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>lehekülg</single>
+      <multiple>leheküljed</multiple>
+    </term>
+    <term name="paragraph">
+      <single>lõik</single>
+      <multiple>lõigud</multiple>
+    </term>
+    <term name="part">
+      <single>osa</single>
+      <multiple>osad</multiple>
+    </term>
+    <term name="section">
+      <single>alajaotis</single>
+      <multiple>alajaotised</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>värss</single>
+      <multiple>värsid</multiple>
+    </term>
+    <term name="volume">
+      <single>köide</single>
+      <multiple>köited</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">rmt</term>
+    <term name="chapter" form="short">ptk</term>
+    <term name="column" form="short">v</term>
+    <term name="figure" form="short">joon</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">nr</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>lk</single>
+      <multiple>lk</multiple>
+    </term>
+    <term name="paragraph" form="short">lõik</term>
+    <term name="part" form="short">osa</term>
+    <term name="section" form="short">alajaot.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>kd</single>
+      <multiple>kd</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>toimetaja</single>
+      <multiple>toimetajad</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>toimetaja</single>
+      <multiple>toimetajad</multiple>
+    </term>
+    <term name="translator">
+      <single>tõlkija</single>
+      <multiple>tõlkijad</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>toimetaja &amp; tõlkija</single>
+      <multiple>toimetajad &amp; tõlkijad</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>toim</single>
+      <multiple>toim</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>toim</single>
+      <multiple>toim</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tõlk</single>
+      <multiple>tõlk</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>toim &amp; tõlk</single>
+      <multiple>toim &amp; tõlk</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">toimetanud</term>
+    <term name="editorial-director" form="verb">toimetanud</term>
+    <term name="translator" form="verb">tõlkinud</term>
+    <term name="editortranslator" form="verb">toimetanud &amp; tõlkinud</term>
+    <term name="recipient" form="verb"/>
+    <term name="interviewer" form="verb">intervjueerinud</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short"/>
+    <term name="editor" form="verb-short">toim</term>
+    <term name="editorial-director" form="verb-short">toim</term>
+    <term name="translator" form="verb-short">tõlk</term>
+    <term name="editortranslator" form="verb-short">toim &amp; tõlk</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">jaanuar</term>
+    <term name="month-02">veebruar</term>
+    <term name="month-03">märts</term>
+    <term name="month-04">aprill</term>
+    <term name="month-05">mai</term>
+    <term name="month-06">juuni</term>
+    <term name="month-07">juuli</term>
+    <term name="month-08">august</term>
+    <term name="month-09">september</term>
+    <term name="month-10">oktoober</term>
+    <term name="month-11">november</term>
+    <term name="month-12">detsember</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jaan</term>
+    <term name="month-02" form="short">veebr</term>
+    <term name="month-03" form="short">märts</term>
+    <term name="month-04" form="short">apr</term>
+    <term name="month-05" form="short">mai</term>
+    <term name="month-06" form="short">juuni</term>
+    <term name="month-07" form="short">juuli</term>
+    <term name="month-08" form="short">aug</term>
+    <term name="month-09" form="short">sept</term>
+    <term name="month-10" form="short">okt</term>
+    <term name="month-11" form="short">nov</term>
+    <term name="month-12" form="short">dets</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">kevad</term>
+    <term name="season-02">suvi</term>
+    <term name="season-03">sügis</term>
+    <term name="season-04">talv</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-eu.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="eu">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="year" suffix="(e)ko "/>
+    <date-part name="month" suffix="aren "/>
+    <date-part name="day" suffix="a"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="day" form="numeric-leading-zeros"/>
+  </date>
+  <terms>
+    <term name="accessed">eskuratua</term>
+    <term name="and">eta</term>
+    <term name="and others">eta beste</term>
+    <term name="anonymous">ezezaguna</term>
+    <term name="anonymous" form="short">ezez.</term>
+    <term name="at">-(e)n</term>
+    <term name="by">-(e)k egina</term>
+    <term name="circa">inguru</term>
+    <term name="circa" form="short">ing.</term>
+    <term name="cited">aipatua</term>
+    <term name="edition">
+      <single>argitalpena</single>
+      <multiple>argitalpenak</multiple>
+    </term>
+    <term name="edition" form="short">arg.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">bidean</term>
+    <term name="from">-(e)tik</term>
+    <term name="ibid">ibíd.</term>
+    <term name="in">in</term>
+    <term name="in press">moldiztegian</term>
+    <term name="internet">internet</term>
+    <term name="interview">elkarrizketa</term>
+    <term name="letter">gutuna</term>
+    <term name="no date">datarik gabe</term>
+    <term name="no date" form="short">d. g.</term>
+    <term name="online">sarean</term>
+    <term name="presented at">-(e)n aurkeztua</term>
+    <term name="reference">
+      <single>aipamena</single>
+      <multiple>aipamenak</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>aip.</single>
+      <multiple>aip.</multiple>
+    </term>
+    <term name="retrieved">berreskuratua</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">K.a.</term>
+    <term name="bc">K.o.</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">“</term>
+    <term name="close-inner-quote">â€</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">lehengo</term>
+    <term name="long-ordinal-02">bigarren</term>
+    <term name="long-ordinal-03">hirugarren</term>
+    <term name="long-ordinal-04">laugarren</term>
+    <term name="long-ordinal-05">bosgarren</term>
+    <term name="long-ordinal-06">seigarren</term>
+    <term name="long-ordinal-07">zazpigarren</term>
+    <term name="long-ordinal-08">zortzigarren</term>
+    <term name="long-ordinal-09">bederatzigarren</term>
+    <term name="long-ordinal-10">hamargarren</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologia</term>
+    <term name="astronomy">astronomia</term>
+    <term name="biology">biologia</term>
+    <term name="botany">botanika</term>
+    <term name="chemistry">kimika</term>
+    <term name="engineering">ingenieritza</term>
+    <term name="generic-base">oinarri orokorra</term>
+    <term name="geography">geografia</term>
+    <term name="geology">geologia</term>
+    <term name="history">historia</term>
+    <term name="humanities">giza-gaiak</term>
+    <term name="linguistics">hizkuntzalaritza</term>
+    <term name="literature">literatura</term>
+    <term name="math">matematika</term>
+    <term name="medicine">medikuntza</term>
+    <term name="philosophy">filosofia</term>
+    <term name="physics">fiska</term>
+    <term name="psychology">psicologia</term>
+    <term name="sociology">soziologia</term>
+    <term name="science">zientziak</term>
+    <term name="political_science">politika zientziak</term>
+    <term name="social_science">gizarte zientziak</term>
+    <term name="theology">teologia</term>
+    <term name="zoology">zoologia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>liburua</single>
+      <multiple>liburuak</multiple>
+    </term>
+    <term name="chapter">
+      <single>kapitulua</single>
+      <multiple>kapituluak</multiple>
+    </term>
+    <term name="column">
+      <single>zutabea</single>
+      <multiple>zutabeak</multiple>
+    </term>
+    <term name="figure">
+      <single>irudia</single>
+      <multiple>irudiak</multiple>
+    </term>
+    <term name="folio">
+      <single>orria</single>
+      <multiple>orriak</multiple>
+    </term>
+    <term name="issue">
+      <single>zenbakia</single>
+      <multiple>zenbakiak</multiple>
+    </term>
+    <term name="line">
+      <single>lerroa</single>
+      <multiple>lerroak</multiple>
+    </term>
+    <term name="note">
+      <single>oharra</single>
+      <multiple>oharrak</multiple>
+    </term>
+    <term name="opus">
+      <single>obra</single>
+      <multiple>obrak</multiple>
+    </term>
+    <term name="page">
+      <single>orrialdea</single>
+      <multiple>orrialdeak</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragrafoa</single>
+      <multiple>paragrafoak</multiple>
+    </term>
+    <term name="part">
+      <single>zatia</single>
+      <multiple>zatiak</multiple>
+    </term>
+    <term name="section">
+      <single>atala</single>
+      <multiple>atalak</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub voce</single>
+      <multiple>sub vocem</multiple>
+    </term>
+    <term name="verse">
+      <single>bertsoa</single>
+      <multiple>bertsoak</multiple>
+    </term>
+    <term name="volume">
+      <single>luburikia</single>
+      <multiple>luburukiak</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">lib.</term>
+    <term name="chapter" form="short">kap.</term>
+    <term name="column" form="short">zut.</term>
+    <term name="figure" form="short">iru.</term>
+    <term name="folio" form="short">or.</term>
+    <term name="issue" form="short">zenb.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>or.</single>
+      <multiple>or.</multiple>
+    </term>
+    <term name="paragraph" form="short">par.</term>
+    <term name="part" form="short">zt.</term>
+    <term name="section" form="short">atal.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.v.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>b.</single>
+      <multiple>bb.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>libk.</single>
+      <multiple>libk.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>argitaratzailea</single>
+      <multiple>argitaratzaileak</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>argitaratzailea</single>
+      <multiple>argitaratzaileak</multiple>
+    </term>
+    <term name="translator">
+      <single>itzultzailea</single>
+      <multiple>itzultzaileak</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>argitaratzaile eta itzultzailea</single>
+      <multiple>argitaratzaile eta itzultzaileak</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>arg.</single>
+      <multiple>arg.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>arg.</single>
+      <multiple>arg.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>itzul.</single>
+      <multiple>itzul.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>arg. eta itzul.</single>
+      <multiple>arg. eta itzul.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">-(e)k argitaratua</term>
+    <term name="editorial-director" form="verb">-(e)k argitaratua</term>
+    <term name="translator" form="verb">-(e)k itzulia</term>
+    <term name="editortranslator" form="verb">-(e)k argitaratu eta itzulia</term>
+    <term name="recipient" form="verb">-(r)entzat</term>
+    <term name="interviewer" form="verb">-(e)k elkarrizketatua</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short"></term>
+    <term name="editor" form="verb-short">arg.</term>
+    <term name="editorial-director" form="verb-short">arg.</term>
+    <term name="translator" form="verb-short">itzul.</term>
+    <term name="editortranslator" form="verb-short">-(e)k arg. eta itzul.</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">urtarrilak</term>
+    <term name="month-02">otsailak</term>
+    <term name="month-03">martxoak</term>
+    <term name="month-04">apirilak</term>
+    <term name="month-05">maiatzak</term>
+    <term name="month-06">ekainak</term>
+    <term name="month-07">uztailak</term>
+    <term name="month-08">abuztuak</term>
+    <term name="month-09">irailak</term>
+    <term name="month-10">urriak</term>
+    <term name="month-11">azaroak</term>
+    <term name="month-12">abenduak</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">urt.</term>
+    <term name="month-02" form="short">ots.</term>
+    <term name="month-03" form="short">martx.</term>
+    <term name="month-04" form="short">apr.</term>
+    <term name="month-05" form="short">mai.</term>
+    <term name="month-06" form="short">eka.</term>
+    <term name="month-07" form="short">uzt.</term>
+    <term name="month-08" form="short">abz.</term>
+    <term name="month-09" form="short">ira.</term>
+    <term name="month-10" form="short">urr.</term>
+    <term name="month-11" form="short">aza.</term>
+    <term name="month-12" form="short">abe.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">udaberria</term>
+    <term name="season-02">uda</term>
+    <term name="season-03">udazkena</term>
+    <term name="season-04">negua</term>
+  </terms>
+</locale>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-fa-IR.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="fa-IR">
+  <style-options punctuation-in-quote="true"/>
+  <date form="text">
+    <date-part name="month" suffix=" "/>
+    <date-part name="day" form="numeric-leading-zeros" suffix=", "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">دسترسی</term>
+    <term name="and">Ùˆ</term>
+    <term name="and others">و دیگران</term>
+    <term name="anonymous">ناشناس</term>
+    <term name="anonymous" form="short">ناشناس</term>
+    <term name="at">در</term>
+    <term name="by">توسط</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">یادکرد</term>
+    <term name="edition">
+      <single>ویرایش</single>
+      <multiple>ویرایش‌های</multiple>
+    </term>
+    <term name="edition" form="short">ویرایش</term>
+    <term name="et-al">و دیگران</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">از</term>
+    <term name="ibid">همان</term>
+    <term name="in">در</term>
+    <term name="in press">زیر چاپ</term>
+    <term name="internet">اینترنت</term>
+    <term name="interview">مصاحبه</term>
+    <term name="letter">نامه</term>
+    <term name="no date">بدون تاریخ</term>
+    <term name="no date" form="short">بدون تاریخ</term>
+    <term name="online">برخط</term>
+    <term name="presented at">ارائه شده در</term>
+    <term name="reference">
+      <single>مرجع</single>
+      <multiple>مراجع</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>مرجع</single>
+      <multiple>مراجع</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+
+      <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+      <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+      <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+      <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">اول</term>
+    <term name="long-ordinal-02">دوم</term>
+    <term name="long-ordinal-03">سوم</term>
+    <term name="long-ordinal-04">چهارم</term>
+    <term name="long-ordinal-05">پنجم</term>
+    <term name="long-ordinal-06">ششم</term>
+    <term name="long-ordinal-07">Ù‡ÙØªÙ…</term>
+    <term name="long-ordinal-08">هشتم</term>
+    <term name="long-ordinal-09">نهم</term>
+    <term name="long-ordinal-10">دهم</term>
+
+   <!-- CATEGORIES -->
+    <term name="anthropology">مردمشناسی</term>
+    <term name="astronomy">ستاره‌شناسی</term>
+    <term name="biology">زیستشناسی</term>
+    <term name="botany">گیاه‌شناسی</term>
+    <term name="chemistry">شیمی</term>
+    <term name="engineering">مهندسی</term>
+    <term name="generic-base">کلیات</term>
+    <term name="geography">جغراÙیا</term>
+    <term name="geology">زمینشناسی</term>
+    <term name="history">تاریخ</term>
+    <term name="humanities">علوم انسانی</term>
+    <term name="linguistics">زبان‌شناسی</term>
+    <term name="literature">ادبیات</term>
+    <term name="math">ریاضیات</term>
+    <term name="medicine">پزشکی</term>
+    <term name="philosophy">ÙلسÙÙ‡</term>
+    <term name="physics">Ùیزیک</term>
+    <term name="psychology">روانشناسی</term>
+    <term name="sociology">جامعه‌شناسی</term>
+    <term name="science">علوم</term>
+    <term name="political_science">علوم سیاسی</term>
+    <term name="social_science">علوم اجتماعی</term>
+    <term name="theology">الهیات</term>
+    <term name="zoology">جانورشناسی</term>
+ 
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>کتاب</single>
+      <multiple>کتاب‌های</multiple>
+    </term>
+    <term name="chapter">
+      <single>ÙØµÙ„</single>
+      <multiple>ÙØµÙ„‌های</multiple>
+    </term>
+    <term name="column">
+      <single>ستون</single>
+      <multiple>ستون‌های</multiple>
+    </term>
+    <term name="figure">
+      <single>تصویر</single>
+      <multiple>تصاویر</multiple>
+    </term>
+    <term name="folio">
+      <single>برگ</single>
+      <multiple>برگ‌های</multiple>
+    </term>
+    <term name="issue">
+      <single>شماره</single>
+      <multiple>شماره‌های</multiple>
+    </term>
+    <term name="line">
+      <single>خط</single>
+      <multiple>خطوط</multiple>
+    </term>
+    <term name="note">
+      <single>یادداشت</single>
+      <multiple>یادداشت‌های</multiple>
+    </term>
+    <term name="opus">
+      <single>قطعه</single>
+      <multiple>قطعات</multiple>
+    </term>
+    <term name="page">
+      <single>ØµÙØ­Ù‡</single>
+      <multiple>ØµÙØ­Ø§Øª</multiple>
+    </term>
+    <term name="paragraph">
+      <single>پاراگراÙ</single>
+      <multiple>پاراگراÙ‌های</multiple>
+    </term>
+    <term name="part">
+      <single>بخش</single>
+      <multiple>بخش‌های</multiple>
+    </term>
+    <term name="section">
+      <single>قسمت</single>
+      <multiple>قسمت‌های</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>بیت</single>
+      <multiple>بیت‌های</multiple>
+    </term>
+    <term name="volume">
+      <single>جلد</single>
+      <multiple>جلدهای</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">کتاب</term>
+    <term name="chapter" form="short">ÙØµÙ„</term>
+    <term name="column" form="short">ستون</term>
+    <term name="figure" form="short">تصویر</term>
+    <term name="folio" form="short">برگ</term>
+    <term name="issue" form="short">Ø´</term>
+    <term name="opus" form="short">قطعه</term>
+    <term name="page" form="short">
+      <single>ص</single>
+      <multiple>صص</multiple>
+    </term>
+    <term name="paragraph" form="short">پاراگراÙ</term>
+    <term name="part" form="short">بخش</term>
+    <term name="section" form="short">قسمت</term>
+    <term name="sub verbo" form="short">
+      <single>s.v</single>
+      <multiple>s.vv</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>بیت</single>
+      <multiple>ابیات</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>ج</single>
+      <multiple>جج</multiple>
+    </term>
+
+      <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+      <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>ویرایشگر</single>
+      <multiple>ویرایشگران</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>ویرایشگر</single>
+      <multiple>ویرایشگران</multiple>
+    </term>
+    <term name="translator">
+      <single>مترجم</single>
+      <multiple>مترجمین</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>ویرایشگر و مترجم</single>
+      <multiple>ویرایشگران و مترجمین</multiple>
+    </term>
+
+      <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ویرایشگر</single>
+      <multiple>ویرایشگران</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ویرایشگر</single>
+      <multiple>ویرایشگران</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>مترجم</single>
+      <multiple>مترجمین</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ویرایشگر و مترجم</single>
+      <multiple>ویرایشگران و مترجمین</multiple>
+    </term>
+
+      <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">edited by</term>
+    <term name="editorial-director" form="verb">ویراسته‌ی</term>
+    <term name="translator" form="verb">ترجمه‌ی</term>
+    <term name="editortranslator" form="verb">ترجمه و ویراسته‌ی</term>
+    <term name="recipient" form="verb">به</term>
+    <term name="interviewer" form="verb">مصاحبه توسط</term>
+
+      <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">توسط</term>
+    <term name="editor" form="verb-short">ویراسته‌ی</term>
+    <term name="editorial-director" form="verb-short">ویراسته‌ی</term>
+    <term name="translator" form="verb-short">ترجمه‌ی</term>
+    <term name="editortranslator" form="verb-short">ترجمه و ویراسته‌ی</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">ژانویه</term>
+    <term name="month-02">Ùوریه</term>
+    <term name="month-03">مارس</term>
+    <term name="month-04">آوریل</term>
+    <term name="month-05">می</term>
+    <term name="month-06">ژوئن</term>
+    <term name="month-07">جولای</term>
+    <term name="month-08">آگوست</term>
+    <term name="month-09">سپتامبر</term>
+    <term name="month-10">اکتبر</term>
+    <term name="month-11">نوامبر</term>
+    <term name="month-12">دسامبر</term>
+    
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">ژانویه</term>
+    <term name="month-02" form="short">Ùوریه</term>
+    <term name="month-03" form="short">مارس</term>
+    <term name="month-04" form="short">آوریل</term>
+    <term name="month-05" form="short">می</term>
+    <term name="month-06" form="short">ژوئن</term>
+    <term name="month-07" form="short">جولای</term>
+    <term name="month-08" form="short">آگوست</term>
+    <term name="month-09" form="short">سپتامبر</term>
+    <term name="month-10" form="short">اکتبر</term>
+    <term name="month-11" form="short">نوامبر</term>
+    <term name="month-12" form="short">دسامبر</term>
+
+      <!-- SEASONS -->
+    <term name="season-01">بهار</term>
+    <term name="season-02">تابستان</term>
+    <term name="season-03">پاییز</term>
+    <term name="season-04">زمستان</term>
+  </terms>
+</locale>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-fi-FI.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="fi-FI">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" suffix="."/>
+    <date-part name="month" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">viitattu</term>
+    <term name="and">ja</term>
+    <term name="and others">ym.</term>
+    <term name="anonymous">tuntematon</term>
+    <term name="anonymous" form="short">tuntematon</term>
+    <term name="at">osoitteessa</term>
+    <term name="by">tekijä</term>
+    <term name="circa">noin</term>
+    <term name="circa" form="short">n.</term>
+    <term name="cited">viitattu</term>
+    <term name="edition">
+      <single>painos</single>
+      <multiple>painokset</multiple>
+    </term>
+    <term name="edition" form="short">p.</term>
+    <term name="et-al">ym.</term>
+    <term name="forthcoming">tulossa</term>
+    <term name="from">alkaen</term>
+    <term name="ibid">mt.</term>
+    <term name="in">teoksessa</term>
+    <term name="in press">painossa</term>
+    <term name="internet">internet</term>
+    <term name="interview">haastattelu</term>
+    <term name="letter">kirje</term>
+    <term name="no date">ei päivämäärää</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">verkossa</term>
+    <term name="presented at">esitetty tilaisuudessa</term>
+    <term name="reference">
+      <single>viittaus</single>
+      <multiple>viittaukset</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>viit..</single>
+      <multiple>viit.</multiple>
+    </term>
+    <term name="retrieved">noudettu</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">eaa.</term>
+    <term name="bc">jaa.</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">ensimmäinen</term>
+    <term name="long-ordinal-02">toinen</term>
+    <term name="long-ordinal-03">kolmas</term>
+    <term name="long-ordinal-04">neljäs</term>
+    <term name="long-ordinal-05">viides</term>
+    <term name="long-ordinal-06">kuudes</term>
+    <term name="long-ordinal-07">seitsemäs</term>
+    <term name="long-ordinal-08">kahdeksas</term>
+    <term name="long-ordinal-09">yhdeksäs</term>
+    <term name="long-ordinal-10">kymmenes</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologia</term>
+    <term name="astronomy">tähtitiede</term>
+    <term name="biology">biologia</term>
+    <term name="botany">kasvitiede</term>
+    <term name="chemistry">kemia</term>
+    <term name="engineering">tekniikka</term>
+    <term name="generic-base">yleinen</term>
+    <term name="geography">maantiede</term>
+    <term name="geology">geologia</term>
+    <term name="history">historia</term>
+    <term name="humanities">humanistiset tieteet</term>
+    <term name="linguistics">kielitiede</term>
+    <term name="literature">kirjallisuus</term>
+    <term name="math">matematiikka</term>
+    <term name="medicine">lääketiede</term>
+    <term name="philosophy">filosofia</term>
+    <term name="physics">fysiikka</term>
+    <term name="psychology">psykologia</term>
+    <term name="sociology">sosiologia</term>
+    <term name="science">luonnontieteet</term>
+    <term name="political_science">politiikan tutkimus</term>
+    <term name="social_science">yhteiskuntatieteet</term>
+    <term name="theology">teologia</term>
+    <term name="zoology">eläintiede</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>kirja</single>
+      <multiple>kirjat</multiple>
+    </term>
+    <term name="chapter">
+      <single>luku</single>
+      <multiple>luvut</multiple>
+    </term>
+    <term name="column">
+      <single>palsta</single>
+      <multiple>palstat</multiple>
+    </term>
+    <term name="figure">
+      <single>kuvio</single>
+      <multiple>kuviot</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>foliot</multiple>
+    </term>
+    <term name="issue">
+      <single>numero</single>
+      <multiple>numerot</multiple>
+    </term>
+    <term name="line">
+      <single>rivi</single>
+      <multiple>rivit</multiple>
+    </term>
+    <term name="note">
+      <single>muistiinpano</single>
+      <multiple>muistiinpanot</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opukset</multiple>
+    </term>
+    <term name="page">
+      <single>sivu</single>
+      <multiple>sivut</multiple>
+    </term>
+    <term name="paragraph">
+      <single>kappale</single>
+      <multiple>kappaleet</multiple>
+    </term>
+    <term name="part">
+      <single>osa</single>
+      <multiple>osat</multiple>
+    </term>
+    <term name="section">
+      <single>osa</single>
+      <multiple>osat</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>säkeistö</single>
+      <multiple>säkeistöt</multiple>
+    </term>
+    <term name="volume">
+      <single>vuosikerta</single>
+      <multiple>vuosikerrat</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">kirja</term>
+    <term name="chapter" form="short">luku</term>
+    <term name="column" form="short">palsta</term>
+    <term name="figure" form="short">kuv.</term>
+    <term name="folio" form="short">fol.</term>
+    <term name="issue" form="short">nro</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>s.</single>
+      <multiple>ss.</multiple>
+    </term>
+    <term name="paragraph" form="short">kappale</term>
+    <term name="part" form="short">osa</term>
+    <term name="section" form="short">osa</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>säk.</single>
+      <multiple>säk.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vol.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>toimittaja</single>
+      <multiple>toimittajat</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>toimittaja</single>
+      <multiple>toimittajat</multiple>
+    </term>
+    <term name="translator">
+      <single>suomentaja</single>
+      <multiple>suomentajat</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>toimittaja ja suomentaja</single>
+      <multiple>toimittajat ja suomentajat</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>toim.</single>
+      <multiple>toim.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>toim.</single>
+      <multiple>toim.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>suom.</single>
+      <multiple>suom.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>toim. ja suom.</single>
+      <multiple>toim. ja suom.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">toimittanut</term>
+    <term name="editorial-director" form="verb">toimittanut</term>
+    <term name="translator" form="verb">suomentanut</term>
+    <term name="editortranslator" form="verb">toimittanut ja suomentanut</term>
+    <term name="recipient" form="verb">vastaanottaja</term>
+    <term name="interviewer" form="verb">haastatellut</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short"></term>
+    <term name="editor" form="verb-short">toim.</term>
+    <term name="editorial-director" form="verb-short">toim.</term>
+    <term name="translator" form="verb-short">suom.</term>
+    <term name="editortranslator" form="verb-short">toim. ja suom.</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">tammikuu</term>
+    <term name="month-02">helmikuu</term>
+    <term name="month-03">maaliskuu</term>
+    <term name="month-04">huhtikuu</term>
+    <term name="month-05">toukokuu</term>
+    <term name="month-06">kesäkuu</term>
+    <term name="month-07">heinäkuu</term>
+    <term name="month-08">elokuu</term>
+    <term name="month-09">syyskuu</term>
+    <term name="month-10">lokakuu</term>
+    <term name="month-11">marraskuu</term>
+    <term name="month-12">joulukuu</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">tammi</term>
+    <term name="month-02" form="short">helmi</term>
+    <term name="month-03" form="short">maalis</term>
+    <term name="month-04" form="short">huhti</term>
+    <term name="month-05" form="short">touko</term>
+    <term name="month-06" form="short">kesä</term>
+    <term name="month-07" form="short">heinä</term>
+    <term name="month-08" form="short">elo</term>
+    <term name="month-09" form="short">syys</term>
+    <term name="month-10" form="short">loka</term>
+    <term name="month-11" form="short">marras</term>
+    <term name="month-12" form="short">joulu</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">kevät</term>
+    <term name="season-02">kesä</term>
+    <term name="season-03">syksy</term>
+    <term name="season-04">talvi</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-fr-FR.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="fr-FR">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">consulté</term>
+    <term name="and">et</term>
+    <term name="and others">et autres</term>
+    <term name="anonymous">anonyme</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">à</term>
+    <term name="by">par</term>
+    <term name="circa">vers</term>
+    <term name="circa" form="short">v.</term>
+    <term name="cited">cité</term>
+    <term name="edition">
+      <single>édition</single>
+      <multiple>éditions</multiple>
+    </term>
+    <term name="edition" form="short">éd.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">à paraître</term>
+    <term name="from">de</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">dans</term>
+    <term name="in press">sous presse</term>
+    <term name="internet">Internet</term>
+    <term name="interview">entretien</term>
+    <term name="letter">lettre</term>
+    <term name="no date">sans date</term>
+    <term name="no date" form="short">s. d.</term>
+    <term name="online">en ligne</term>
+    <term name="presented at">présenté à</term>
+    <term name="reference">
+      <single>référence</single>
+      <multiple>références</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>réf.</single>
+      <multiple>réf.</multiple>
+    </term>
+    <term name="retrieved">consulté</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">apr. J.-C.</term>
+    <term name="bc">av. J.-C.</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">« </term>
+    <term name="close-quote"> »</term>
+    <term name="open-inner-quote">“</term>
+    <term name="close-inner-quote">â€</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">ᵉʳ</term>
+    <term name="ordinal-02">ᵉ</term>
+    <term name="ordinal-03">ᵉ</term>
+    <term name="ordinal-04">ᵉ</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">premier</term>
+    <term name="long-ordinal-02">deuxième</term>
+    <term name="long-ordinal-03">troisième</term>
+    <term name="long-ordinal-04">quatrième</term>
+    <term name="long-ordinal-05">cinquième</term>
+    <term name="long-ordinal-06">sixième</term>
+    <term name="long-ordinal-07">septième</term>
+    <term name="long-ordinal-08">huitième</term>
+    <term name="long-ordinal-09">neuvième</term>
+    <term name="long-ordinal-10">dixième</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropologie</term>
+    <term name="astronomy">astronomie</term>
+    <term name="biology">biologie</term>
+    <term name="botany">botanique</term>
+    <term name="chemistry">chimie</term>
+    <term name="engineering">ingénierie</term>
+    <term name="generic-base">base générique</term>
+    <term name="geography">géographie</term>
+    <term name="geology">géologie</term>
+    <term name="history">histoire</term>
+    <term name="humanities">lettres et sciences humaines</term>
+    <term name="linguistics">linguistique</term>
+    <term name="literature">littérature</term>
+    <term name="math">mathématiques</term>
+    <term name="medicine">médecine</term>
+    <term name="philosophy">philosophie</term>
+    <term name="physics">physique</term>
+    <term name="psychology">psychologie</term>
+    <term name="sociology">sociologie</term>
+    <term name="science">sciences de la nature</term>
+    <term name="political_science">science politique</term>
+    <term name="social_science">sciences sociales</term>
+    <term name="theology">théologie</term>
+    <term name="zoology">zoologie</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>livre</single>
+      <multiple>livres</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapitre</single>
+      <multiple>chapitres</multiple>
+    </term>
+    <term name="column">
+      <single>colonne</single>
+      <multiple>colonnes</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>numéro</single>
+      <multiple>numéros</multiple>
+    </term>
+    <term name="line">
+      <single>ligne</single>
+      <multiple>lignes</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opus</multiple>
+    </term>
+    <term name="page">
+      <single>page</single>
+      <multiple>pages</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraphe</single>
+      <multiple>paragraphes</multiple>
+    </term>
+    <term name="part">
+      <single>partie</single>
+      <multiple>parties</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verset</single>
+      <multiple>versets</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">liv.</term>
+    <term name="chapter" form="short">chap.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">fáµ’</term>
+    <term name="issue" form="short">náµ’</term>
+    <term name="line" form="short">l.</term>
+    <term name="note" form="short">n.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>p.</multiple>
+    </term>
+    <term name="paragraph" form="short">paragr.</term>
+    <term name="part" form="short">part.</term>
+    <term name="section" form="short">sect.</term>
+    <term name="sub verbo" form="short">
+      <single>s. v.</single>
+      <multiple>s. vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>v.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vol.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>§</single>
+      <multiple>§</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>éditeur</single>
+      <multiple>éditeurs</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>directeur</single>
+      <multiple>directeurs</multiple>
+    </term>
+    <term name="translator">
+      <single>traducteur</single>
+      <multiple>traducteurs</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>éditeur et traducteur</single>
+      <multiple>éditeurs et traducteurs</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>éd.</single>
+      <multiple>éd.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>dir.</single>
+      <multiple>dir.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>trad.</single>
+      <multiple>trad.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>éd. et trad.</single>
+      <multiple>éd. et trad.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">édité par</term>
+    <term name="editorial-director" form="verb">sous la direction de</term>
+    <term name="translator" form="verb">traduit par</term>
+    <term name="editortranslator" form="verb">édité et traduit par</term>
+    <term name="recipient" form="verb">à</term>
+    <term name="interviewer" form="verb">entretien réalisé par</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">par</term>
+    <term name="editor" form="verb-short">éd. par</term>
+    <term name="editorial-director" form="verb-short">ss la dir. de</term>
+    <term name="translator" form="verb-short">trad. par</term>
+    <term name="editortranslator" form="verb-short">éd. et trad. par</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">janvier</term>
+    <term name="month-02">février</term>
+    <term name="month-03">mars</term>
+    <term name="month-04">avril</term>
+    <term name="month-05">mai</term>
+    <term name="month-06">juin</term>
+    <term name="month-07">juillet</term>
+    <term name="month-08">août</term>
+    <term name="month-09">septembre</term>
+    <term name="month-10">octobre</term>
+    <term name="month-11">novembre</term>
+    <term name="month-12">décembre</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">janv.</term>
+    <term name="month-02" form="short">févr.</term>
+    <term name="month-03" form="short">mars</term>
+    <term name="month-04" form="short">avr.</term>
+    <term name="month-05" form="short">mai</term>
+    <term name="month-06" form="short">juin</term>
+    <term name="month-07" form="short">juill.</term>
+    <term name="month-08" form="short">août</term>
+    <term name="month-09" form="short">sept.</term>
+    <term name="month-10" form="short">oct.</term>
+    <term name="month-11" form="short">nov.</term>
+    <term name="month-12" form="short">déc.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">printemps</term>
+    <term name="season-02">été</term>
+    <term name="season-03">automne</term>
+    <term name="season-04">hiver</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-he-IL.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="he-IL">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">גישה</term>
+    <term name="and">ו</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">-ב</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">ו×חרי×</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">מתוך</term>
+    <term name="ibid">ש×</term>
+    <term name="in">בתוך</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">nd</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">×וחזר</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>ספר</single>
+      <multiple>ספרי×</multiple>
+    </term>
+    <term name="chapter">
+      <single>פרק</single>
+      <multiple>פרקי×</multiple>
+    </term>
+    <term name="column">
+      <single>טור</single>
+      <multiple>טורי×</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>מספר</single>
+      <multiple>מספרי×</multiple>
+    </term>
+    <term name="line">
+      <single>שורה</single>
+      <multiple>שורות</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>×ופוס</single>
+      <multiple>×ופרה</multiple>
+    </term>
+    <term name="page">
+      <single>עמוד</single>
+      <multiple>עמודי×</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraph</single>
+      <multiple>פיסקה</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>בית</single>
+      <multiple>בתי×</multiple>
+    </term>
+    <term name="volume">
+      <single>כרך</single>
+      <multiple>כרכי×</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk</term>
+    <term name="chapter" form="short">chap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">no</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>'עמ</single>
+      <multiple>'עמ</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>עורך</single>
+      <multiple>עורכי×</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>מתרג×</single>
+      <multiple>מתרגמי×</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed</single>
+      <multiple>eds</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tran</single>
+      <multiple>trans</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">נערך ע"י</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">×ª×•×¨×’× ×¢"×™</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">ינו×ר</term>
+    <term name="month-02">פברו×ר</term>
+    <term name="month-03">מרץ</term>
+    <term name="month-04">×פריל</term>
+    <term name="month-05">מ××™</term>
+    <term name="month-06">יוני</term>
+    <term name="month-07">יולי</term>
+    <term name="month-08">×וגוסט</term>
+    <term name="month-09">ספטמבר</term>
+    <term name="month-10">×וקטובר</term>
+    <term name="month-11">נובמבר</term>
+    <term name="month-12">דצמבר</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan</term>
+    <term name="month-02" form="short">Feb</term>
+    <term name="month-03" form="short">Mar</term>
+    <term name="month-04" form="short">Apr</term>
+    <term name="month-05" form="short">May</term>
+    <term name="month-06" form="short">Jun</term>
+    <term name="month-07" form="short">Jul</term>
+    <term name="month-08" form="short">Aug</term>
+    <term name="month-09" form="short">Sep</term>
+    <term name="month-10" form="short">Oct</term>
+    <term name="month-11" form="short">Nov</term>
+    <term name="month-12" form="short">Dec</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-hu-HU.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="hu-HU">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="year"/>
+    <date-part name="month" prefix=". "/>
+    <date-part name="day" prefix=" " suffix="."/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="."/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="."/>
+  </date>
+  <terms>
+    <term name="accessed">elérés</term>
+    <term name="and">és</term>
+    <term name="and others">és mások</term>
+    <term name="anonymous">név nélkül</term>
+    <term name="anonymous" form="short">nn</term>
+    <term name="at"/>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">idézi</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">megjelenés alatt</term>
+    <term name="from">forrás</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">nyomtatás alatt</term>
+    <term name="internet">internet</term>
+    <term name="interview">interjú</term>
+    <term name="letter">levél</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">nd</term>
+    <term name="online">online</term>
+    <term name="presented at">előadás</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">elérés</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">»</term>
+    <term name="close-inner-quote">«</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropológia</term>
+    <term name="astronomy">csillagászat</term>
+    <term name="biology">biológia</term>
+    <term name="botany">botanika</term>
+    <term name="chemistry">kémia</term>
+    <term name="engineering">mérnöki tudományok</term>
+    <term name="generic-base">általános</term>
+    <term name="geography">földrajz</term>
+    <term name="geology">geológia</term>
+    <term name="history">történelem</term>
+    <term name="humanities">bölcsésztudományok</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">irodalom</term>
+    <term name="math">matematika</term>
+    <term name="medicine">orvostudomány</term>
+    <term name="philosophy">filozófia</term>
+    <term name="physics">fizika</term>
+    <term name="psychology">pszichológia</term>
+    <term name="sociology">szociológia</term>
+    <term name="science">tudomány</term>
+    <term name="political_science">politikatudomány</term>
+    <term name="social_science">társadalomtudomány</term>
+    <term name="theology">teológia</term>
+    <term name="zoology">zoológia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>könyv</single>
+      <multiple>könyv</multiple>
+    </term>
+    <term name="chapter">
+      <single>fejezet</single>
+      <multiple>fejezet</multiple>
+    </term>
+    <term name="column">
+      <single>oszlop</single>
+      <multiple>oszlop</multiple>
+    </term>
+    <term name="figure">
+      <single>ábra</single>
+      <multiple>ábra</multiple>
+    </term>
+    <term name="folio">
+      <single>fóliáns</single>
+      <multiple>fóliáns</multiple>
+    </term>
+    <term name="issue">
+      <single>szám</single>
+      <multiple>szám</multiple>
+    </term>
+    <term name="line">
+      <single>sor</single>
+      <multiple>sor</multiple>
+    </term>
+    <term name="note">
+      <single>jegyzet</single>
+      <multiple>jegyzet</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>oldal</single>
+      <multiple>oldal</multiple>
+    </term>
+    <term name="paragraph">
+      <single>bekezdés</single>
+      <multiple>bekezdés</multiple>
+    </term>
+    <term name="part">
+      <single>rész</single>
+      <multiple>rész</multiple>
+    </term>
+    <term name="section">
+      <single>szakasz</single>
+      <multiple>szakasz</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>versszak</single>
+      <multiple>versszak</multiple>
+    </term>
+    <term name="volume">
+      <single>kötet</single>
+      <multiple>kötet</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">könyv</term>
+    <term name="chapter" form="short">fej</term>
+    <term name="column" form="short">oszl</term>
+    <term name="figure" form="short">ábr</term>
+    <term name="folio" form="short">fol</term>
+    <term name="issue" form="short">sz</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>o</single>
+      <multiple>o</multiple>
+    </term>
+    <term name="paragraph" form="short">bek</term>
+    <term name="part" form="short">rész</term>
+    <term name="section" form="short">szak</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>vsz</single>
+      <multiple>vsz</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>szerkesztő</single>
+      <multiple>szerkesztő</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>fordító</single>
+      <multiple>fordító</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>szerk</single>
+      <multiple>szerk</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>ford</single>
+      <multiple>ford</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">szerkesztette</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">fordította</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">címzett</term>
+    <term name="interviewer" form="verb">interjúkészítő</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">szerk</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">ford</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">január</term>
+    <term name="month-02">február</term>
+    <term name="month-03">március</term>
+    <term name="month-04">április</term>
+    <term name="month-05">május</term>
+    <term name="month-06">június</term>
+    <term name="month-07">július</term>
+    <term name="month-08">augusztus</term>
+    <term name="month-09">szeptember</term>
+    <term name="month-10">október</term>
+    <term name="month-11">november</term>
+    <term name="month-12">december</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jan</term>
+    <term name="month-02" form="short">febr</term>
+    <term name="month-03" form="short">márc</term>
+    <term name="month-04" form="short">ápr</term>
+    <term name="month-05" form="short">máj</term>
+    <term name="month-06" form="short">jún</term>
+    <term name="month-07" form="short">júl</term>
+    <term name="month-08" form="short">aug</term>
+    <term name="month-09" form="short">szept</term>
+    <term name="month-10" form="short">okt</term>
+    <term name="month-11" form="short">nov</term>
+    <term name="month-12" form="short">dec</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-is-IS.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="is-IS">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" suffix="."/>
+    <date-part name="month" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">sótt</term>
+    <term name="and">og</term>
+    <term name="and others">og fleiri</term>
+    <term name="anonymous">nafnlaus</term>
+    <term name="anonymous" form="short">nafnl.</term>
+    <term name="at">af</term>
+    <term name="by">eftir</term>
+    <term name="circa">sirka</term>
+    <term name="circa" form="short">u.þ.b.</term>
+    <term name="cited">tilvitnun</term>
+    <term name="edition">
+      <single>útgáfa</single>
+      <multiple>útgáfur</multiple>
+    </term>
+    <term name="edition" form="short">útg.</term>
+    <term name="et-al">o.fl.</term>
+    <term name="forthcoming">óbirt</term>
+    <term name="from">af</term>
+    <term name="ibid">sama heimild</term>
+    <term name="in">í</term>
+    <term name="in press">í prentun</term>
+    <term name="internet">rafrænt</term>
+    <term name="interview">viðtal</term>
+    <term name="letter">bréf</term>
+    <term name="no date">engin dagsetning</term>
+    <term name="no date" form="short">e.d.</term>
+    <term name="online">rafrænt</term>
+    <term name="presented at">flutt á</term>
+    <term name="reference">
+      <single>tilvitnun</single>
+      <multiple>tilvitnanir</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>tilv.</single>
+      <multiple>tilv.</multiple>
+    </term>
+    <term name="retrieved">sótt</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">e.Kr.</term>
+    <term name="bc">f.Kr.</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">fyrsti</term>
+    <term name="long-ordinal-02">annar</term>
+    <term name="long-ordinal-03">þriðji</term>
+    <term name="long-ordinal-04">fjórði</term>
+    <term name="long-ordinal-05">fimmti</term>
+    <term name="long-ordinal-06">sjötti</term>
+    <term name="long-ordinal-07">sjöundi</term>
+    <term name="long-ordinal-08">áttundi</term>
+    <term name="long-ordinal-09">níundi</term>
+    <term name="long-ordinal-10">tíundi</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">mannfræði</term>
+    <term name="astronomy">stjörnufræði</term>
+    <term name="biology">líffræði</term>
+    <term name="botany">grasafræði</term>
+    <term name="chemistry">efnafræði</term>
+    <term name="engineering">verkfræði</term>
+    <term name="generic-base">almennt efni</term>
+    <term name="geography">landafræði</term>
+    <term name="geology">jarðfræði</term>
+    <term name="history">saga</term>
+    <term name="humanities">hugvísindi</term>
+    <term name="linguistics">málvísindi</term>
+    <term name="literature">bókmenntir</term>
+    <term name="math">stærðfræði</term>
+    <term name="medicine">læknisfræði</term>
+    <term name="philosophy">heimspeki</term>
+    <term name="physics">eðlisfræði</term>
+    <term name="psychology">sálfræði</term>
+    <term name="sociology">félagsfræði</term>
+    <term name="science">vísindi</term>
+    <term name="political_science">stjórnmálafræði</term>
+    <term name="social_science">félagsvísindi</term>
+    <term name="theology">guðfræði</term>
+    <term name="zoology">dýrafræði</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>bók</single>
+      <multiple>bækur</multiple>
+    </term>
+    <term name="chapter">
+      <single>kafli</single>
+      <multiple>kaflar</multiple>
+    </term>
+    <term name="column">
+      <single>dálkur</single>
+      <multiple>dálkar</multiple>
+    </term>
+    <term name="figure">
+      <single>mynd</single>
+      <multiple>myndir</multiple>
+    </term>
+    <term name="folio">
+      <single>handrit</single>
+      <multiple>handrit</multiple>
+    </term>
+    <term name="issue">
+      <single>númer</single>
+      <multiple>númer</multiple>
+    </term>
+    <term name="line">
+      <single>lína</single>
+      <multiple>línur</multiple>
+    </term>
+    <term name="note">
+      <single>skilaboð</single>
+      <multiple>skilaboð</multiple>
+    </term>
+    <term name="opus">
+      <single>tónverk</single>
+      <multiple>tónverk</multiple>
+    </term>
+    <term name="page">
+      <single>blaðsíða</single>
+      <multiple>blaðsíður</multiple>
+    </term>
+    <term name="paragraph">
+      <single>málsgrein</single>
+      <multiple>málsgreinar</multiple>
+    </term>
+    <term name="part">
+      <single>hluti</single>
+      <multiple>hlutar</multiple>
+    </term>
+    <term name="section">
+      <single>hluti</single>
+      <multiple>hlutar</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>vers</single>
+      <multiple>vers</multiple>
+    </term>
+    <term name="volume">
+      <single>bindi</single>
+      <multiple>bindi</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">b.</term>
+    <term name="chapter" form="short">k.</term>
+    <term name="column" form="short">d.</term>
+    <term name="figure" form="short">mynd.</term>
+    <term name="folio" form="short">handr.</term>
+    <term name="issue" form="short">nr.</term>
+    <term name="opus" form="short">tónv.</term>
+    <term name="page" form="short">
+      <single>bls.</single>
+      <multiple>bls.</multiple>
+    </term>
+    <term name="paragraph" form="short">málsgr.</term>
+    <term name="part" form="short">hl.</term>
+    <term name="section" form="short">hl.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>v.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>bindi</single>
+      <multiple>bindi</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single>höfundur</single>
+      <multiple>höfundar</multiple>
+    </term>
+    <term name="editor">
+      <single>ritstjóri</single>
+      <multiple>ritstjórar</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>ritstjóri</single>
+      <multiple>ritstjórar</multiple>
+    </term>
+    <term name="translator">
+      <single>þýðandi</single>
+      <multiple>þýðendur</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>ritstjóri og þýðandi</single>
+      <multiple>ritstjórar og þýðendur</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single>höf.</single>
+      <multiple>höf.</multiple>
+    </term>
+    <term name="editor" form="short">
+      <single>ritstj.</single>
+      <multiple>ritstj.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ritstj.</single>
+      <multiple>ritstj.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>þýð.</single>
+      <multiple>þýð.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ritstj. og þýð.</single>
+      <multiple>ritstj. og þýð.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">ritstjóri</term>
+    <term name="editorial-director" form="verb">ritstjóri</term>
+    <term name="translator" form="verb">þýddi</term>
+    <term name="editortranslator" form="verb">ritstjóri og þýðandi</term>
+    <term name="recipient" form="verb">til</term>
+    <term name="interviewer" form="verb">viðtal tók</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">eftir</term>
+    <term name="editor" form="verb-short">ritst.</term>
+    <term name="editorial-director" form="verb-short">ritst.</term>
+    <term name="translator" form="verb-short">þýð.</term>
+    <term name="editortranslator" form="verb-short">ritst. og þýð.</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">janúar</term>
+    <term name="month-02">febrúar</term>
+    <term name="month-03">mars</term>
+    <term name="month-04">apríl</term>
+    <term name="month-05">maí</term>
+    <term name="month-06">júní</term>
+    <term name="month-07">júlí</term>
+    <term name="month-08">ágúst</term>
+    <term name="month-09">september</term>
+    <term name="month-10">október</term>
+    <term name="month-11">nóvember</term>
+    <term name="month-12">desember</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jan.</term>
+    <term name="month-02" form="short">feb.</term>
+    <term name="month-03" form="short">mar.</term>
+    <term name="month-04" form="short">apr.</term>
+    <term name="month-05" form="short">maí</term>
+    <term name="month-06" form="short">jún.</term>
+    <term name="month-07" form="short">júl.</term>
+    <term name="month-08" form="short">ágú.</term>
+    <term name="month-09" form="short">sep.</term>
+    <term name="month-10" form="short">okt.</term>
+    <term name="month-11" form="short">nóv.</term>
+    <term name="month-12" form="short">des.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">vor</term>
+    <term name="season-02">sumar</term>
+    <term name="season-03">haust</term>
+    <term name="season-04">vetur</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-it-IT.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="it-IT">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">consultato</term>
+    <term name="and">e</term>
+    <term name="and others">e altri</term>
+    <term name="anonymous">anonimo</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">a</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">citato</term>
+    <term name="edition">
+      <single>edizione</single>
+      <multiple>edizioni</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">futuro</term>
+    <term name="from">da</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in stampa</term>
+    <term name="internet">internet</term>
+    <term name="interview">intervista</term>
+    <term name="letter">lettera</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">S.d.</term>
+    <term name="online">in linea</term>
+    <term name="presented at">presentato al</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">recuperato</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologia</term>
+    <term name="astronomy">astronomia</term>
+    <term name="biology">biologia</term>
+    <term name="botany">botanica</term>
+    <term name="chemistry">chimica</term>
+    <term name="engineering">ingegneria</term>
+    <term name="generic-base">generica</term>
+    <term name="geography">geografia</term>
+    <term name="geology">geologia</term>
+    <term name="history">storia</term>
+    <term name="humanities">discipline umanistiche</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">letteratura</term>
+    <term name="math">matematica</term>
+    <term name="medicine">medicina</term>
+    <term name="philosophy">filosofia</term>
+    <term name="physics">fisica</term>
+    <term name="psychology">psicologia</term>
+    <term name="sociology">sociologia</term>
+    <term name="science">scienze</term>
+    <term name="political_science">scienze politiche</term>
+    <term name="social_science">sociologia</term>
+    <term name="theology">teologia</term>
+    <term name="zoology">zoologia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>libro</single>
+      <multiple>libri</multiple>
+    </term>
+    <term name="chapter">
+      <single>capitolo</single>
+      <multiple>capitoli</multiple>
+    </term>
+    <term name="column">
+      <single>colonna</single>
+      <multiple>colonne</multiple>
+    </term>
+    <term name="figure">
+      <single>figura</single>
+      <multiple>figure</multiple>
+    </term>
+    <term name="folio">
+      <single>foglio</single>
+      <multiple>fogli</multiple>
+    </term>
+    <term name="issue">
+      <single>numero</single>
+      <multiple>numeri</multiple>
+    </term>
+    <term name="line">
+      <single>riga</single>
+      <multiple>righe</multiple>
+    </term>
+    <term name="note">
+      <single>nota</single>
+      <multiple>note</multiple>
+    </term>
+    <term name="opus">
+      <single>opera</single>
+      <multiple>opere</multiple>
+    </term>
+    <term name="page">
+      <single>pagina</single>
+      <multiple>pagine</multiple>
+    </term>
+    <term name="paragraph">
+      <single>capoverso</single>
+      <multiple>capoversi</multiple>
+    </term>
+    <term name="part">
+      <single>parte</single>
+      <multiple>parti</multiple>
+    </term>
+    <term name="section">
+      <single>paragrafo</single>
+      <multiple>paragrafi</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verso</single>
+      <multiple>versi</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumi</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">lib</term>
+    <term name="chapter" form="short">cap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">fgl</term>
+    <term name="issue" form="short">n°</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>pag</single>
+      <multiple>pagg</multiple>
+    </term>
+    <term name="paragraph" form="short">cpv</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">par</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vol</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>curatore</single>
+      <multiple>curatori</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>traduttore</single>
+      <multiple>traduttori</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>cur</single>
+      <multiple>cur</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>trad</single>
+      <multiple>trad</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">a cura di</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">tradotto da</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">a</term>
+    <term name="interviewer" form="verb">intervista di</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">cur. da</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trad. da</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Gennaio</term>
+    <term name="month-02">Febbraio</term>
+    <term name="month-03">Marzo</term>
+    <term name="month-04">Aprile</term>
+    <term name="month-05">Maggio</term>
+    <term name="month-06">Giugno</term>
+    <term name="month-07">Luglio</term>
+    <term name="month-08">Agosto</term>
+    <term name="month-09">Settembre</term>
+    <term name="month-10">Ottobre</term>
+    <term name="month-11">Novembre</term>
+    <term name="month-12">Dicembre</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Gen</term>
+    <term name="month-02" form="short">Feb</term>
+    <term name="month-03" form="short">Mar</term>
+    <term name="month-04" form="short">Apr</term>
+    <term name="month-05" form="short">Mag</term>
+    <term name="month-06" form="short">Giu</term>
+    <term name="month-07" form="short">Lug</term>
+    <term name="month-08" form="short">Ago</term>
+    <term name="month-09" form="short">Set</term>
+    <term name="month-10" form="short">Ott</term>
+    <term name="month-11" form="short">Nov</term>
+    <term name="month-12" form="short">Dic</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-ja-JP.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="ja-JP">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="year" suffix="å¹´"/>
+    <date-part name="month" form="numeric" suffix="月"/>
+    <date-part name="day" suffix="æ—¥"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year" suffix="å¹´"/>
+    <date-part name="month" form="numeric" suffix="月"/>
+    <date-part name="day" suffix="æ—¥"/>
+  </date>
+  <terms>
+    <term name="accessed">アクセス</term>
+    <term name="and">ã¨</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">ä»–</term>
+    <term name="forthcoming">近刊</term>
+    <term name="from">ã‹ã‚‰</term>
+    <term name="ibid">剿޲</term>
+    <term name="in"/>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">日付ãªã—</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">読ã¿è¾¼ã¿</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">「</term>
+    <term name="close-quote">ã€</term>
+    <term name="open-inner-quote">『</term>
+    <term name="close-inner-quote">ã€</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>行</single>
+      <multiple>行</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>ページ</single>
+      <multiple>ページ</multiple>
+    </term>
+    <term name="paragraph">
+      <single>段è½</single>
+      <multiple>段è½</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk</term>
+    <term name="chapter" form="short">chap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">å·</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>p</single>
+      <multiple>p</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>編集者</single>
+      <multiple>編集者</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>翻訳者</single>
+      <multiple>翻訳者</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>編集者</single>
+      <multiple>編集者</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>翻訳者</single>
+      <multiple>翻訳者</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">編集者:</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">翻訳者:</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">1月</term>
+    <term name="month-02">2月</term>
+    <term name="month-03">3月</term>
+    <term name="month-04">4月</term>
+    <term name="month-05">5月</term>
+    <term name="month-06">6月</term>
+    <term name="month-07">7月</term>
+    <term name="month-08">8月</term>
+    <term name="month-09">9月</term>
+    <term name="month-10">10月</term>
+    <term name="month-11">11月</term>
+    <term name="month-12">12月</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">1月</term>
+    <term name="month-02" form="short">2月</term>
+    <term name="month-03" form="short">3月</term>
+    <term name="month-04" form="short">4月</term>
+    <term name="month-05" form="short">5月</term>
+    <term name="month-06" form="short">6月</term>
+    <term name="month-07" form="short">7月</term>
+    <term name="month-08" form="short">8月</term>
+    <term name="month-09" form="short">9月</term>
+    <term name="month-10" form="short">10月</term>
+    <term name="month-11" form="short">11月</term>
+    <term name="month-12" form="short">12月</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-km-KH.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="km-KH">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric" suffix="​"/>
+    <date-part name="month" suffix="​"/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">accessed</term>
+    <term name="and">and</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">from</term>
+    <term name="ibid">ibid</term>
+    <term name="in">in</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">ទីមួយ</term>
+    <term name="long-ordinal-02">ទីពីរ</term>
+    <term name="long-ordinal-03">ទីបី</term>
+    <term name="long-ordinal-04">ទីបួន</term>
+    <term name="long-ordinal-05">ទីប្រាំ</term>
+    <term name="long-ordinal-06">ទីប្រាំមួយ</term>
+    <term name="long-ordinal-07">ទីប្រាំពីរ</term>
+    <term name="long-ordinal-08">ទីប្រាំបី</term>
+    <term name="long-ordinal-09">ទីប្រាំបួន</term>
+    <term name="long-ordinal-10">ទីដប់មួយ</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">នរវិទ្យា</term>
+    <term name="astronomy">ážáž¶ážšáž¶ážœáž·áž‘្យា</term>
+    <term name="biology">ជីវវិទ្យា</term>
+    <term name="botany">រុក្ážážœáž·áž‘្យា</term>
+    <term name="chemistry">គីមីវិទ្យា</term>
+    <term name="engineering">វិស្វកម្ម</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">ភូមិវិទ្យា</term>
+    <term name="geology">ភូគព្ភវិទ្យា</term>
+    <term name="history">ប្រវážáŸ’ážáž·ážœáž·áž‘្យា</term>
+    <term name="humanities">មនុស្សវិទ្យា</term>
+    <term name="linguistics">ភាសាវិទ្យា</term>
+    <term name="literature">អក្សរសាស្ážáŸ’ážš</term>
+    <term name="math">គណិážážœáž·áž‘្យា</term>
+    <term name="medicine">ážœáŸáž‡áŸ’ជសាស្ážáŸ’ážš</term>
+    <term name="philosophy">ទស្សនវិទ្យា</term>
+    <term name="physics">រូបវិទ្យា</term>
+    <term name="psychology">áž…áž·ážáŸ’ážážœáž·áž‘្យា</term>
+    <term name="sociology">សង្គមវិទ្យា</term>
+    <term name="science">វិទ្យាសាស្ážáŸ’ážš</term>
+    <term name="political_science">វិទ្យាសាស្ážáŸ’រនយោបាយ</term>
+    <term name="social_science">សង្គមវិទ្យា</term>
+    <term name="theology">áž‘áŸážœážœáž·áž‘្យា</term>
+    <term name="zoology">សážáŸ’ážážœáž·áž‘្យា</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>សៀវភៅ</single>
+      <multiple>សៀវភៅ</multiple>
+    </term>
+    <term name="chapter">
+      <single>ជំពូក</single>
+      <multiple>ជំពូក</multiple>
+    </term>
+    <term name="column">
+      <single>កាឡោន</single>
+      <multiple>កាឡោន</multiple>
+    </term>
+    <term name="figure">
+      <single>ážáž½áž›áŸáž</single>
+      <multiple>ážáž½áž›áŸáž</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>ចំនួន</single>
+      <multiple>ចំនួន</multiple>
+    </term>
+    <term name="line">
+      <single>បន្ទាážáŸ‹</single>
+      <multiple>បន្ទាážáŸ‹</multiple>
+    </term>
+    <term name="note">
+      <single>កំណážáŸ‹áž…ំណាំ</single>
+      <multiple>កំណážáŸ‹áž…ំណាំ</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>ទំពáŸážš</single>
+      <multiple>ទំពáŸážš</multiple>
+    </term>
+    <term name="paragraph">
+      <single>កážáž¶ážážŽáŸ’ឌ</single>
+      <multiple>កážáž¶ážážŽáŸ’ឌ</multiple>
+    </term>
+    <term name="part">
+      <single>ជំពូក</single>
+      <multiple>ជំពូក</multiple>
+    </term>
+    <term name="section">
+      <single>ផ្នែក</single>
+      <multiple>ផ្នែក</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>វ៉ុល</single>
+      <multiple>វ៉ុល</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk.</term>
+    <term name="chapter" form="short">chap.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">f.</term>
+    <term name="issue" form="short">no.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>pp.</multiple>
+    </term>
+    <term name="paragraph" form="short">para.</term>
+    <term name="part" form="short">pt.</term>
+    <term name="section" form="short">sec.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>vv.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vols.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="editorial-director">
+      <single/>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>translator</single>
+      <multiple>translator</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tran.</single>
+      <multiple>trans.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">edited by</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">translated by</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans.</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">មករា</term>
+    <term name="month-02">កុម្ភៈ</term>
+    <term name="month-03">មីនា</term>
+    <term name="month-04">មáŸážŸáž¶</term>
+    <term name="month-05">ឧសភា</term>
+    <term name="month-06">មិážáž»áž“áž¶</term>
+    <term name="month-07">កក្កដា</term>
+    <term name="month-08">សីហា</term>
+    <term name="month-09">កញ្ញា</term>
+    <term name="month-10">ážáž»áž›áž¶</term>
+    <term name="month-11">វិច្ឆិកា</term>
+    <term name="month-12">ធ្នូ</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan.</term>
+    <term name="month-02" form="short">Feb.</term>
+    <term name="month-03" form="short">Mar.</term>
+    <term name="month-04" form="short">Apr.</term>
+    <term name="month-05" form="short">May</term>
+    <term name="month-06" form="short">Jun.</term>
+    <term name="month-07" form="short">Jul.</term>
+    <term name="month-08" form="short">Aug.</term>
+    <term name="month-09" form="short">Sep.</term>
+    <term name="month-10" form="short">Oct.</term>
+    <term name="month-11" form="short">Nov.</term>
+    <term name="month-12" form="short">Dec.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-ko-KR.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="ko-KR">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="year" suffix="ë…„"/>
+    <date-part name="month" form="numeric" prefix=" " suffix="ì›”"/>
+    <date-part name="day" prefix=" " suffix="ì¼"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="/"/>
+  </date>
+  <terms>
+    <term name="accessed">ì ‘ê·¼ëœ</term>
+    <term name="and">와/과</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">기타</term>
+    <term name="forthcoming">근간</term>
+    <term name="from">(으)로부터</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">ì¼ìž ì—†ìŒ</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>í–‰</single>
+      <multiple>í–‰</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>페ì´ì§€</single>
+      <multiple>페ì´ì§€</multiple>
+    </term>
+    <term name="paragraph">
+      <single>단ë½</single>
+      <multiple>단ë½</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk</term>
+    <term name="chapter" form="short">chap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">호</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>p</single>
+      <multiple>pp</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>편집ìž</single>
+      <multiple>편집ìž</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>번역ìž</single>
+      <multiple>번역ìž</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>편집ìž</single>
+      <multiple>편집ìž</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>번역ìž</single>
+      <multiple>번역ìž</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">편집ìžï¼š</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">번역ìžï¼š</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">1ì›”</term>
+    <term name="month-02">2ì›”</term>
+    <term name="month-03">3ì›”</term>
+    <term name="month-04">4ì›”</term>
+    <term name="month-05">5ì›”</term>
+    <term name="month-06">6ì›”</term>
+    <term name="month-07">7ì›”</term>
+    <term name="month-08">8ì›”</term>
+    <term name="month-09">9ì›”</term>
+    <term name="month-10">10ì›”</term>
+    <term name="month-11">11ì›”</term>
+    <term name="month-12">12ì›”</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">1</term>
+    <term name="month-02" form="short">2</term>
+    <term name="month-03" form="short">3</term>
+    <term name="month-04" form="short">4</term>
+    <term name="month-05" form="short">5</term>
+    <term name="month-06" form="short">6</term>
+    <term name="month-07" form="short">7</term>
+    <term name="month-08" form="short">8</term>
+    <term name="month-09" form="short">9</term>
+    <term name="month-10" form="short">10</term>
+    <term name="month-11" form="short">11</term>
+    <term name="month-12" form="short">12</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-mn-MN.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="mn-MN">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="."/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="."/>
+  </date>
+  <terms>
+    <term name="accessed">accessed</term>
+    <term name="and">and</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">from</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <!-- (Assumed to follow Russian conventions) -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">„</term>
+    <term name="close-inner-quote">“</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>line</single>
+      <multiple>lines</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>page</single>
+      <multiple>pages</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraph</single>
+      <multiple>paragraph</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk</term>
+    <term name="chapter" form="short">chap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">no</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>p</single>
+      <multiple>pp</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>translator</single>
+      <multiple>translators</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed</single>
+      <multiple>eds</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tran</single>
+      <multiple>trans</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">edited by</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">translated by</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">January</term>
+    <term name="month-02">February</term>
+    <term name="month-03">March</term>
+    <term name="month-04">April</term>
+    <term name="month-05">May</term>
+    <term name="month-06">June</term>
+    <term name="month-07">July</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">October</term>
+    <term name="month-11">November</term>
+    <term name="month-12">December</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan</term>
+    <term name="month-02" form="short">Feb</term>
+    <term name="month-03" form="short">Mar</term>
+    <term name="month-04" form="short">Apr</term>
+    <term name="month-05" form="short">May</term>
+    <term name="month-06" form="short">Jun</term>
+    <term name="month-07" form="short">Jul</term>
+    <term name="month-08" form="short">Aug</term>
+    <term name="month-09" form="short">Sep</term>
+    <term name="month-10" form="short">Oct</term>
+    <term name="month-11" form="short">Nov</term>
+    <term name="month-12" form="short">Dec</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-nb-NO.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="nb-NO">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+  </date>
+  <terms>
+    <term name="accessed">Ã¥pnet</term>
+    <term name="and">og</term>
+    <term name="and others">med flere</term>
+    <term name="anonymous">anonym</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">på</term>
+    <term name="by">av</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">ca.</term>
+    <term name="cited">sitert</term>
+    <term name="edition">
+      <single>utgave</single>
+      <multiple>utgaver</multiple>
+    </term>
+    <term name="edition" form="short">utg.</term>
+    <term name="et-al">mfl.</term>
+    <term name="forthcoming">kommende</term>
+    <term name="from">fra</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">i</term>
+    <term name="in press">i trykk</term>
+    <term name="internet">Internett</term>
+    <term name="interview">intervju</term>
+    <term name="letter">brev</term>
+    <term name="no date">ingen dato</term>
+    <term name="no date" form="short">udatert</term>
+    <term name="online">online</term>
+    <term name="presented at">presentert på</term>
+    <term name="reference">
+      <single>referanse</single>
+      <multiple>referanser</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refr.</multiple>
+    </term>
+    <term name="retrieved">hentet</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">f.Kr</term>
+    <term name="bc">e.Kr</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">første</term>
+    <term name="long-ordinal-02">andre</term>
+    <term name="long-ordinal-03">tredje</term>
+    <term name="long-ordinal-04">fjerde</term>
+    <term name="long-ordinal-05">femte</term>
+    <term name="long-ordinal-06">sjette</term>
+    <term name="long-ordinal-07">sjuende</term>
+    <term name="long-ordinal-08">Ã¥ttende</term>
+    <term name="long-ordinal-09">niende</term>
+    <term name="long-ordinal-10">tiende</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologi</term>
+    <term name="astronomy">astronomi</term>
+    <term name="biology">biologi</term>
+    <term name="botany">botanikk</term>
+    <term name="chemistry">kjemi</term>
+    <term name="engineering">ingeniørvitenskap</term>
+    <term name="generic-base">generell</term>
+    <term name="geography">geografi</term>
+    <term name="geology">geologi</term>
+    <term name="history">historie</term>
+    <term name="humanities">humanistiske fag</term>
+    <term name="linguistics">lingvistikk</term>
+    <term name="literature">litteratur</term>
+    <term name="math">mattematikk</term>
+    <term name="medicine">medisin</term>
+    <term name="philosophy">filosofi</term>
+    <term name="physics">fysikk</term>
+    <term name="psychology">fysiologi</term>
+    <term name="sociology">sosiologi</term>
+    <term name="science">naturvitenskap</term>
+    <term name="political_science">statsvitenskap</term>
+    <term name="social_science">samfunnsvitenskap</term>
+    <term name="theology">teologi</term>
+    <term name="zoology">zoologi</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>bok</single>
+      <multiple>bøker</multiple>
+    </term>
+    <term name="chapter">
+      <single>kapittel</single>
+      <multiple>kapitler</multiple>
+    </term>
+    <term name="column">
+      <single>kolonne</single>
+      <multiple>kolonner</multiple>
+    </term>
+    <term name="figure">
+      <single>figur</single>
+      <multiple>figurer</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folioer</multiple>
+    </term>
+    <term name="issue">
+      <single>nummer</single>
+      <multiple>numre</multiple>
+    </term>
+    <term name="line">
+      <single>linje</single>
+      <multiple>linjer</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>noter</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opus</multiple>
+    </term>
+    <term name="page">
+      <single>side</single>
+      <multiple>sider</multiple>
+    </term>
+    <term name="paragraph">
+      <single>avsnitt</single>
+      <multiple>avsnitt</multiple>
+    </term>
+    <term name="part">
+      <single>del</single>
+      <multiple>deler</multiple>
+    </term>
+    <term name="section">
+      <single>paragraf</single>
+      <multiple>paragrafer</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>vers</single>
+      <multiple>vers</multiple>
+    </term>
+    <term name="volume">
+      <single>bind</single>
+      <multiple>bind</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">b.</term>
+    <term name="chapter" form="short">kap.</term>
+    <term name="column" form="short">kol.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">fol.</term>
+    <term name="issue" form="short">nr.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>s.</single>
+      <multiple>s.</multiple>
+    </term>
+    <term name="paragraph" form="short">avsn.</term>
+    <term name="part" form="short">d.</term>
+    <term name="section" form="short">pargr.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>v.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>bd.</single>
+      <multiple>bd.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>redaktør</single>
+      <multiple>redaktører</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>redaktør</single>
+      <multiple>redaktører</multiple>
+    </term>
+    <term name="translator">
+      <single>oversetter</single>
+      <multiple>oversettere</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>redaktør &amp; oversetter</single>
+      <multiple>redaktører &amp; oversettere</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>overs.</single>
+      <multiple>overs.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>red. &amp; overs.</single>
+      <multiple>red. &amp; overs.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">redigert av</term>
+    <term name="editorial-director" form="verb">redigert av</term>
+    <term name="translator" form="verb">oversatt av</term>
+    <term name="editortranslator" form="verb">redigert &amp; oversatt av</term>
+    <term name="recipient" form="verb">mottatt av</term>
+    <term name="interviewer" form="verb">intervjuet av</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">av</term>
+    <term name="editor" form="verb-short">red.</term>
+    <term name="editorial-director" form="verb-short">red.</term>
+    <term name="translator" form="verb-short">overs.</term>
+    <term name="editortranslator" form="verb-short">red. &amp; overs. av</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">januar</term>
+    <term name="month-02">februar</term>
+    <term name="month-03">mars</term>
+    <term name="month-04">april</term>
+    <term name="month-05">mai</term>
+    <term name="month-06">juni</term>
+    <term name="month-07">juli</term>
+    <term name="month-08">august</term>
+    <term name="month-09">september</term>
+    <term name="month-10">oktober</term>
+    <term name="month-11">november</term>
+    <term name="month-12">desember</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jan.</term>
+    <term name="month-02" form="short">feb.</term>
+    <term name="month-03" form="short">mar.</term>
+    <term name="month-04" form="short">apr.</term>
+    <term name="month-05" form="short">mai</term>
+    <term name="month-06" form="short">jun.</term>
+    <term name="month-07" form="short">jul.</term>
+    <term name="month-08" form="short">aug.</term>
+    <term name="month-09" form="short">sep.</term>
+    <term name="month-10" form="short">okt.</term>
+    <term name="month-11" form="short">nov.</term>
+    <term name="month-12" form="short">des.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">vår</term>
+    <term name="season-02">sommer</term>
+    <term name="season-03">høst</term>
+    <term name="season-04">vinter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-nl-NL.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="nl-NL">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" suffix="-" range-delimiter="/"/>
+    <date-part name="month" form="numeric" suffix="-" range-delimiter="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">bezocht</term>
+    <term name="and">en</term>
+    <term name="and others">en anderen</term>
+    <term name="anonymous">anoniem</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">bij</term>
+    <term name="by">door</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">geciteerd</term>
+    <term name="edition">
+      <single>editie</single>
+      <multiple>edities</multiple>
+    </term>
+    <term name="edition" form="short">ed.</term>
+    <term name="et-al">e.a.</term>
+    <term name="forthcoming">in voorbereiding</term>
+    <term name="from">van</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in druk</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">brief</term>
+    <term name="no date">zonder datum</term>
+    <term name="no date" form="short">z.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">gepresenteerd bij</term>
+    <term name="reference">
+      <single>referentie</single>
+      <multiple>referenties</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">verkregen</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">e</term>
+    <term name="ordinal-02">e</term>
+    <term name="ordinal-03">e</term>
+    <term name="ordinal-04">e</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">eerste</term>
+    <term name="long-ordinal-02">tweede</term>
+    <term name="long-ordinal-03">derde</term>
+    <term name="long-ordinal-04">vierde</term>
+    <term name="long-ordinal-05">vijfde</term>
+    <term name="long-ordinal-06">zesde</term>
+    <term name="long-ordinal-07">zevende</term>
+    <term name="long-ordinal-08">achtste</term>
+    <term name="long-ordinal-09">negende</term>
+    <term name="long-ordinal-10">tiende</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropologie</term>
+    <term name="astronomy">astronomie</term>
+    <term name="biology">biologie</term>
+    <term name="botany">botanie</term>
+    <term name="chemistry">scheikunde</term>
+    <term name="engineering">techniek</term>
+    <term name="generic-base">generiek</term>
+    <term name="geography">geografie</term>
+    <term name="geology">geologie</term>
+    <term name="history">geschiedenis</term>
+    <term name="humanities">geesteswetenschappen</term>
+    <term name="linguistics">taalkunde</term>
+    <term name="literature">literatuur</term>
+    <term name="math">wiskunde</term>
+    <term name="medicine">medicijnen</term>
+    <term name="philosophy">filosofie</term>
+    <term name="physics">natuurkunde</term>
+    <term name="psychology">psychologie</term>
+    <term name="sociology">sociologie</term>
+    <term name="science">wetenschap</term>
+    <term name="political_science">politieke wetenschappen</term>
+    <term name="social_science">sociale wetenschappen</term>
+    <term name="theology">theologie</term>
+    <term name="zoology">zoologie</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>boek</single>
+      <multiple>boeken</multiple>
+    </term>
+    <term name="chapter">
+      <single>hoofdstuk</single>
+      <multiple>hoofdstukken</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figuur</single>
+      <multiple>figuren</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folio's</multiple>
+    </term>
+    <term name="issue">
+      <single>nummer</single>
+      <multiple>nummers</multiple>
+    </term>
+    <term name="line">
+      <single>regel</single>
+      <multiple>regels</multiple>
+    </term>
+    <term name="note">
+      <single>aantekening</single>
+      <multiple>aantekeningen</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>pagina</single>
+      <multiple>pagina's</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraaf</single>
+      <multiple>paragrafen</multiple>
+    </term>
+    <term name="part">
+      <single>deel</single>
+      <multiple>delen</multiple>
+    </term>
+    <term name="section">
+      <single>sectie</single>
+      <multiple>secties</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>vers</single>
+      <multiple>versen</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk.</term>
+    <term name="chapter" form="short">hfdst.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">f.</term>
+    <term name="issue" form="short">nr.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>pp.</multiple>
+    </term>
+    <term name="paragraph" form="short">par.</term>
+    <term name="part" form="short">deel</term>
+    <term name="section" form="short">sec.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>vv.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vols.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>redacteur</single>
+      <multiple>redacteuren</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>redacteur</single>
+      <multiple>redacteuren</multiple>
+    </term>
+    <term name="translator">
+      <single>vertaler</single>
+      <multiple>vertalers</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>redacteur &amp; vertaler</single>
+      <multiple>redacteuren &amp; vertalers</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>vert.</single>
+      <multiple>vert.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>red. &amp; vert.</single>
+      <multiple>red. &amp; vert.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">bewerkt door</term>
+    <term name="editorial-director" form="verb">bewerkt door</term>
+    <term name="translator" form="verb">vertaald door</term>
+    <term name="editortranslator" form="verb">bewerkt &amp; vertaald door</term>
+    <term name="recipient" form="verb">ontvangen door</term>
+    <term name="interviewer" form="verb">geïnterviewd door</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">door</term>
+    <term name="editor" form="verb-short">bewerkt door</term>
+    <term name="editorial-director" form="verb-short">bewerkt door</term>
+    <term name="translator" form="verb-short">vertaald door</term>
+    <term name="editortranslator" form="verb-short">bewerkt &amp; vertaald door</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">januari</term>
+    <term name="month-02">februari</term>
+    <term name="month-03">maart</term>
+    <term name="month-04">april</term>
+    <term name="month-05">mei</term>
+    <term name="month-06">juni</term>
+    <term name="month-07">juli</term>
+    <term name="month-08">augustus</term>
+    <term name="month-09">september</term>
+    <term name="month-10">oktober</term>
+    <term name="month-11">november</term>
+    <term name="month-12">december</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jan.</term>
+    <term name="month-02" form="short">feb.</term>
+    <term name="month-03" form="short">mrt.</term>
+    <term name="month-04" form="short">apr.</term>
+    <term name="month-05" form="short">mei</term>
+    <term name="month-06" form="short">jun.</term>
+    <term name="month-07" form="short">jul.</term>
+    <term name="month-08" form="short">aug.</term>
+    <term name="month-09" form="short">sep.</term>
+    <term name="month-10" form="short">okt.</term>
+    <term name="month-11" form="short">nov.</term>
+    <term name="month-12" form="short">dec.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">lente</term>
+    <term name="season-02">zomer</term>
+    <term name="season-03">herst</term>
+    <term name="season-04">winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-nn-NO.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="nn-NO">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+  </date>
+  <terms>
+    <term name="accessed">vitja</term>
+    <term name="and">og</term>
+    <term name="and others">med fleire</term>
+    <term name="anonymous">anonym</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">på</term>
+    <term name="by">av</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">ca.</term>
+    <term name="cited">sitert</term>
+    <term name="edition">
+      <single>utgåve</single>
+      <multiple>utgåver</multiple>
+    </term>
+    <term name="edition" form="short">utg.</term>
+    <term name="et-al">mfl.</term>
+    <term name="forthcoming">kommande</term>
+    <term name="from">frå</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">i</term>
+    <term name="in press">i trykk</term>
+    <term name="internet">Internett</term>
+    <term name="interview">intervju</term>
+    <term name="letter">brev</term>
+    <term name="no date">ingen dato</term>
+    <term name="no date" form="short">udatert</term>
+    <term name="online">online</term>
+    <term name="presented at">presentert på</term>
+    <term name="reference">
+      <single>referanse</single>
+      <multiple>referansar</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refr.</multiple>
+    </term>
+    <term name="retrieved">henta</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">f.Kr</term>
+    <term name="bc">e.Kr</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">første</term>
+    <term name="long-ordinal-02">andre</term>
+    <term name="long-ordinal-03">tredje</term>
+    <term name="long-ordinal-04">fjerde</term>
+    <term name="long-ordinal-05">femte</term>
+    <term name="long-ordinal-06">sjette</term>
+    <term name="long-ordinal-07">sjuande</term>
+    <term name="long-ordinal-08">Ã¥ttande</term>
+    <term name="long-ordinal-09">niande</term>
+    <term name="long-ordinal-10">tiande</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologi</term>
+    <term name="astronomy">astronomi</term>
+    <term name="biology">biologi</term>
+    <term name="botany">botanikk</term>
+    <term name="chemistry">kjemi</term>
+    <term name="engineering">ingeniørvitskap</term>
+    <term name="generic-base">generell</term>
+    <term name="geography">geografi</term>
+    <term name="geology">geologi</term>
+    <term name="history">historie</term>
+    <term name="humanities">humanistiske fag</term>
+    <term name="linguistics">lingvistikk</term>
+    <term name="literature">litteratur</term>
+    <term name="math">mattematikk</term>
+    <term name="medicine">medisin</term>
+    <term name="philosophy">filosofi</term>
+    <term name="physics">fysikk</term>
+    <term name="psychology">fysiologi</term>
+    <term name="sociology">sosiologi</term>
+    <term name="science">naturvitskap</term>
+    <term name="political_science">statsvitskap</term>
+    <term name="social_science">samfunnsvitskap</term>
+    <term name="theology">teologi</term>
+    <term name="zoology">zoologi</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>bok</single>
+      <multiple>bøker</multiple>
+    </term>
+    <term name="chapter">
+      <single>kapittel</single>
+      <multiple>kapittel</multiple>
+    </term>
+    <term name="column">
+      <single>kolonne</single>
+      <multiple>kolonner</multiple>
+    </term>
+    <term name="figure">
+      <single>figur</single>
+      <multiple>figurar</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folioar</multiple>
+    </term>
+    <term name="issue">
+      <single>nummer</single>
+      <multiple>nummer</multiple>
+    </term>
+    <term name="line">
+      <single>linje</single>
+      <multiple>linjer</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notar</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opus</multiple>
+    </term>
+    <term name="page">
+      <single>side</single>
+      <multiple>sider</multiple>
+    </term>
+    <term name="paragraph">
+      <single>avsnitt</single>
+      <multiple>avsnitt</multiple>
+    </term>
+    <term name="part">
+      <single>del</single>
+      <multiple>deler</multiple>
+    </term>
+    <term name="section">
+      <single>paragraf</single>
+      <multiple>paragrafar</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>vers</single>
+      <multiple>vers</multiple>
+    </term>
+    <term name="volume">
+      <single>bind</single>
+      <multiple>bind</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">b.</term>
+    <term name="chapter" form="short">kap.</term>
+    <term name="column" form="short">kol.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">fol.</term>
+    <term name="issue" form="short">nr.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>s.</single>
+      <multiple>s.</multiple>
+    </term>
+    <term name="paragraph" form="short">avsn.</term>
+    <term name="part" form="short">d.</term>
+    <term name="section" form="short">par.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>v.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>bd.</single>
+      <multiple>bd.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>redaktør</single>
+      <multiple>redaktørar</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>redaktør</single>
+      <multiple>redaktørar</multiple>
+    </term>
+    <term name="translator">
+      <single>omsetjar</single>
+      <multiple>omsetjarar</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>redaktør &amp; omsetjar</single>
+      <multiple>redaktørar &amp; omsetjarar</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>oms.</single>
+      <multiple>oms.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>red. &amp; oms.</single>
+      <multiple>red. &amp; oms.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">redigert av</term>
+    <term name="editorial-director" form="verb">redigert av</term>
+    <term name="translator" form="verb">omsett av</term>
+    <term name="editortranslator" form="verb">redigert &amp; omsett av</term>
+    <term name="recipient" form="verb">motteke av</term>
+    <term name="interviewer" form="verb">intervjua av</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">av</term>
+    <term name="editor" form="verb-short">red.</term>
+    <term name="editorial-director" form="verb-short">red.</term>
+    <term name="translator" form="verb-short">oms.</term>
+    <term name="editortranslator" form="verb-short">red. &amp; oms. av</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">januar</term>
+    <term name="month-02">februar</term>
+    <term name="month-03">mars</term>
+    <term name="month-04">april</term>
+    <term name="month-05">mai</term>
+    <term name="month-06">juni</term>
+    <term name="month-07">juli</term>
+    <term name="month-08">august</term>
+    <term name="month-09">september</term>
+    <term name="month-10">oktober</term>
+    <term name="month-11">november</term>
+    <term name="month-12">desember</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jan.</term>
+    <term name="month-02" form="short">feb.</term>
+    <term name="month-03" form="short">mar.</term>
+    <term name="month-04" form="short">apr.</term>
+    <term name="month-05" form="short">mai</term>
+    <term name="month-06" form="short">jun.</term>
+    <term name="month-07" form="short">jul.</term>
+    <term name="month-08" form="short">aug.</term>
+    <term name="month-09" form="short">sep.</term>
+    <term name="month-10" form="short">okt.</term>
+    <term name="month-11" form="short">nov.</term>
+    <term name="month-12" form="short">des.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">vår</term>
+    <term name="season-02">sommar</term>
+    <term name="season-03">haust</term>
+    <term name="season-04">vinter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-pl-PL.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="pl-PL">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">udostępniono</term>
+    <term name="and">i</term>
+    <term name="and others">i inni</term>
+    <term name="anonymous">anonim</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">na</term>
+    <term name="by">przez</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">ca</term>
+    <term name="cited">cytowane</term>
+    <term name="edition">
+      <single>wydanie</single>
+      <multiple>wydania</multiple>
+    </term>
+    <term name="edition" form="short">wyd.</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">w przygotowaniu</term>
+    <term name="from">z</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">w</term>
+    <term name="in press">w druku</term>
+    <term name="internet">internet</term>
+    <term name="interview">wywiad</term>
+    <term name="letter">list</term>
+    <term name="no date">brak daty</term>
+    <term name="no date" form="short">b.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">zaprezentowano na</term>
+    <term name="reference">
+      <single>referencja</single>
+      <multiple>referencje</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>ref.</multiple>
+    </term>
+    <term name="retrieved">pobrano</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">n.e.</term>
+    <term name="bc">p.n.e.</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">«</term>
+    <term name="close-inner-quote">»</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">.</term>
+    <term name="ordinal-02">.</term>
+    <term name="ordinal-03">.</term>
+    <term name="ordinal-04">.</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">pierwszy</term>
+    <term name="long-ordinal-02">drugi</term>
+    <term name="long-ordinal-03">trzeci</term>
+    <term name="long-ordinal-04">czwarty</term>
+    <term name="long-ordinal-05">piÄ…ty</term>
+    <term name="long-ordinal-06">szósty</term>
+    <term name="long-ordinal-07">siódmy</term>
+    <term name="long-ordinal-08">ósmy</term>
+    <term name="long-ordinal-09">dziewiÄ…ty</term>
+    <term name="long-ordinal-10">dziesiÄ…ty</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologia</term>
+    <term name="astronomy">astronomia</term>
+    <term name="biology">biologia</term>
+    <term name="botany">botanika</term>
+    <term name="chemistry">chemia</term>
+    <term name="engineering">inżynieria</term>
+    <term name="generic-base">ogólny</term>
+    <term name="geography">geografia</term>
+    <term name="geology">geologia</term>
+    <term name="history">historia</term>
+    <term name="humanities">humanistyka</term>
+    <term name="linguistics">lingwistyka</term>
+    <term name="literature">literatura</term>
+    <term name="math">matematyka</term>
+    <term name="medicine">medycyna</term>
+    <term name="philosophy">filozofia</term>
+    <term name="physics">fizyka</term>
+    <term name="psychology">psychologia</term>
+    <term name="sociology">socjologia</term>
+    <term name="science">nauki ścisłe</term>
+    <term name="political_science">nauki polityczne</term>
+    <term name="social_science">nauki społeczne</term>
+    <term name="theology">teologia</term>
+    <term name="zoology">zoologia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>książka</single>
+      <multiple>książki</multiple>
+    </term>
+    <term name="chapter">
+      <single>rozdział</single>
+      <multiple>rozdziały</multiple>
+    </term>
+    <term name="column">
+      <single>kolumna</single>
+      <multiple>kolumny</multiple>
+    </term>
+    <term name="figure">
+      <single>rycina</single>
+      <multiple>ryciny</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folio</multiple>
+    </term>
+    <term name="issue">
+      <single>numer</single>
+      <multiple>numery</multiple>
+    </term>
+    <term name="line">
+      <single>wers</single>
+      <multiple>wersy</multiple>
+    </term>
+    <term name="note">
+      <single>notatka</single>
+      <multiple>notatki</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>strona</single>
+      <multiple>strony</multiple>
+    </term>
+    <term name="paragraph">
+      <single>akapit</single>
+      <multiple>akapity</multiple>
+    </term>
+    <term name="part">
+      <single>część</single>
+      <multiple>części</multiple>
+    </term>
+    <term name="section">
+      <single>sekcja</single>
+      <multiple>sekcje</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>wers</single>
+      <multiple>wersy</multiple>
+    </term>
+    <term name="volume">
+      <single>tom</single>
+      <multiple>tomy</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">książka</term>
+    <term name="chapter" form="short">rozdz.</term>
+    <term name="column" form="short">kol.</term>
+    <term name="figure" form="short">ryc.</term>
+    <term name="folio" form="short">fol.</term>
+    <term name="issue" form="short">nr</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>s.</single>
+      <multiple>ss.</multiple>
+    </term>
+    <term name="paragraph" form="short">akap.</term>
+    <term name="part" form="short">cz.</term>
+    <term name="section" form="short">sekc.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>w.</single>
+      <multiple>w.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>t.</single>
+      <multiple>t.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>redaktor</single>
+      <multiple>redaktorzy</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>edytor</single>
+      <multiple>edytorzy</multiple>
+    </term>
+    <term name="translator">
+      <single>tłumacz</single>
+      <multiple>tłumacze</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>redaktor &amp; tłumacz</single>
+      <multiple>redaktorzy &amp; tłumacze</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>red.</single>
+      <multiple>red.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tłum.</single>
+      <multiple>tłum.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>red. &amp; tłum.</single>
+      <multiple>red. &amp; tłum.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">zredagowane przez</term>
+    <term name="editorial-director" form="verb">zredagowane przez</term>
+    <term name="translator" form="verb">przetłumaczone przez</term>
+    <term name="editortranslator" form="verb">zredagowane &amp; przetłumaczone przez</term>
+    <term name="recipient" form="verb">dla</term>
+    <term name="interviewer" form="verb">przeprowadzony przez</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">przez</term>
+    <term name="editor" form="verb-short">red.</term>
+    <term name="editorial-director" form="verb-short">red.</term>
+    <term name="translator" form="verb-short">tłum.</term>
+    <term name="editortranslator" form="verb-short">red. &amp; tłum.</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">styczeń</term>
+    <term name="month-02">luty</term>
+    <term name="month-03">marzec</term>
+    <term name="month-04">kwiecień</term>
+    <term name="month-05">maj</term>
+    <term name="month-06">czerwiec</term>
+    <term name="month-07">lipiec</term>
+    <term name="month-08">sierpień</term>
+    <term name="month-09">wrzesień</term>
+    <term name="month-10">październik</term>
+    <term name="month-11">listopad</term>
+    <term name="month-12">grudzień</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">sty.</term>
+    <term name="month-02" form="short">luty</term>
+    <term name="month-03" form="short">mar.</term>
+    <term name="month-04" form="short">kwi.</term>
+    <term name="month-05" form="short">maj</term>
+    <term name="month-06" form="short">cze.</term>
+    <term name="month-07" form="short">lip.</term>
+    <term name="month-08" form="short">sie.</term>
+    <term name="month-09" form="short">wrz.</term>
+    <term name="month-10" form="short">paź.</term>
+    <term name="month-11" form="short">lis.</term>
+    <term name="month-12" form="short">grudz.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">wiosna</term>
+    <term name="season-02">lato</term>
+    <term name="season-03">jesień</term>
+    <term name="season-04">zima</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-pt-BR.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="pt-BR">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" de "/>
+    <date-part name="month" suffix=" de "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">acessado</term>
+    <term name="and">e</term>
+    <term name="and others">e outros</term>
+    <term name="anonymous">anônimo</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">em</term>
+    <term name="by">por</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">citado</term>
+    <term name="edition">
+      <single>edição</single>
+      <multiple>edições</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">a ser publicado</term>
+    <term name="from">de</term>
+    <term name="ibid">ibidem</term>
+    <term name="in">in</term>
+    <term name="in press">no prelo</term>
+    <term name="internet">internet</term>
+    <term name="interview">entrevista</term>
+    <term name="letter">carta</term>
+    <term name="no date">sem data</term>
+    <term name="no date" form="short">[s.d.]</term>
+    <term name="online">online</term>
+    <term name="presented at">apresentado em</term>
+    <term name="reference">
+      <single>referência</single>
+      <multiple>referências</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">recuperado</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">º</term>
+    <term name="ordinal-02">º</term>
+    <term name="ordinal-03">º</term>
+    <term name="ordinal-04">º</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">primeiro</term>
+    <term name="long-ordinal-02">segundo</term>
+    <term name="long-ordinal-03">terceiro</term>
+    <term name="long-ordinal-04">quarto</term>
+    <term name="long-ordinal-05">quinto</term>
+    <term name="long-ordinal-06">sexto</term>
+    <term name="long-ordinal-07">sétimo</term>
+    <term name="long-ordinal-08">oitavo</term>
+    <term name="long-ordinal-09">nono</term>
+    <term name="long-ordinal-10">décimo</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologia</term>
+    <term name="astronomy">astronomia</term>
+    <term name="biology">biologia</term>
+    <term name="botany">botânica</term>
+    <term name="chemistry">química</term>
+    <term name="engineering">engenharia</term>
+    <term name="generic-base">base genérica</term>
+    <term name="geography">geografia</term>
+    <term name="geology">geologia</term>
+    <term name="history">história</term>
+    <term name="humanities">humanidades</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literatura</term>
+    <term name="math">matemática</term>
+    <term name="medicine">medicina</term>
+    <term name="philosophy">philosofia</term>
+    <term name="physics">física</term>
+    <term name="psychology">psicologia</term>
+    <term name="sociology">sociologia</term>
+    <term name="science">ciências</term>
+    <term name="political_science">ciências políticas</term>
+    <term name="social_science">ciências sociais</term>
+    <term name="theology">teologia</term>
+    <term name="zoology">zoologia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>livro</single>
+      <multiple>livros</multiple>
+    </term>
+    <term name="chapter">
+      <single>capítulo</single>
+      <multiple>capítulos</multiple>
+    </term>
+    <term name="column">
+      <single>coluna</single>
+      <multiple>colunas</multiple>
+    </term>
+    <term name="figure">
+      <single>figura</single>
+      <multiple>figuras</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>número</single>
+      <multiple>números</multiple>
+    </term>
+    <term name="line">
+      <single>linha</single>
+      <multiple>linhas</multiple>
+    </term>
+    <term name="note">
+      <single>nota</single>
+      <multiple>notas</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>página</single>
+      <multiple>páginas</multiple>
+    </term>
+    <term name="paragraph">
+      <single>parágrafo</single>
+      <multiple>parágrafos</multiple>
+    </term>
+    <term name="part">
+      <single>parte</single>
+      <multiple>partes</multiple>
+    </term>
+    <term name="section">
+      <single>seção</single>
+      <multiple>seções</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verso</single>
+      <multiple>versos</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">liv.</term>
+    <term name="chapter" form="short">cap.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">f.</term>
+    <term name="issue" form="short">nº</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>p.</multiple>
+    </term>
+    <term name="paragraph" form="short">parag.</term>
+    <term name="part" form="short">pt.</term>
+    <term name="section" form="short">seç.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>vv.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vols.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>organizador</single>
+      <multiple>organizadores</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>tradutor</single>
+      <multiple>tradutores</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor e tradutor</single>
+      <multiple>editores e tradutores</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>org.</single>
+      <multiple>orgs.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>trad.</single>
+      <multiple>trads.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. e trad.</single>
+      <multiple>eds. e trads.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">organizado por</term>
+    <term name="editorial-director" form="verb">editado por</term>
+    <term name="translator" form="verb">traduzido por</term>
+    <term name="editortranslator" form="verb">editado &amp; traduzido por</term>
+    <term name="recipient" form="verb">para</term>
+    <term name="interviewer" form="verb">entrevista de</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">por</term>
+    <term name="editor" form="verb-short">org.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trad.</term>
+    <term name="editortranslator" form="verb-short">ed. e trad. por</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">janeiro</term>
+    <term name="month-02">fevereiro</term>
+    <term name="month-03">março</term>
+    <term name="month-04">abril</term>
+    <term name="month-05">maio</term>
+    <term name="month-06">junho</term>
+    <term name="month-07">julho</term>
+    <term name="month-08">agosto</term>
+    <term name="month-09">setembro</term>
+    <term name="month-10">outubro</term>
+    <term name="month-11">novembro</term>
+    <term name="month-12">dezembro</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jan.</term>
+    <term name="month-02" form="short">fev.</term>
+    <term name="month-03" form="short">mar.</term>
+    <term name="month-04" form="short">abr.</term>
+    <term name="month-05" form="short">maio</term>
+    <term name="month-06" form="short">jun.</term>
+    <term name="month-07" form="short">jul.</term>
+    <term name="month-08" form="short">ago.</term>
+    <term name="month-09" form="short">set.</term>
+    <term name="month-10" form="short">out.</term>
+    <term name="month-11" form="short">nov.</term>
+    <term name="month-12" form="short">dez.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Primavera</term>
+    <term name="season-02">Verão</term>
+    <term name="season-03">Outono</term>
+    <term name="season-04">Inverno</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-pt-PT.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="pt-PT">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" de "/>
+    <date-part name="month" suffix=" de "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">acedido</term>
+    <term name="and">e</term>
+    <term name="and others">e outros</term>
+    <term name="anonymous">anónimo</term>
+    <term name="anonymous" form="short">anón</term>
+    <term name="at">em</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">citado</term>
+    <term name="edition">
+      <single>edição</single>
+      <multiple>edições</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">a publicar</term>
+    <term name="from">de</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">em</term>
+    <term name="in press">no prelo</term>
+    <term name="internet">internet</term>
+    <term name="interview">entrevista</term>
+    <term name="letter">carta</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">sem data</term>
+    <term name="online">em linha</term>
+    <term name="presented at">apresentado na</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">obtido</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">“</term>
+    <term name="close-inner-quote">â€</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologia</term>
+    <term name="astronomy">astronomia</term>
+    <term name="biology">biologia</term>
+    <term name="botany">botânica</term>
+    <term name="chemistry">química</term>
+    <term name="engineering">engenharia</term>
+    <term name="generic-base">base genérica</term>
+    <term name="geography">geografia</term>
+    <term name="geology">geologia</term>
+    <term name="history">história</term>
+    <term name="humanities">humanidades</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literatura</term>
+    <term name="math">matemática</term>
+    <term name="medicine">medicina</term>
+    <term name="philosophy">filosofia</term>
+    <term name="physics">física</term>
+    <term name="psychology">psicologia</term>
+    <term name="sociology">sociologia</term>
+    <term name="science">ciência</term>
+    <term name="political_science">ciência política</term>
+    <term name="social_science">ciência social</term>
+    <term name="theology">teologia</term>
+    <term name="zoology">zoologia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>livro</single>
+      <multiple>livros</multiple>
+    </term>
+    <term name="chapter">
+      <single>capítulo</single>
+      <multiple>capítulos</multiple>
+    </term>
+    <term name="column">
+      <single>coluna</single>
+      <multiple>colunas</multiple>
+    </term>
+    <term name="figure">
+      <single>figura</single>
+      <multiple>figuras</multiple>
+    </term>
+    <term name="folio">
+      <single>fólio</single>
+      <multiple>fólios</multiple>
+    </term>
+    <term name="issue">
+      <single>número</single>
+      <multiple>número</multiple>
+    </term>
+    <term name="line">
+      <single>linha</single>
+      <multiple>linhas</multiple>
+    </term>
+    <term name="note">
+      <single>nota</single>
+      <multiple>notas</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>página</single>
+      <multiple>páginas</multiple>
+    </term>
+    <term name="paragraph">
+      <single>parágrafo</single>
+      <multiple>parágrafos</multiple>
+    </term>
+    <term name="part">
+      <single>parte</single>
+      <multiple>partes</multiple>
+    </term>
+    <term name="section">
+      <single>secção</single>
+      <multiple>secções</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>versículo</single>
+      <multiple>versículos</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">liv</term>
+    <term name="chapter" form="short">cap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">n</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>p</single>
+      <multiple>pp</multiple>
+    </term>
+    <term name="paragraph" form="short">par</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editores</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>tradutor</single>
+      <multiple>tradutores</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed</single>
+      <multiple>eds</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>trad</single>
+      <multiple>trads</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">editado por</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">traduzido por</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">para</term>
+    <term name="interviewer" form="verb">entrevistado por</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trad</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Janeiro</term>
+    <term name="month-02">Fevereiro</term>
+    <term name="month-03">Março</term>
+    <term name="month-04">Abril</term>
+    <term name="month-05">Maio</term>
+    <term name="month-06">Junho</term>
+    <term name="month-07">Julho</term>
+    <term name="month-08">Agosto</term>
+    <term name="month-09">Setembro</term>
+    <term name="month-10">Outubro</term>
+    <term name="month-11">Novembro</term>
+    <term name="month-12">Dezembro</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan</term>
+    <term name="month-02" form="short">Fev</term>
+    <term name="month-03" form="short">Mar</term>
+    <term name="month-04" form="short">Abr</term>
+    <term name="month-05" form="short">Mai</term>
+    <term name="month-06" form="short">Jun</term>
+    <term name="month-07" form="short">Jul</term>
+    <term name="month-08" form="short">Ago</term>
+    <term name="month-09" form="short">Set</term>
+    <term name="month-10" form="short">Out</term>
+    <term name="month-11" form="short">Nov</term>
+    <term name="month-12" form="short">Dez</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-ro-RO.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="ro-RO">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" suffix="."/>
+    <date-part name="month" form="numeric" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">data accesării:</term>
+    <term name="and">și</term>
+    <term name="and others">și alții</term>
+    <term name="anonymous">anonim</term>
+    <term name="anonymous" form="short">anon.</term>
+    <term name="at">la</term>
+    <term name="by">de</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">cca.</term>
+    <term name="cited">citat</term>
+    <term name="edition">
+      <single>ediția</single>
+      <multiple>edițiile</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">în curs de apariție</term>
+    <term name="from">din</term>
+    <term name="ibid">ibidem</term>
+    <term name="in">în</term>
+    <term name="in press">sub tipar</term>
+    <term name="internet">internet</term>
+    <term name="interview">interviu</term>
+    <term name="letter">scrisoare</term>
+    <term name="no date">fără dată</term>
+    <term name="no date" form="short">f.a.</term>
+    <term name="online">online</term>
+    <term name="presented at">prezentat la</term>
+    <term name="reference">
+      <single>referință</single>
+      <multiple>referințe</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>ref.</multiple>
+    </term>
+    <term name="retrieved">preluat în</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">d.Hr.</term>
+    <term name="bc">î.Hr.</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">«</term>
+    <term name="close-inner-quote">»</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01"/>
+    <term name="ordinal-02">-lea</term>
+    <term name="ordinal-03">-lea</term>
+    <term name="ordinal-04">-lea</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">primul</term>
+    <term name="long-ordinal-02">al doilea</term>
+    <term name="long-ordinal-03">al treilea</term>
+    <term name="long-ordinal-04">al patrulea</term>
+    <term name="long-ordinal-05">al cincilea</term>
+    <term name="long-ordinal-06">al șaselea</term>
+    <term name="long-ordinal-07">al șaptelea</term>
+    <term name="long-ordinal-08">al optulea</term>
+    <term name="long-ordinal-09">al nouălea</term>
+    <term name="long-ordinal-10">al zecelea</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologie</term>
+    <term name="astronomy">astronomie</term>
+    <term name="biology">biologie</term>
+    <term name="botany">botanică</term>
+    <term name="chemistry">chimie</term>
+    <term name="engineering">inginerie</term>
+    <term name="generic-base">general (de bază)</term>
+    <term name="geography">geografie</term>
+    <term name="geology">geologie</term>
+    <term name="history">istorie</term>
+    <term name="humanities">științe umaniste</term>
+    <term name="linguistics">lingvistică</term>
+    <term name="literature">literatură</term>
+    <term name="math">matematică</term>
+    <term name="medicine">medicină</term>
+    <term name="philosophy">filosofie</term>
+    <term name="physics">fizică</term>
+    <term name="psychology">psihologie</term>
+    <term name="sociology">sociologie</term>
+    <term name="science">știință</term>
+    <term name="political_science">științe politice</term>
+    <term name="social_science">științe sociale</term>
+    <term name="theology">teologie</term>
+    <term name="zoology">zoologie</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>cartea</single>
+      <multiple>cărțile</multiple>
+    </term>
+    <term name="chapter">
+      <single>capitolul</single>
+      <multiple>capitolele</multiple>
+    </term>
+    <term name="column">
+      <single>coloana</single>
+      <multiple>coloanele</multiple>
+    </term>
+    <term name="figure">
+      <single>figura</single>
+      <multiple>figurile</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folio</multiple>
+    </term>
+    <term name="issue">
+      <single>numărul</single>
+      <multiple>numerele</multiple>
+    </term>
+    <term name="line">
+      <single>linia</single>
+      <multiple>liniile</multiple>
+    </term>
+    <term name="note">
+      <single>nota</single>
+      <multiple>notele</multiple>
+    </term>
+    <term name="opus">
+      <single>opusul</single>
+      <multiple>opusurile</multiple>
+    </term>
+    <term name="page">
+      <single>pagina</single>
+      <multiple>paginile</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraful</single>
+      <multiple>paragrafele</multiple>
+    </term>
+    <term name="part">
+      <single>partea</single>
+      <multiple>părțile</multiple>
+    </term>
+    <term name="section">
+      <single>secțiunea</single>
+      <multiple>secțiunile</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>versetul</single>
+      <multiple>versetele</multiple>
+    </term>
+    <term name="volume">
+      <single>volumul</single>
+      <multiple>volumele</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">cart.</term>
+    <term name="chapter" form="short">cap.</term>
+    <term name="column" form="short">col.</term>
+    <term name="figure" form="short">fig.</term>
+    <term name="folio" form="short">fol.</term>
+    <term name="issue" form="short">nr.</term>
+    <term name="opus" form="short">op.</term>
+    <term name="page" form="short">
+      <single>p.</single>
+      <multiple>pp.</multiple>
+    </term>
+    <term name="paragraph" form="short">par.</term>
+    <term name="part" form="short">part.</term>
+    <term name="section" form="short">sec.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v.</single>
+      <multiple>vv.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol.</single>
+      <multiple>vol.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single>autor</single>
+      <multiple>autori</multiple>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editori</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editori</multiple>
+    </term>
+    <term name="translator">
+      <single>traducător</single>
+      <multiple>traducători</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; traducător</single>
+      <multiple>editori &amp; traducători</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single>aut.</single>
+      <multiple>aut.</multiple>
+    </term>
+    <term name="editor" form="short">
+      <single>ed.</single>
+      <multiple>ed.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>ed.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>trad.</single>
+      <multiple>trad.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; trad.</single>
+      <multiple>ed. &amp; trad.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">ediție de</term>
+    <term name="editorial-director" form="verb">ediție de</term>
+    <term name="translator" form="verb">traducere de</term>
+    <term name="editortranslator" form="verb">ediție &amp; traducere de</term>
+    <term name="recipient" form="verb">în</term>
+    <term name="interviewer" form="verb">interviu de</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">de</term>
+    <term name="editor" form="verb-short">ed.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trad.</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trad. de</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">ianuarie</term>
+    <term name="month-02">februarie</term>
+    <term name="month-03">martie</term>
+    <term name="month-04">aprilie</term>
+    <term name="month-05">mai</term>
+    <term name="month-06">iunie</term>
+    <term name="month-07">iulie</term>
+    <term name="month-08">august</term>
+    <term name="month-09">septembrie</term>
+    <term name="month-10">octombrie</term>
+    <term name="month-11">noiembrie</term>
+    <term name="month-12">decembrie</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">ian.</term>
+    <term name="month-02" form="short">feb.</term>
+    <term name="month-03" form="short">mar.</term>
+    <term name="month-04" form="short">apr.</term>
+    <term name="month-05" form="short">mai</term>
+    <term name="month-06" form="short">iun.</term>
+    <term name="month-07" form="short">iul.</term>
+    <term name="month-08" form="short">aug.</term>
+    <term name="month-09" form="short">sep.</term>
+    <term name="month-10" form="short">oct.</term>
+    <term name="month-11" form="short">nov.</term>
+    <term name="month-12" form="short">dec.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">primăvara</term>
+    <term name="season-02">vara</term>
+    <term name="season-03">toamna</term>
+    <term name="season-04">iarna</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-ru-RU.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="ru-RU">
+  <!-- Translation by Alexei Kouprianov alexei.kouprianov@gmail.com -->
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year" suffix=" г."/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">проÑмотрено</term>
+    <term name="and">и</term>
+    <term name="and others">и др.</term>
+    <term name="anonymous">аноним</term>
+    <term name="anonymous" form="short">анон.</term>
+    <term name="at">на</term>
+    <term name="by"/>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">ca.</term>
+    <term name="cited">цитируетÑÑ Ð¿Ð¾</term>
+    <term name="cited" form="short">цит. по</term>
+    <term name="edition">
+      <single>издание</single>
+      <multiple>изданиÑ</multiple>
+    </term>
+    <term name="edition" form="short">изд.</term>
+    <term name="et-al">и др.</term>
+    <term name="forthcoming">ожидаетÑÑ</term>
+    <term name="from">от</term>
+    <term name="ibid">там же</term>
+    <term name="in">в</term>
+    <term name="in press">в печати</term>
+    <term name="internet">Интернет</term>
+    <term name="interview">интервью</term>
+    <term name="letter">пиÑьмо</term>
+    <term name="no date">без даты</term>
+    <term name="no date" form="short">б. д.</term>
+    <term name="online">online</term>
+    <term name="presented at">предÑтавлено на</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">извлечено</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">н. Ñ.</term>
+    <term name="bc">до н. Ñ.</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">„</term>
+    <term name="close-inner-quote">“</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">й</term>
+    <term name="ordinal-02">й</term>
+    <term name="ordinal-03">й</term>
+    <term name="ordinal-04">й</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">первый</term>
+    <term name="long-ordinal-02">второй</term>
+    <term name="long-ordinal-03">третий</term>
+    <term name="long-ordinal-04">четвертый</term>
+    <term name="long-ordinal-05">пÑтый</term>
+    <term name="long-ordinal-06">шеÑтой</term>
+    <term name="long-ordinal-07">Ñедьмой</term>
+    <term name="long-ordinal-08">воÑьмой</term>
+    <term name="long-ordinal-09">девÑтый</term>
+    <term name="long-ordinal-10">деÑÑтый</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">антропологиÑ</term>
+    <term name="astronomy">аÑтрономиÑ</term>
+    <term name="biology">биологиÑ</term>
+    <term name="botany">ботаника</term>
+    <term name="chemistry">химиÑ</term>
+    <term name="engineering">инженерное дело</term>
+    <term name="generic-base">общий</term>
+    <term name="geography">географиÑ</term>
+    <term name="geology">геологиÑ</term>
+    <term name="history">иÑториÑ</term>
+    <term name="humanities">гуманитарные науки</term>
+    <term name="linguistics">лингвиÑтика</term>
+    <term name="literature">литературоведение</term>
+    <term name="math">математика</term>
+    <term name="medicine">медицина</term>
+    <term name="philosophy">филоÑофиÑ</term>
+    <term name="physics">физика</term>
+    <term name="psychology">пÑихологиÑ</term>
+    <term name="sociology">ÑоциологиÑ</term>
+    <term name="science">еÑтеÑтвенные науки</term>
+    <term name="political_science">политичеÑкие науки</term>
+    <term name="social_science">Ñоциальные науки</term>
+    <term name="theology">теологиÑ</term>
+    <term name="zoology">зоологиÑ</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>книга</single>
+      <multiple>книги</multiple>
+    </term>
+    <term name="chapter">
+      <single>глава</single>
+      <multiple>главы</multiple>
+    </term>
+    <term name="column">
+      <single>Ñтолбец</single>
+      <multiple>Ñтолбцы</multiple>
+    </term>
+    <term name="figure">
+      <single>риÑунок</single>
+      <multiple>риÑунки</multiple>
+    </term>
+    <term name="folio">
+      <single>лиÑÑ‚</single>
+      <multiple>лиÑты</multiple>
+    </term>
+    <term name="issue">
+      <single>выпуÑк</single>
+      <multiple>выпуÑки</multiple>
+    </term>
+    <term name="line">
+      <single>Ñтрока</single>
+      <multiple>Ñтроки</multiple>
+    </term>
+    <term name="note">
+      <single>примечание</single>
+      <multiple>примечаниÑ</multiple>
+    </term>
+    <term name="opus">
+      <single>Ñочинение</single>
+      <multiple>ÑочинениÑ</multiple>
+    </term>
+    <term name="page">
+      <single>Ñтраница</single>
+      <multiple>Ñтраницы</multiple>
+    </term>
+    <term name="paragraph">
+      <single>параграф</single>
+      <multiple>параграфы</multiple>
+    </term>
+    <term name="part">
+      <single>чаÑть</single>
+      <multiple>чаÑти</multiple>
+    </term>
+    <term name="section">
+      <single>раздел</single>
+      <multiple>разделы</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>Ñмотри</single>
+      <multiple>Ñмотри</multiple>
+    </term>
+    <term name="verse">
+      <single>Ñтих</single>
+      <multiple>Ñтихи</multiple>
+    </term>
+    <term name="volume">
+      <single>том</single>
+      <multiple>тома</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">кн.</term>
+    <term name="chapter" form="short">гл.</term>
+    <term name="column" form="short">Ñтб.</term>
+    <term name="figure" form="short">риÑ.</term>
+    <term name="folio" form="short">л.</term>
+    <term name="issue" form="short">â„–</term>
+    <term name="opus" form="short">Ñоч.</term>
+    <term name="page" form="short">
+      <single>Ñ.</single>
+      <multiple>Ñ.</multiple>
+    </term>
+    <term name="paragraph" form="short">пара.</term>
+    <term name="part" form="short">ч.</term>
+    <term name="section" form="short">разд.</term>
+    <term name="sub verbo" form="short">
+      <single>Ñм.</single>
+      <multiple>Ñм.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>ÑÑ‚.</single>
+      <multiple>ÑÑ‚.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>Ñ‚.</single>
+      <multiple>тт.</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>редактор</single>
+      <multiple>редакторы</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>ответÑтвенный редактор</single>
+      <multiple>ответÑтвенные редакторы</multiple>
+    </term>
+    <term name="translator">
+      <single>переводчик</single>
+      <multiple>переводчики</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>редактор и переводчик</single>
+      <multiple>редакторы и переводчики</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ред.</single>
+      <multiple>ред.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>отв. ред.</single>
+      <multiple>отв. ред.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>перев.</single>
+      <multiple>перев.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ред. и перев.</single>
+      <multiple>ред. и перев.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">отредактировано</term>
+    <term name="editorial-director" form="verb">отредактировано</term>
+    <term name="translator" form="verb">переведено</term>
+    <term name="editortranslator" form="verb">отредактировано и переведено</term>
+    <term name="recipient" form="verb">к</term>
+    <term name="interviewer" form="verb">интервью</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short"/>
+    <term name="editor" form="verb-short">ред.</term>
+    <term name="editorial-director" form="verb-short">отв. ред.</term>
+    <term name="translator" form="verb-short">перев.</term>
+    <term name="editortranslator" form="verb-short">ред. и перев.</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Ñнварь</term>
+    <term name="month-02">февраль</term>
+    <term name="month-03">март</term>
+    <term name="month-04">апрель</term>
+    <term name="month-05">май</term>
+    <term name="month-06">июнь</term>
+    <term name="month-07">июль</term>
+    <term name="month-08">авгуÑÑ‚</term>
+    <term name="month-09">ÑентÑбрь</term>
+    <term name="month-10">октÑбрь</term>
+    <term name="month-11">ноÑбрь</term>
+    <term name="month-12">декабрь</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Ñнв.</term>
+    <term name="month-02" form="short">фев.</term>
+    <term name="month-03" form="short">мар.</term>
+    <term name="month-04" form="short">апр.</term>
+    <term name="month-05" form="short">май</term>
+    <term name="month-06" form="short">июн.</term>
+    <term name="month-07" form="short">июл.</term>
+    <term name="month-08" form="short">авг.</term>
+    <term name="month-09" form="short">Ñен.</term>
+    <term name="month-10" form="short">окт.</term>
+    <term name="month-11" form="short">ноÑ.</term>
+    <term name="month-12" form="short">дек.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">веÑна</term>
+    <term name="season-02">лета</term>
+    <term name="season-03">оÑень</term>
+    <term name="season-04">зима</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-sk-SK.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="sk-SK">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric-leading-zeros" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" suffix="."/>
+    <date-part name="month" form="numeric" suffix="."/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">cit</term>
+    <term name="and">a</term>
+    <term name="and others">and Äalší</term>
+    <term name="anonymous">anonym</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">v</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cit</term>
+    <term name="edition">
+      <single>vydanie</single>
+      <multiple>vydania</multiple>
+    </term>
+    <term name="edition" form="short">vyd</term>
+    <term name="et-al">et al</term>
+    <term name="forthcoming">nadchádzajúci</term>
+    <term name="from">z</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">v</term>
+    <term name="in press">v tlaÄi</term>
+    <term name="internet">internet</term>
+    <term name="interview">osobná komunikácia</term>
+    <term name="letter">list</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">prezentované na</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">cit</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropológia</term>
+    <term name="astronomy">astronómia</term>
+    <term name="biology">biológia</term>
+    <term name="botany">botanika</term>
+    <term name="chemistry">chémia</term>
+    <term name="engineering">strojárstvo/technika</term>
+    <term name="generic-base">všeobecný základ</term>
+    <term name="geography">geografia</term>
+    <term name="geology">geológia</term>
+    <term name="history">história</term>
+    <term name="humanities">humanitné vedy</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literatúra</term>
+    <term name="math">matematika</term>
+    <term name="medicine">medicína</term>
+    <term name="philosophy">filozofia</term>
+    <term name="physics">fyzika</term>
+    <term name="psychology">psychológia</term>
+    <term name="sociology">sociológia</term>
+    <term name="science">veda</term>
+    <term name="political_science">politické vedy</term>
+    <term name="social_science">sociálne vedy</term>
+    <term name="theology">teológia</term>
+    <term name="zoology">zoológia</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>kniha</single>
+      <multiple>knihy</multiple>
+    </term>
+    <term name="chapter">
+      <single>kapitola</single>
+      <multiple>kapitoly</multiple>
+    </term>
+    <term name="column">
+      <single>stĺpec</single>
+      <multiple>stĺpce</multiple>
+    </term>
+    <term name="figure">
+      <single>obrázok</single>
+      <multiple>obrázky</multiple>
+    </term>
+    <term name="folio">
+      <single>list</single>
+      <multiple>listy</multiple>
+    </term>
+    <term name="issue">
+      <single>Äíslo</single>
+      <multiple>Äísla</multiple>
+    </term>
+    <term name="line">
+      <single>riadok</single>
+      <multiple>riadky</multiple>
+    </term>
+    <term name="note">
+      <single>poznámka</single>
+      <multiple>poznámky</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>strana</single>
+      <multiple>strany</multiple>
+    </term>
+    <term name="paragraph">
+      <single>odstavec</single>
+      <multiple>odstavce</multiple>
+    </term>
+    <term name="part">
+      <single>ÄasÅ¥</single>
+      <multiple>Äasti</multiple>
+    </term>
+    <term name="section">
+      <single>sekcia</single>
+      <multiple>sekcie</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verš</single>
+      <multiple>verše</multiple>
+    </term>
+    <term name="volume">
+      <single>roÄník</single>
+      <multiple>roÄníky</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">k</term>
+    <term name="chapter" form="short">kap</term>
+    <term name="column" form="short">stĺp</term>
+    <term name="figure" form="short">obr</term>
+    <term name="folio" form="short">l</term>
+    <term name="issue" form="short">Ä</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>s</single>
+      <multiple>s</multiple>
+    </term>
+    <term name="paragraph" form="short">par</term>
+    <term name="part" form="short">Ä</term>
+    <term name="section" form="short">sek</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>v</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>roÄ</single>
+      <multiple>roÄ</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editori</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>prekladateľ</single>
+      <multiple>prekladatelia</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed</single>
+      <multiple>ed</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>prek</single>
+      <multiple>prek</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">editoval</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">preložil</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">adresát</term>
+    <term name="interviewer" form="verb">rozhovor urobil</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">prel</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">január</term>
+    <term name="month-02">február</term>
+    <term name="month-03">marec</term>
+    <term name="month-04">apríl</term>
+    <term name="month-05">máj</term>
+    <term name="month-06">jún</term>
+    <term name="month-07">júl</term>
+    <term name="month-08">august</term>
+    <term name="month-09">september</term>
+    <term name="month-10">október</term>
+    <term name="month-11">november</term>
+    <term name="month-12">december</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jan</term>
+    <term name="month-02" form="short">feb</term>
+    <term name="month-03" form="short">mar</term>
+    <term name="month-04" form="short">apr</term>
+    <term name="month-05" form="short">máj</term>
+    <term name="month-06" form="short">jún</term>
+    <term name="month-07" form="short">júl</term>
+    <term name="month-08" form="short">aug</term>
+    <term name="month-09" form="short">sep</term>
+    <term name="month-10" form="short">okt</term>
+    <term name="month-11" form="short">nov</term>
+    <term name="month-12" form="short">dec</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-sl-SI.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="sl-SI">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric-leading-zeros" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year" suffix="."/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+  </date>
+  <terms>
+    <term name="accessed">dostopano</term>
+    <term name="and">in</term>
+    <term name="and others">in drugi</term>
+    <term name="anonymous">anonimni</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">pri</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">citirano</term>
+    <term name="edition">
+      <single>izdaja</single>
+      <multiple>izdaje</multiple>
+    </term>
+    <term name="edition" form="short">iz</term>
+    <term name="et-al">idr.</term>
+    <term name="forthcoming">pred izidom</term>
+    <term name="from">od</term>
+    <term name="ibid">isto</term>
+    <term name="in">v</term>
+    <term name="in press">v tisku</term>
+    <term name="internet">internet</term>
+    <term name="interview">intervju</term>
+    <term name="letter">pismo</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">b.d.</term>
+    <term name="online">na spletu</term>
+    <term name="presented at">predstavljeno na</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">pridobljeno</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">‚</term>
+    <term name="close-inner-quote">‘</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologija</term>
+    <term name="astronomy">astronomija</term>
+    <term name="biology">biologija</term>
+    <term name="botany">botanika</term>
+    <term name="chemistry">kemija</term>
+    <term name="engineering">strojništvo</term>
+    <term name="generic-base">splošno</term>
+    <term name="geography">geografija</term>
+    <term name="geology">geologija</term>
+    <term name="history">zgodovina</term>
+    <term name="humanities">humanistika</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literatura</term>
+    <term name="math">matematika</term>
+    <term name="medicine">medicina</term>
+    <term name="philosophy">filozofija</term>
+    <term name="physics">fizika</term>
+    <term name="psychology">psihologija</term>
+    <term name="sociology">sociologija</term>
+    <term name="science">znanost</term>
+    <term name="political_science">politologija</term>
+    <term name="social_science">družbene vede</term>
+    <term name="theology">teologija</term>
+    <term name="zoology">zoologija</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>knjiga</single>
+      <multiple>knjige</multiple>
+    </term>
+    <term name="chapter">
+      <single>poglavje</single>
+      <multiple>poglavja</multiple>
+    </term>
+    <term name="column">
+      <single>stolpec</single>
+      <multiple>stolpci</multiple>
+    </term>
+    <term name="figure">
+      <single>slika</single>
+      <multiple>slike</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folii</multiple>
+    </term>
+    <term name="issue">
+      <single>številka</single>
+      <multiple>številke</multiple>
+    </term>
+    <term name="line">
+      <single>vrstica</single>
+      <multiple>vrstice</multiple>
+    </term>
+    <term name="note">
+      <single>opomba</single>
+      <multiple>opombe</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>stran</single>
+      <multiple>strani</multiple>
+    </term>
+    <term name="paragraph">
+      <single>odstavek</single>
+      <multiple>odstavki</multiple>
+    </term>
+    <term name="part">
+      <single>del</single>
+      <multiple>deli</multiple>
+    </term>
+    <term name="section">
+      <single>odsek</single>
+      <multiple>odseki</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verz</single>
+      <multiple>verzi</multiple>
+    </term>
+    <term name="volume">
+      <single>letnik</single>
+      <multiple>letniki</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">knj</term>
+    <term name="chapter" form="short">pogl</term>
+    <term name="column" form="short">sto</term>
+    <term name="figure" form="short">sl</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">št</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>str</single>
+      <multiple>str</multiple>
+    </term>
+    <term name="paragraph" form="short">odst</term>
+    <term name="part" form="short">del</term>
+    <term name="section" form="short">odsk</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>v</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>let</single>
+      <multiple>let</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>urednik</single>
+      <multiple>uredniki</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>prevajalec</single>
+      <multiple>prevajalci</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ur</single>
+      <multiple>ur</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>prev</single>
+      <multiple>prev</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">uredil</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">prevedel</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">za</term>
+    <term name="interviewer" form="verb">intervjuval</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ur</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">prev</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">januar</term>
+    <term name="month-02">februar</term>
+    <term name="month-03">marec</term>
+    <term name="month-04">april</term>
+    <term name="month-05">maj</term>
+    <term name="month-06">junij</term>
+    <term name="month-07">julij</term>
+    <term name="month-08">avgust</term>
+    <term name="month-09">september</term>
+    <term name="month-10">oktober</term>
+    <term name="month-11">november</term>
+    <term name="month-12">december</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">jan</term>
+    <term name="month-02" form="short">feb</term>
+    <term name="month-03" form="short">mar</term>
+    <term name="month-04" form="short">apr</term>
+    <term name="month-05" form="short">maj</term>
+    <term name="month-06" form="short">jun</term>
+    <term name="month-07" form="short">jul</term>
+    <term name="month-08" form="short">avg</term>
+    <term name="month-09" form="short">sep</term>
+    <term name="month-10" form="short">okt</term>
+    <term name="month-11" form="short">nov</term>
+    <term name="month-12" form="short">dec</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-sr-RS.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="sr-RS">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric-leading-zeros" suffix=". "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year" suffix="."/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+  </date>
+  <terms>
+    <term name="accessed">приÑтупљено</term>
+    <term name="and">и</term>
+    <term name="and others">и оÑтали</term>
+    <term name="anonymous">анонимна</term>
+    <term name="anonymous" form="short">анон.</term>
+    <term name="at">на</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">цитирано</term>
+    <term name="edition">
+      <single>издање</single>
+      <multiple>издања</multiple>
+    </term>
+    <term name="edition" form="short">изд.</term>
+    <term name="et-al">и оÑтали</term>
+    <term name="forthcoming">долазећи</term>
+    <term name="from">од</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">у</term>
+    <term name="in press">у штампи</term>
+    <term name="internet">Интернет</term>
+    <term name="interview">интервју</term>
+    <term name="letter">пиÑмо</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">без датума</term>
+    <term name="online">на Интернету</term>
+    <term name="presented at">предÑтављено на</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">преузето</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">„</term>
+    <term name="close-quote">“</term>
+    <term name="open-inner-quote">‚</term>
+    <term name="close-inner-quote">‘</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">антропологија</term>
+    <term name="astronomy">аÑтрономија</term>
+    <term name="biology">биологија</term>
+    <term name="botany">ботаника</term>
+    <term name="chemistry">хемија</term>
+    <term name="engineering">инжињерÑтво</term>
+    <term name="generic-base">уопштена оÑнова</term>
+    <term name="geography">географија</term>
+    <term name="geology">геологија</term>
+    <term name="history">иÑторија</term>
+    <term name="humanities">култура и уметноÑÑ‚</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">литература</term>
+    <term name="math">математика</term>
+    <term name="medicine">медицина</term>
+    <term name="philosophy">филозофија</term>
+    <term name="physics">физика</term>
+    <term name="psychology">пÑихологија</term>
+    <term name="sociology">Ñоциологија</term>
+    <term name="science">наука</term>
+    <term name="political_science">политичка наука</term>
+    <term name="social_science">друштвена наука</term>
+    <term name="theology">теологија</term>
+    <term name="zoology">зоологија</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>књига</single>
+      <multiple>књиге</multiple>
+    </term>
+    <term name="chapter">
+      <single>поглавље</single>
+      <multiple>поглавља</multiple>
+    </term>
+    <term name="column">
+      <single>колона</single>
+      <multiple>колоне</multiple>
+    </term>
+    <term name="figure">
+      <single>цртеж</single>
+      <multiple>цртежи</multiple>
+    </term>
+    <term name="folio">
+      <single>фолио</single>
+      <multiple>фолији</multiple>
+    </term>
+    <term name="issue">
+      <single>број</single>
+      <multiple>бројеви</multiple>
+    </term>
+    <term name="line">
+      <single>линија</single>
+      <multiple>линије</multiple>
+    </term>
+    <term name="note">
+      <single>белешка</single>
+      <multiple>белешке</multiple>
+    </term>
+    <term name="opus">
+      <single>опуÑ</single>
+      <multiple>опера</multiple>
+    </term>
+    <term name="page">
+      <single>Ñтраница</single>
+      <multiple>Ñтранице</multiple>
+    </term>
+    <term name="paragraph">
+      <single>параграф</single>
+      <multiple>параграфи</multiple>
+    </term>
+    <term name="part">
+      <single>део</single>
+      <multiple>делова</multiple>
+    </term>
+    <term name="section">
+      <single>одељак</single>
+      <multiple>одељака</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>Ñтрофа</single>
+      <multiple>Ñтрофе</multiple>
+    </term>
+    <term name="volume">
+      <single>том</single>
+      <multiple>томова</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">књига</term>
+    <term name="chapter" form="short">Пог.</term>
+    <term name="column" form="short">кол.</term>
+    <term name="figure" form="short">црт.</term>
+    <term name="folio" form="short">фолио</term>
+    <term name="issue" form="short">изд.</term>
+    <term name="opus" form="short">оп.</term>
+    <term name="page" form="short">
+      <single>Ñтр.</single>
+      <multiple>Ñтр.</multiple>
+    </term>
+    <term name="paragraph" form="short">пар.</term>
+    <term name="part" form="short">део</term>
+    <term name="section" form="short">од.</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>Ñтр.</single>
+      <multiple>Ñтр.</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>том</single>
+      <multiple>томови</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>уредник</single>
+      <multiple>урединици</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>преводилац</single>
+      <multiple>преводиоци</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ур.</single>
+      <multiple>ур.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>прев.</single>
+      <multiple>прев.</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">уредио</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">превео</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">прима</term>
+    <term name="interviewer" form="verb">интервјуиÑао</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ур.</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">прев.</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Јануар</term>
+    <term name="month-02">Фебруар</term>
+    <term name="month-03">Март</term>
+    <term name="month-04">Ðприл</term>
+    <term name="month-05">Мај</term>
+    <term name="month-06">Јуни</term>
+    <term name="month-07">Јули</term>
+    <term name="month-08">ÐвгуÑÑ‚</term>
+    <term name="month-09">Септембар</term>
+    <term name="month-10">Октобар</term>
+    <term name="month-11">Ðовембар</term>
+    <term name="month-12">Децембар</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Јан.</term>
+    <term name="month-02" form="short">Феб.</term>
+    <term name="month-03" form="short">Март</term>
+    <term name="month-04" form="short">Ðпр.</term>
+    <term name="month-05" form="short">Мај</term>
+    <term name="month-06" form="short">Јуни</term>
+    <term name="month-07" form="short">Јули</term>
+    <term name="month-08" form="short">Ðвг.</term>
+    <term name="month-09" form="short">Сеп.</term>
+    <term name="month-10" form="short">Окт.</term>
+    <term name="month-11" form="short">Ðов.</term>
+    <term name="month-12" form="short">Дец.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-sv-SE.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="sv-SE">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric-leading-zeros" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="-" range-delimiter="/"/>
+  </date>
+  <terms>
+    <term name="accessed">Ã¥tkomstdatum</term>
+    <term name="and">och</term>
+    <term name="and others">och andra</term>
+    <term name="anonymous">anonym</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">vid</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">citerad</term>
+    <term name="edition">
+      <single>upplaga</single>
+      <multiple>upplagor</multiple>
+    </term>
+    <term name="edition" form="short">uppl</term>
+    <term name="et-al">m.fl.</term>
+    <term name="forthcoming">kommande</term>
+    <term name="from">från</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">i</term>
+    <term name="in press">i tryck</term>
+    <term name="internet">internet</term>
+    <term name="interview">intervju</term>
+    <term name="letter">brev</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">nd</term>
+    <term name="online">online</term>
+    <term name="presented at">presenterad vid</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">hämtad</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">â€</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">’</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropologi</term>
+    <term name="astronomy">astronomi</term>
+    <term name="biology">biologi</term>
+    <term name="botany">botanik</term>
+    <term name="chemistry">kemi</term>
+    <term name="engineering">teknik</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geografi</term>
+    <term name="geology">geologi</term>
+    <term name="history">historia</term>
+    <term name="humanities">humaniora</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">litteraturvetenskap</term>
+    <term name="math">matematik</term>
+    <term name="medicine">medicin</term>
+    <term name="philosophy">filosofi</term>
+    <term name="physics">fysik</term>
+    <term name="psychology">psykologi</term>
+    <term name="sociology">sociologi</term>
+    <term name="science">vetenskap</term>
+    <term name="political_science">statsvetenskap</term>
+    <term name="social_science">samhällsvetenskap</term>
+    <term name="theology">teologi</term>
+    <term name="zoology">zoologi</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>bok</single>
+      <multiple>böcker</multiple>
+    </term>
+    <term name="chapter">
+      <single>kapitel</single>
+      <multiple>kapitel</multiple>
+    </term>
+    <term name="column">
+      <single>kolumn</single>
+      <multiple>kolumner</multiple>
+    </term>
+    <term name="figure">
+      <single>figur</single>
+      <multiple>figurer</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>nummer</single>
+      <multiple>nummer</multiple>
+    </term>
+    <term name="line">
+      <single>rad</single>
+      <multiple>rader</multiple>
+    </term>
+    <term name="note">
+      <single>not</single>
+      <multiple>noter</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>sida</single>
+      <multiple>sidor</multiple>
+    </term>
+    <term name="paragraph">
+      <single>stycke</single>
+      <multiple>stycken</multiple>
+    </term>
+    <term name="part">
+      <single>dek</single>
+      <multiple>delar</multiple>
+    </term>
+    <term name="section">
+      <single>avsnitt</single>
+      <multiple>avsnitt</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>vers</single>
+      <multiple>verser</multiple>
+    </term>
+    <term name="volume">
+      <single>volym</single>
+      <multiple>volumer</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bok</term>
+    <term name="chapter" form="short">kap</term>
+    <term name="column" form="short">kol</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">num</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>s</single>
+      <multiple>ss</multiple>
+    </term>
+    <term name="paragraph" form="short">st</term>
+    <term name="part" form="short">del</term>
+    <term name="section" form="short">avs</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>vers</single>
+      <multiple>verser</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>redaktör</single>
+      <multiple>redaktörer</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>översättare</single>
+      <multiple>översättare</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>red</single>
+      <multiple>reds</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>övers</single>
+      <multiple>övers</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">redigerad av</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">översatt av</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">till</term>
+    <term name="interviewer" form="verb">intervju av</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">red</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">övers</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Januari</term>
+    <term name="month-02">Februari</term>
+    <term name="month-03">Mars</term>
+    <term name="month-04">April</term>
+    <term name="month-05">Maj</term>
+    <term name="month-06">Juni</term>
+    <term name="month-07">Juli</term>
+    <term name="month-08">Augusti</term>
+    <term name="month-09">September</term>
+    <term name="month-10">Oktober</term>
+    <term name="month-11">November</term>
+    <term name="month-12">December</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan</term>
+    <term name="month-02" form="short">Feb</term>
+    <term name="month-03" form="short">Mar</term>
+    <term name="month-04" form="short">Apr</term>
+    <term name="month-05" form="short">Maj</term>
+    <term name="month-06" form="short">Jun</term>
+    <term name="month-07" form="short">Jul</term>
+    <term name="month-08" form="short">Aug</term>
+    <term name="month-09" form="short">Sep</term>
+    <term name="month-10" form="short">Okt</term>
+    <term name="month-11" form="short">Nov</term>
+    <term name="month-12" form="short">Dec</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-th-TH.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="th-TH">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">สืบค้น</term>
+    <term name="and">à¹à¸¥à¸°</term>
+    <term name="and others">à¹à¸¥à¸°à¸„ณะ</term>
+    <term name="anonymous">นิรนาม</term>
+    <term name="anonymous" form="short">นิรนาม</term>
+    <term name="at">ที่</term>
+    <term name="by">โดย</term>
+    <term name="circa">โดยประมาณ</term>
+    <term name="circa" form="short">ประมาณ</term>
+    <term name="cited">อ้างถึง</term>
+    <term name="edition">
+      <single>พิมพ์ครั้งที่</single>
+      <multiple>พิมพ์ครั้งที่</multiple>
+    </term>
+    <term name="edition" form="short">พิมพ์ครั้งที่</term>
+    <term name="et-al">à¹à¸¥à¸°à¸„ณะ</term>
+    <term name="forthcoming">เต็มใจให้ข้อมูล</term>
+    <term name="from">จาà¸</term>
+    <term name="ibid"> ในที่เดียวà¸à¸±à¸™</term>
+    <term name="in">ใน</term>
+    <term name="in press">à¸à¸³à¸¥à¸±à¸‡à¸£à¸­à¸•ีพิมพ์</term>
+    <term name="internet">อินเทอร์เน็ต</term>
+    <term name="interview">à¸à¸²à¸£à¸ªà¸±à¸¡à¸ à¸²à¸©à¸“์</term>
+    <term name="letter">จดหมาย</term>
+    <term name="no date">ไม่ปราà¸à¸à¸›à¸µà¸—ี่พิมพ์</term>
+    <term name="no date" form="short">ม.ป.ป.</term>
+    <term name="online">ออนไลน์</term>
+    <term name="presented at">นำเสนอที่</term>
+    <term name="reference">
+      <single>เอà¸à¸ªà¸²à¸£à¸­à¹‰à¸²à¸‡à¸­à¸´à¸‡</single>
+      <multiple>เอà¸à¸ªà¸²à¸£à¸­à¹‰à¸²à¸‡à¸­à¸´à¸‡</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>อ้างอิง</single>
+      <multiple>อ้างอิง</multiple>
+    </term>
+    <term name="retrieved">สืบค้น</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">ค.ศ.</term>
+    <term name="bc">พ.ศ.</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">หนึ่ง</term>
+    <term name="ordinal-02">สอง</term>
+    <term name="ordinal-03">สาม</term>
+    <term name="ordinal-04">สี่</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">หนึ่ง</term>
+    <term name="long-ordinal-02">สอง</term>
+    <term name="long-ordinal-03">สาม</term>
+    <term name="long-ordinal-04">สี่</term>
+    <term name="long-ordinal-05">ห้า</term>
+    <term name="long-ordinal-06">หà¸</term>
+    <term name="long-ordinal-07">เจ็ด</term>
+    <term name="long-ordinal-08">à¹à¸›à¸”</term>
+    <term name="long-ordinal-09">เà¸à¹‰à¸²</term>
+    <term name="long-ordinal-10">สิบ</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">มานุษยวิทยา</term>
+    <term name="astronomy">ดาราศาสตร์</term>
+    <term name="biology">ชีววิทยา</term>
+    <term name="botany">พฤà¸à¸©à¸¨à¸²à¸ªà¸•ร์</term>
+    <term name="chemistry">เคมี</term>
+    <term name="engineering">วิศวà¸à¸£à¸£à¸¡à¸¨à¸²à¸ªà¸•ร์</term>
+    <term name="generic-base">พื้นà¸à¸²à¸™à¸—ั่วไป</term>
+    <term name="geography">ภูมิศาสตร์</term>
+    <term name="geology">ธรณีวิทยา</term>
+    <term name="history">ประวัติศาสตร์</term>
+    <term name="humanities">มนุษยศาสตร์</term>
+    <term name="linguistics">ภาษาศาสตร์</term>
+    <term name="literature">วรรณคดี</term>
+    <term name="math">คณิตศาสตร์</term>
+    <term name="medicine">เวชศาสตร์</term>
+    <term name="philosophy">ปรัชà¸à¸²</term>
+    <term name="physics">ฟิสิà¸à¸ªà¹Œ</term>
+    <term name="psychology">จิตวิทยา</term>
+    <term name="sociology">สังคมวิทยา</term>
+    <term name="science">วิทยาศาสตร์</term>
+    <term name="political_science">รัà¸à¸¨à¸²à¸ªà¸•ร์</term>
+    <term name="social_science">สังคมศาสตร์</term>
+    <term name="theology">เทววิทยา</term>
+    <term name="zoology">สัตววิทยา</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>หนังสือ</single>
+      <multiple>หนังสือ</multiple>
+    </term>
+    <term name="chapter">
+      <single>บทที่</single>
+      <multiple>บทที่</multiple>
+    </term>
+    <term name="column">
+      <single>สดมภ์</single>
+      <multiple>สดมภ์</multiple>
+    </term>
+    <term name="figure">
+      <single>รูปภาพ</single>
+      <multiple>รูปภาพ</multiple>
+    </term>
+    <term name="folio">
+      <single>หน้า</single>
+      <multiple>หน้า</multiple>
+    </term>
+    <term name="issue">
+      <single>ฉบับที่</single>
+      <multiple>ฉบับที่</multiple>
+    </term>
+    <term name="line">
+      <single>บรรทัดที่</single>
+      <multiple>บรรทัดที่</multiple>
+    </term>
+    <term name="note">
+      <single>บันทึà¸</single>
+      <multiple>บันทึà¸</multiple>
+    </term>
+    <term name="opus">
+      <single>บทประพันธ์</single>
+      <multiple>บทประพันธ์</multiple>
+    </term>
+    <term name="page">
+      <single>หน้า</single>
+      <multiple>หน้า</multiple>
+    </term>
+    <term name="paragraph">
+      <single>ย่อหน้า</single>
+      <multiple>ย่อหน้า</multiple>
+    </term>
+    <term name="part">
+      <single>ส่วนย่อย</single>
+      <multiple>ส่วนย่อย</multiple>
+    </term>
+    <term name="section">
+      <single>หมวด</single>
+      <multiple>หมวด</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>ใต้คำ</single>
+      <multiple>ใต้คำ</multiple>
+    </term>
+    <term name="verse">
+      <single>ร้อยà¸à¸£à¸­à¸‡</single>
+      <multiple>ร้อยà¸à¸£à¸­à¸‡</multiple>
+    </term>
+    <term name="volume">
+      <single>ปีที่</single>
+      <multiple>ปีที่</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">หนังสือ</term>
+    <term name="chapter" form="short">บทที่</term>
+    <term name="column" form="short">สดมภ์</term>
+    <term name="figure" form="short">รูปภาพ</term>
+    <term name="folio" form="short">หน้า</term>
+    <term name="issue" form="short">ฉบับที่</term>
+    <term name="opus" form="short">บทประพันธ์</term>
+    <term name="page" form="short">
+      <single>น.</single>
+      <multiple>น.</multiple>
+    </term>
+    <term name="paragraph" form="short">ย่อหน้า</term>
+    <term name="part" form="short">ส่วนย่อย</term>
+    <term name="section" form="short">หมวด</term>
+    <term name="sub verbo" form="short">
+      <single>ใต้คำ</single>
+      <multiple>ใต้คำ</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>ร้อยà¸à¸£à¸­à¸‡</single>
+      <multiple>ร้อยà¸à¸£à¸­à¸‡</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>ปี</single>
+      <multiple>ปี</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single></single>
+      <multiple></multiple>
+    </term>
+    <term name="editor">
+      <single>บรรณาธิà¸à¸²à¸£</single>
+      <multiple>บรรณาธิà¸à¸²à¸£</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>ผู้อำนวยà¸à¸²à¸£à¸šà¸—บรรณาธิà¸à¸²à¸£</single>
+      <multiple>ผู้อำนวยà¸à¸²à¸£à¸šà¸—บรรณาธิà¸à¸²à¸£</multiple>
+    </term>
+    <term name="translator">
+      <single>ผู้à¹à¸›à¸¥</single>
+      <multiple>ผู้à¹à¸›à¸¥</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>บรรณาธิà¸à¸²à¸£à¹à¸¥à¸°à¸œà¸¹à¹‰à¹à¸›à¸¥</single>
+      <multiple>บรรณาธิà¸à¸²à¸£à¹à¸¥à¸°à¸œà¸¹à¹‰à¹à¸›à¸¥</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single></single>
+      <multiple></multiple>
+    </term>
+    <term name="editor" form="short">
+      <single>บ.à¸.</single>
+      <multiple>บ.à¸.</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ผอ.บทบรรณาธิà¸à¸²à¸£</single>
+      <multiple>ผอ.บทบรรณาธิà¸à¸²à¸£</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>ผู้à¹à¸›à¸¥</single>
+      <multiple>ผู้à¹à¸›à¸¥</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>บ.à¸.</single>
+      <multiple>บ.à¸.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">เรียบเรียงโดย</term>
+    <term name="editorial-director" form="verb">เรียบเรียงโดย</term>
+    <term name="translator" form="verb">à¹à¸›à¸¥à¹‚ดย</term>
+    <term name="editortranslator" form="verb">à¹à¸›à¸¥à¹à¸¥à¸°à¹€à¸£à¸µà¸¢à¸šà¹€à¸£à¸µà¸¢à¸‡à¹‚ดย</term>
+    <term name="recipient" form="verb">ถึง</term>
+    <term name="interviewer" form="verb">สัมภาษณ์โดย</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">โดย</term>
+    <term name="editor" form="verb-short">โดย</term>
+    <term name="editorial-director" form="verb-short">โดย</term>
+    <term name="translator" form="verb-short">à¹à¸›à¸¥</term>
+    <term name="editortranslator" form="verb-short">à¹à¸›à¸¥à¹à¸¥à¸°à¹€à¸£à¸µà¸¢à¸šà¹€à¸£à¸µà¸¢à¸‡à¹‚ดย</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">มà¸à¸£à¸²à¸„ม</term>
+    <term name="month-02">à¸à¸¸à¸¡à¸ à¸²à¸žà¸±à¸™à¸˜à¹Œ</term>
+    <term name="month-03">มีนาคม</term>
+    <term name="month-04">เมษายน</term>
+    <term name="month-05">พฤษภาคม</term>
+    <term name="month-06">มิถุนายน</term>
+    <term name="month-07">à¸à¸£à¸à¸Žà¸²à¸„ม</term>
+    <term name="month-08">สิงหาคม</term>
+    <term name="month-09">à¸à¸±à¸™à¸¢à¸²à¸¢à¸™</term>
+    <term name="month-10">ตุลาคาม</term>
+    <term name="month-11">พฤศจิà¸à¸²à¸¢à¸™</term>
+    <term name="month-12">ธันวาคม</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">ม.ค.</term>
+    <term name="month-02" form="short">à¸.พ.</term>
+    <term name="month-03" form="short">มี.ค.</term>
+    <term name="month-04" form="short">เม.ย.</term>
+    <term name="month-05" form="short">พ.ค.</term>
+    <term name="month-06" form="short">มิ.ย.</term>
+    <term name="month-07" form="short">à¸.ค.</term>
+    <term name="month-08" form="short">ส.ค.</term>
+    <term name="month-09" form="short">à¸.ย.</term>
+    <term name="month-10" form="short">ต.ค.</term>
+    <term name="month-11" form="short">พ.ย.</term>
+    <term name="month-12" form="short">ธ.ค.</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">ฤดูใบไม้ผลิ</term>
+    <term name="season-02">ฤดูร้อน</term>
+    <term name="season-03">ฤดูใบไม้ร่วง</term>
+    <term name="season-04">ฤดูหนาว</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-tr-TR.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="tr-TR">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric-leading-zeros" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">eriÅŸildi</term>
+    <term name="and">ve</term>
+    <term name="and others">ve diÄŸ.</term>
+    <term name="anonymous">isimsiz</term>
+    <term name="anonymous" form="short">isimsiz</term>
+    <term name="at">de</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">kaynak</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">ve diÄŸ.</term>
+    <term name="forthcoming">gelecek</term>
+    <term name="from">den</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">içinde</term>
+    <term name="in press">basımda</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">tarih yok</term>
+    <term name="online">çevrimiçi</term>
+    <term name="presented at">sunulan</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">eriÅŸildi</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">‹</term>
+    <term name="close-inner-quote">›</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">antropoloji</term>
+    <term name="astronomy">astronomi</term>
+    <term name="biology">biyoloji</term>
+    <term name="botany">botanik</term>
+    <term name="chemistry">kimya</term>
+    <term name="engineering">mühendislik</term>
+    <term name="generic-base">generic-base</term>
+    <term name="geography">coÄŸrafya</term>
+    <term name="geology">jeoloji</term>
+    <term name="history">tarih</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">edebiyat</term>
+    <term name="math">matematik</term>
+    <term name="medicine">tıp</term>
+    <term name="philosophy">felsefe</term>
+    <term name="physics">fizik</term>
+    <term name="psychology">pisikoloji</term>
+    <term name="sociology">sosyoloji</term>
+    <term name="science">bilim</term>
+    <term name="political_science">siyaset bilimi</term>
+    <term name="social_science">sosyal bilimler</term>
+    <term name="theology">din bilimi</term>
+    <term name="zoology">hayvanbilimi</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>kitap</single>
+      <multiple>kitaplar</multiple>
+    </term>
+    <term name="chapter">
+      <single>bölüm</single>
+      <multiple>bölümler</multiple>
+    </term>
+    <term name="column">
+      <single>sütun</single>
+      <multiple>sütunlar</multiple>
+    </term>
+    <term name="figure">
+      <single>ÅŸekil</single>
+      <multiple>ÅŸekiller</multiple>
+    </term>
+    <term name="folio">
+      <single>folyo</single>
+      <multiple>folyo</multiple>
+    </term>
+    <term name="issue">
+      <single>sayı</single>
+      <multiple>sayılar</multiple>
+    </term>
+    <term name="line">
+      <single>satır</single>
+      <multiple>satırlar</multiple>
+    </term>
+    <term name="note">
+      <single>not</single>
+      <multiple>notlar</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>sayfa</single>
+      <multiple>sayfalar</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraf</single>
+      <multiple>paragraflar</multiple>
+    </term>
+    <term name="part">
+      <single>kısım</single>
+      <multiple>kısımlar</multiple>
+    </term>
+    <term name="section">
+      <single>bölüm</single>
+      <multiple>bölümler</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>dize</single>
+      <multiple>dizeler</multiple>
+    </term>
+    <term name="volume">
+      <single>cilt</single>
+      <multiple>ciltler</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">kit</term>
+    <term name="chapter" form="short">böl</term>
+    <term name="column" form="short">süt</term>
+    <term name="figure" form="short">ÅŸek</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">sayı</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>s</single>
+      <multiple>ss</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">kıs</term>
+    <term name="section" form="short">böl</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editör</single>
+      <multiple>editörler</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>çevirmen</single>
+      <multiple>çevirmenler</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed</single>
+      <multiple>ed</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>çev</single>
+      <multiple>çev</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">editör</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">çeviren</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">Röportaj yapan</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">çev</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Ocak</term>
+    <term name="month-02">Åžubat</term>
+    <term name="month-03">Mart</term>
+    <term name="month-04">Nisan</term>
+    <term name="month-05">Mayıs</term>
+    <term name="month-06">Haziran</term>
+    <term name="month-07">Temmuz</term>
+    <term name="month-08">AÄŸustos</term>
+    <term name="month-09">Eylül</term>
+    <term name="month-10">Ekim</term>
+    <term name="month-11">Kasım</term>
+    <term name="month-12">Aralık</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Oca</term>
+    <term name="month-02" form="short">Åžub</term>
+    <term name="month-03" form="short">Mar</term>
+    <term name="month-04" form="short">Nis</term>
+    <term name="month-05" form="short">May</term>
+    <term name="month-06" form="short">Haz</term>
+    <term name="month-07" form="short">Tem</term>
+    <term name="month-08" form="short">AÄŸu</term>
+    <term name="month-09" form="short">Eyl</term>
+    <term name="month-10" form="short">Eki</term>
+    <term name="month-11" form="short">Kas</term>
+    <term name="month-12" form="short">Ara</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-uk-UA.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="uk-UA">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" form="numeric-leading-zeros" suffix=", "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">accessed</term>
+    <term name="and">Ñ–</term>
+    <term name="and others">та інші</term>
+    <term name="anonymous">анонімний</term>
+    <term name="anonymous" form="short">анон.</term>
+    <term name="at">на</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">із</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">в</term>
+    <term name="in press">у преÑÑ–</term>
+    <term name="internet">інтернет</term>
+    <term name="interview">інтервю</term>
+    <term name="letter">лиÑÑ‚</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">n.d.</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <!-- (Single quote added without authority) -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">антропологіÑ</term>
+    <term name="astronomy">аÑтрономіÑ</term>
+    <term name="biology">біологіÑ</term>
+    <term name="botany">ботаніка</term>
+    <term name="chemistry">хіміÑ</term>
+    <term name="engineering">інженеріÑ</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">географіÑ</term>
+    <term name="geology">геологіÑ</term>
+    <term name="history">Ñ–ÑторіÑ</term>
+    <term name="humanities">гуманітарні</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">література</term>
+    <term name="math">математика</term>
+    <term name="medicine">медицина</term>
+    <term name="philosophy">філоÑофіÑ</term>
+    <term name="physics">фізика</term>
+    <term name="psychology">пÑихологіÑ</term>
+    <term name="sociology">ÑоціологіÑ</term>
+    <term name="science">наука</term>
+    <term name="political_science">політичні науки</term>
+    <term name="social_science">Ñоціальні науки</term>
+    <term name="theology">теологіÑ</term>
+    <term name="zoology">зоологіÑ</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>line</single>
+      <multiple>lines</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>page</single>
+      <multiple>pages</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraph</single>
+      <multiple>paragraph</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk</term>
+    <term name="chapter" form="short">chap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">no</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>p</single>
+      <multiple>pp</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>translator</single>
+      <multiple>translators</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed</single>
+      <multiple>eds</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tran</single>
+      <multiple>trans</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">edited by</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">translated by</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Січень</term>
+    <term name="month-02">Лютий</term>
+    <term name="month-03">Березень</term>
+    <term name="month-04">Квітень</term>
+    <term name="month-05">Травень</term>
+    <term name="month-06">Червень</term>
+    <term name="month-07">Липень</term>
+    <term name="month-08">Серпень</term>
+    <term name="month-09">ВереÑень</term>
+    <term name="month-10">Жовтень</term>
+    <term name="month-11">ЛиÑтопад</term>
+    <term name="month-12">Грудень</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Січ</term>
+    <term name="month-02" form="short">Лют</term>
+    <term name="month-03" form="short">Бер</term>
+    <term name="month-04" form="short">Квіт</term>
+    <term name="month-05" form="short">Трав</term>
+    <term name="month-06" form="short">Чер</term>
+    <term name="month-07" form="short">Лип</term>
+    <term name="month-08" form="short">Сер</term>
+    <term name="month-09" form="short">Вер</term>
+    <term name="month-10" form="short">Жов</term>
+    <term name="month-11" form="short">ЛиÑ</term>
+    <term name="month-12" form="short">Груд</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-vi-VN.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="vi-VN">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="day" suffix=" "/>
+    <date-part name="month" suffix=" "/>
+    <date-part name="year"/>
+  </date>
+  <date form="numeric">
+    <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
+    <date-part name="year"/>
+  </date>
+  <terms>
+    <term name="accessed">truy cập</term>
+    <term name="and">và</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">và c.s.</term>
+    <term name="forthcoming">sắp tới</term>
+    <term name="from">từ</term>
+    <term name="ibid">n.t.</term>
+    <term name="in">trong</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">không ngày</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">truy vấn</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">«</term>
+    <term name="close-quote">»</term>
+    <term name="open-inner-quote">‹</term>
+    <term name="close-inner-quote">›</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>dòng</single>
+      <multiple>dòng</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>trang</single>
+      <multiple>trang</multiple>
+    </term>
+    <term name="paragraph">
+      <single>đoạn văn</single>
+      <multiple>đoạn văn</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk</term>
+    <term name="chapter" form="short">chap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">số p.h</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>tr</single>
+      <multiple>tr</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>biên tập viên</single>
+      <multiple>biên tập viên</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>biên dịch viên</single>
+      <multiple>biên dịch viên</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>b.t.v</single>
+      <multiple>b.t.v</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>b.d.v</single>
+      <multiple>b.d.v</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">biên tập bởi</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">biên dịch bởi</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">b.t</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">b.d</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">Tháng Giêng</term>
+    <term name="month-02">Tháng Hai</term>
+    <term name="month-03">Tháng Ba</term>
+    <term name="month-04">Tháng Tư</term>
+    <term name="month-05">Tháng Năm</term>
+    <term name="month-06">Tháng Sáu</term>
+    <term name="month-07">Tháng Bảy</term>
+    <term name="month-08">Tháng Tám</term>
+    <term name="month-09">Tháng Chín</term>
+    <term name="month-10">Tháng Mưá»i</term>
+    <term name="month-11">Tháng Mưá»i-Má»™t</term>
+    <term name="month-12">Tháng Chạp</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">tháng 1</term>
+    <term name="month-02" form="short">tháng 2</term>
+    <term name="month-03" form="short">tháng 3</term>
+    <term name="month-04" form="short">tháng 4</term>
+    <term name="month-05" form="short">tháng 5</term>
+    <term name="month-06" form="short">tháng 6</term>
+    <term name="month-07" form="short">tháng 7</term>
+    <term name="month-08" form="short">tháng 8</term>
+    <term name="month-09" form="short">tháng 9</term>
+    <term name="month-10" form="short">tháng 10</term>
+    <term name="month-11" form="short">tháng 11</term>
+    <term name="month-12" form="short">tháng 12</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-zh-CN.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="zh-CN">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="year" suffix="å¹´"/>
+    <date-part name="month" form="numeric" suffix="月"/>
+    <date-part name="day" suffix="æ—¥"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric" prefix="-" range-delimiter="/"/>
+    <date-part name="day" prefix="-" range-delimiter="/"/>
+  </date>
+  <terms>
+    <term name="accessed">accessed</term>
+    <term name="and">and</term>
+    <term name="and others">and others</term>
+    <term name="anonymous">anonymous</term>
+    <term name="anonymous" form="short">anon</term>
+    <term name="at">at</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">cited</term>
+    <term name="edition">
+      <single>edition</single>
+      <multiple>editions</multiple>
+    </term>
+    <term name="edition" form="short">ed</term>
+    <term name="et-al">et al.</term>
+    <term name="forthcoming">forthcoming</term>
+    <term name="from">from</term>
+    <term name="ibid">ibid.</term>
+    <term name="in">in</term>
+    <term name="in press">in press</term>
+    <term name="internet">internet</term>
+    <term name="interview">interview</term>
+    <term name="letter">letter</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">nd</term>
+    <term name="online">online</term>
+    <term name="presented at">presented at the</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">retrieved</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <term name="open-quote">“</term>
+    <term name="close-quote">â€</term>
+    <term name="open-inner-quote">‘</term>
+    <term name="close-inner-quote">’</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">anthropology</term>
+    <term name="astronomy">astronomy</term>
+    <term name="biology">biology</term>
+    <term name="botany">botany</term>
+    <term name="chemistry">chemistry</term>
+    <term name="engineering">engineering</term>
+    <term name="generic-base">generic base</term>
+    <term name="geography">geography</term>
+    <term name="geology">geology</term>
+    <term name="history">history</term>
+    <term name="humanities">humanities</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">literature</term>
+    <term name="math">math</term>
+    <term name="medicine">medicine</term>
+    <term name="philosophy">philosophy</term>
+    <term name="physics">physics</term>
+    <term name="psychology">psychology</term>
+    <term name="sociology">sociology</term>
+    <term name="science">science</term>
+    <term name="political_science">political science</term>
+    <term name="social_science">social science</term>
+    <term name="theology">theology</term>
+    <term name="zoology">zoology</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>book</single>
+      <multiple>books</multiple>
+    </term>
+    <term name="chapter">
+      <single>chapter</single>
+      <multiple>chapters</multiple>
+    </term>
+    <term name="column">
+      <single>column</single>
+      <multiple>columns</multiple>
+    </term>
+    <term name="figure">
+      <single>figure</single>
+      <multiple>figures</multiple>
+    </term>
+    <term name="folio">
+      <single>folio</single>
+      <multiple>folios</multiple>
+    </term>
+    <term name="issue">
+      <single>number</single>
+      <multiple>numbers</multiple>
+    </term>
+    <term name="line">
+      <single>line</single>
+      <multiple>line</multiple>
+    </term>
+    <term name="note">
+      <single>note</single>
+      <multiple>notes</multiple>
+    </term>
+    <term name="opus">
+      <single>opus</single>
+      <multiple>opera</multiple>
+    </term>
+    <term name="page">
+      <single>page</single>
+      <multiple>pages</multiple>
+    </term>
+    <term name="paragraph">
+      <single>paragraph</single>
+      <multiple>paragraph</multiple>
+    </term>
+    <term name="part">
+      <single>part</single>
+      <multiple>parts</multiple>
+    </term>
+    <term name="section">
+      <single>section</single>
+      <multiple>sections</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>verse</single>
+      <multiple>verses</multiple>
+    </term>
+    <term name="volume">
+      <single>volume</single>
+      <multiple>volumes</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">bk</term>
+    <term name="chapter" form="short">chap</term>
+    <term name="column" form="short">col</term>
+    <term name="figure" form="short">fig</term>
+    <term name="folio" form="short">f</term>
+    <term name="issue" form="short">no</term>
+    <term name="opus" form="short">op</term>
+    <term name="page" form="short">
+      <single>p</single>
+      <multiple>pp</multiple>
+    </term>
+    <term name="paragraph" form="short">para</term>
+    <term name="part" form="short">pt</term>
+    <term name="section" form="short">sec</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>v</single>
+      <multiple>vv</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>vol</single>
+      <multiple>vols</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>translator</single>
+      <multiple>translators</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single/>
+      <multiple/>
+    </term>
+    <term name="editor" form="short">
+      <single>ed</single>
+      <multiple>eds</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>tran</single>
+      <multiple>trans</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">edited by</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">translated by</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">to</term>
+    <term name="interviewer" form="verb">interview by</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ed</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">trans</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">January</term>
+    <term name="month-02">February</term>
+    <term name="month-03">March</term>
+    <term name="month-04">April</term>
+    <term name="month-05">May</term>
+    <term name="month-06">June</term>
+    <term name="month-07">July</term>
+    <term name="month-08">August</term>
+    <term name="month-09">September</term>
+    <term name="month-10">October</term>
+    <term name="month-11">November</term>
+    <term name="month-12">December</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">Jan</term>
+    <term name="month-02" form="short">Feb</term>
+    <term name="month-03" form="short">Mar</term>
+    <term name="month-04" form="short">Apr</term>
+    <term name="month-05" form="short">May</term>
+    <term name="month-06" form="short">Jun</term>
+    <term name="month-07" form="short">Jul</term>
+    <term name="month-08" form="short">Aug</term>
+    <term name="month-09" form="short">Sep</term>
+    <term name="month-10" form="short">Oct</term>
+    <term name="month-11" form="short">Nov</term>
+    <term name="month-12" form="short">Dec</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/locale/locales-zh-TW.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0" xml:lang="zh-TW">
+  <style-options punctuation-in-quote="false"/>
+  <date form="text">
+    <date-part name="year" suffix="å¹´"/>
+    <date-part name="month" form="numeric" suffix="月"/>
+    <date-part name="day" suffix="æ—¥"/>
+  </date>
+  <date form="numeric">
+    <date-part name="year"/>
+    <date-part name="month" form="numeric-leading-zeros" prefix="/"/>
+    <date-part name="day" form="numeric-leading-zeros" prefix="/"/>
+  </date>
+  <terms>
+    <term name="accessed">被å–用</term>
+    <term name="and">åŠ</term>
+    <term name="and others">åŠå…¶ä»–</term>
+    <term name="anonymous">ä¸å…·åçš„</term>
+    <term name="anonymous" form="short">ç„¡å</term>
+    <term name="at">在</term>
+    <term name="by">by</term>
+    <term name="circa">circa</term>
+    <term name="circa" form="short">c.</term>
+    <term name="cited">被引用</term>
+    <term name="edition">
+      <single>版本</single>
+      <multiple>版本</multiple>
+    </term>
+    <term name="edition" form="short">版</term>
+    <term name="et-al">等人</term>
+    <term name="forthcoming">將來的</term>
+    <term name="from">從</term>
+    <term name="ibid">åŒä¸Šå‡ºè™•</term>
+    <term name="in">在</term>
+    <term name="in press">å°è¡Œä¸­</term>
+    <term name="internet">網際網路</term>
+    <term name="interview">訪å•</term>
+    <term name="letter">ä¿¡ä»¶</term>
+    <term name="no date">no date</term>
+    <term name="no date" form="short">無日期</term>
+    <term name="online">在線上</term>
+    <term name="presented at">簡報於</term>
+    <term name="reference">
+      <single>reference</single>
+      <multiple>references</multiple>
+    </term>
+    <term name="reference" form="short">
+      <single>ref.</single>
+      <multiple>refs.</multiple>
+    </term>
+    <term name="retrieved">被å–回</term>
+
+    <!-- ANNO DOMINI; BEFORE CHRIST -->
+    <term name="ad">AD</term>
+    <term name="bc">BC</term>
+
+    <!-- QUOTES -->
+    <!-- Source: http://en.wikipedia.org/wiki/Non-English_usage_of_quotation_marks -->
+    <term name="open-quote">「</term>
+    <term name="close-quote">ã€</term>
+    <term name="open-inner-quote">『</term>
+    <term name="close-inner-quote">ã€</term>
+
+    <!-- ORDINALS -->
+    <term name="ordinal-01">st</term>
+    <term name="ordinal-02">nd</term>
+    <term name="ordinal-03">rd</term>
+    <term name="ordinal-04">th</term>
+
+    <!-- LONG ORDINALS -->
+    <term name="long-ordinal-01">first</term>
+    <term name="long-ordinal-02">second</term>
+    <term name="long-ordinal-03">third</term>
+    <term name="long-ordinal-04">fourth</term>
+    <term name="long-ordinal-05">fifth</term>
+    <term name="long-ordinal-06">sixth</term>
+    <term name="long-ordinal-07">seventh</term>
+    <term name="long-ordinal-08">eighth</term>
+    <term name="long-ordinal-09">ninth</term>
+    <term name="long-ordinal-10">tenth</term>
+
+    <!-- CATEGORIES -->
+    <term name="anthropology">人類學</term>
+    <term name="astronomy">天文學</term>
+    <term name="biology">生物學</term>
+    <term name="botany">æ¤ç‰©å­¸</term>
+    <term name="chemistry">化學</term>
+    <term name="engineering">工程學</term>
+    <term name="generic-base">一般基礎</term>
+    <term name="geography">地ç†å­¸</term>
+    <term name="geology">地質學</term>
+    <term name="history">æ­·å²å­¸</term>
+    <term name="humanities">人文學科</term>
+    <term name="linguistics">linguistics</term>
+    <term name="literature">文學</term>
+    <term name="math">數學</term>
+    <term name="medicine">醫學</term>
+    <term name="philosophy">哲學</term>
+    <term name="physics">物ç†å­¸</term>
+    <term name="psychology">心ç†å­¸</term>
+    <term name="sociology">社會學</term>
+    <term name="science">自然科學</term>
+    <term name="political_science">政治科學</term>
+    <term name="social_science">社會科學</term>
+    <term name="theology">神學</term>
+    <term name="zoology">動物學</term>
+
+    <!-- LONG LOCATOR FORMS -->
+    <term name="book">
+      <single>書</single>
+      <multiple>書</multiple>
+    </term>
+    <term name="chapter">
+      <single>ç« </single>
+      <multiple>ç« </multiple>
+    </term>
+    <term name="column">
+      <single>欄</single>
+      <multiple>欄</multiple>
+    </term>
+    <term name="figure">
+      <single>圖</single>
+      <multiple>圖</multiple>
+    </term>
+    <term name="folio">
+      <single>å°é–‹ç´™</single>
+      <multiple>å°é–‹ç´™</multiple>
+    </term>
+    <term name="issue">
+      <single>期數</single>
+      <multiple>期數</multiple>
+    </term>
+    <term name="line">
+      <single>行</single>
+      <multiple>行</multiple>
+    </term>
+    <term name="note">
+      <single>筆記</single>
+      <multiple>筆記</multiple>
+    </term>
+    <term name="opus">
+      <single>作å“</single>
+      <multiple>作å“</multiple>
+    </term>
+    <term name="page">
+      <single>é </single>
+      <multiple>é </multiple>
+    </term>
+    <term name="paragraph">
+      <single>段è½</single>
+      <multiple>段è½</multiple>
+    </term>
+    <term name="part">
+      <single>部</single>
+      <multiple>部</multiple>
+    </term>
+    <term name="section">
+      <single>節</single>
+      <multiple>節</multiple>
+    </term>
+    <term name="sub verbo">
+      <single>sub verbo</single>
+      <multiple>sub verbis</multiple>
+    </term>
+    <term name="verse">
+      <single>è©©å¥</single>
+      <multiple>è©©å¥</multiple>
+    </term>
+    <term name="volume">
+      <single>冊</single>
+      <multiple>冊</multiple>
+    </term>
+
+    <!-- SHORT LOCATOR FORMS -->
+    <term name="book" form="short">書</term>
+    <term name="chapter" form="short">ç« </term>
+    <term name="column" form="short">欄</term>
+    <term name="figure" form="short">圖</term>
+    <term name="folio" form="short">é–‹</term>
+    <term name="issue" form="short">期</term>
+    <term name="opus" form="short">作</term>
+    <term name="page" form="short">
+      <single>é </single>
+      <multiple>é </multiple>
+    </term>
+    <term name="paragraph" form="short">段</term>
+    <term name="part" form="short">部</term>
+    <term name="section" form="short">節</term>
+    <term name="sub verbo" form="short">
+      <single>s.v.</single>
+      <multiple>s.vv.</multiple>
+    </term>
+    <term name="verse" form="short">
+      <single>å¥</single>
+      <multiple>å¥</multiple>
+    </term>
+    <term name="volume" form="short">
+      <single>冊</single>
+      <multiple>冊</multiple>
+    </term>
+
+    <!-- SYMBOL LOCATOR FORMS -->
+    <term name="paragraph" form="symbol">
+      <single>¶</single>
+      <multiple>¶¶</multiple>
+    </term>
+    <term name="section" form="symbol">
+      <single>§</single>
+      <multiple>§§</multiple>
+    </term>
+
+    <!-- LONG ROLE FORMS -->
+    <term name="author">
+      <single>作者</single>
+      <multiple>作者</multiple>
+    </term>
+    <term name="editor">
+      <single>編輯</single>
+      <multiple>編輯</multiple>
+    </term>
+    <term name="editorial-director">
+      <single>editor</single>
+      <multiple>editors</multiple>
+    </term>
+    <term name="translator">
+      <single>翻譯</single>
+      <multiple>翻譯</multiple>
+    </term>
+    <term name="editortranslator">
+      <single>editor &amp; translator</single>
+      <multiple>editors &amp; translators</multiple>
+    </term>
+
+    <!-- SHORT ROLE FORMS -->
+    <term name="author" form="short">
+      <single>作</single>
+      <multiple>作</multiple>
+    </term>
+    <term name="editor" form="short">
+      <single>ç·¨</single>
+      <multiple>ç·¨</multiple>
+    </term>
+    <term name="editorial-director" form="short">
+      <single>ed.</single>
+      <multiple>eds.</multiple>
+    </term>
+    <term name="translator" form="short">
+      <single>è­¯</single>
+      <multiple>è­¯</multiple>
+    </term>
+    <term name="editortranslator" form="short">
+      <single>ed. &amp; tran.</single>
+      <multiple>eds. &amp; trans.</multiple>
+    </term>
+
+    <!-- VERB ROLE FORMS -->
+    <term name="editor" form="verb">編者是</term>
+    <term name="editorial-director" form="verb">edited by</term>
+    <term name="translator" form="verb">譯者是</term>
+    <term name="editortranslator" form="verb">edited &amp; translated by</term>
+    <term name="recipient" form="verb">授與</term>
+    <term name="interviewer" form="verb">訪å•者是</term>
+
+    <!-- SHORT VERB ROLE FORMS -->
+    <term name="container-author" form="verb-short">by</term>
+    <term name="editor" form="verb-short">ç·¨</term>
+    <term name="editorial-director" form="verb-short">ed.</term>
+    <term name="translator" form="verb-short">è­¯</term>
+    <term name="editortranslator" form="verb-short">ed. &amp; trans. by</term>
+
+    <!-- LONG MONTH FORMS -->
+    <term name="month-01">一月</term>
+    <term name="month-02">二月</term>
+    <term name="month-03">三月</term>
+    <term name="month-04">四月</term>
+    <term name="month-05">五月</term>
+    <term name="month-06">六月</term>
+    <term name="month-07">七月</term>
+    <term name="month-08">八月</term>
+    <term name="month-09">乿œˆ</term>
+    <term name="month-10">åæœˆ</term>
+    <term name="month-11">å一月</term>
+    <term name="month-12">å二月</term>
+
+    <!-- SHORT MONTH FORMS -->
+    <term name="month-01" form="short">1月</term>
+    <term name="month-02" form="short">2月</term>
+    <term name="month-03" form="short">3月</term>
+    <term name="month-04" form="short">4月</term>
+    <term name="month-05" form="short">5月</term>
+    <term name="month-06" form="short">6月</term>
+    <term name="month-07" form="short">7月</term>
+    <term name="month-08" form="short">8月</term>
+    <term name="month-09" form="short">9月</term>
+    <term name="month-10" form="short">10月</term>
+    <term name="month-11" form="short">11月</term>
+    <term name="month-12" form="short">12月</term>
+
+    <!-- SEASONS -->
+    <term name="season-01">Spring</term>
+    <term name="season-02">Summer</term>
+    <term name="season-03">Autumn</term>
+    <term name="season-04">Winter</term>
+  </terms>
+</locale>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/schema/csl-categories.rng	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns:cs="http://purl.org/net/xbiblio/csl" xmlns="http://relaxng.org/ns/structure/1.0">
+  <div>
+    <define name="info-format-categories">
+      <choice>
+        <value>author-date</value>
+        <value>numeric</value>
+        <value>label</value>
+        <value>note</value>
+        <value>author</value>
+      </choice>
+    </define>
+    <define name="info-field-categories">
+      <a:documentation>"generic-base" is reserved for truly generic styles (APA, Harvard, etc.).</a:documentation>
+      <choice>
+        <value>anthropology</value>
+        <value>astronomy</value>
+        <value>biology</value>
+        <value>botany</value>
+        <value>chemistry</value>
+        <value>communications</value>
+        <value>engineering</value>
+        <value>generic-base</value>
+        <value>geography</value>
+        <value>geology</value>
+        <value>history</value>
+        <value>humanities</value>
+        <value>law</value>
+        <value>linguistics</value>
+        <value>literature</value>
+        <value>math</value>
+        <value>medicine</value>
+        <value>philosophy</value>
+        <value>physics</value>
+        <value>political_science</value>
+        <value>psychology</value>
+        <value>science</value>
+        <value>social_science</value>
+        <value>sociology</value>
+        <value>theology</value>
+        <value>zoology</value>
+        <ref name="info-categories.extension"/>
+      </choice>
+    </define>
+    <define name="info-categories.extension">
+      <a:documentation>Categories can be redefined in a customization schema, though please
+report obvious gaps for inclusion in the schema.</a:documentation>
+      <notAllowed/>
+    </define>
+  </div>
+</grammar>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/schema/csl-terms.rng	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://relaxng.org/ns/structure/1.0">
+  <div>
+    <a:documentation>Terms</a:documentation>
+    <define name="cs-terms">
+      <choice>
+        <value>accessed</value>
+        <a:documentation>Miscellaneous Terms</a:documentation>
+        <value>ad</value>
+        <value>and</value>
+        <value>and others</value>
+        <value>anonymous</value>
+        <value>at</value>
+        <value>bc</value>
+        <value>by</value>
+        <value>circa</value>
+        <value>cited</value>
+        <value>et-al</value>
+        <value>forthcoming</value>
+        <value>from</value>
+        <value>ibid</value>
+        <value>in</value>
+        <value>in press</value>
+        <value>internet</value>
+        <value>interview</value>
+        <value>letter</value>
+        <value>no date</value>
+        <value>online</value>
+        <value>presented at</value>
+        <value>reference</value>
+        <value>retrieved</value>
+        <value>season-01</value>
+        <a:documentation>Seasons</a:documentation>
+        <value>season-02</value>
+        <value>season-03</value>
+        <value>season-04</value>
+        <value>open-quote</value>
+        <a:documentation>Punctuation</a:documentation>
+        <value>close-quote</value>
+        <value>open-inner-quote</value>
+        <value>close-inner-quote</value>
+        <value>page-range-delimiter</value>
+        <ref name="cs-terms.gender-assignable">
+          <a:documentation>Terms to which a gender may be assigned</a:documentation>
+        </ref>
+        <ref name="cs-terms.gender-variants">
+          <a:documentation>Terms for which gender variants may be specified</a:documentation>
+        </ref>
+        <ref name="cs-terms.locator">
+          <a:documentation>Locators</a:documentation>
+        </ref>
+        <ref name="cs-names">
+          <a:documentation>Contributor Roles</a:documentation>
+        </ref>
+        <value>editortranslator</value>
+        <ref name="info-field-categories">
+          <a:documentation>Categories</a:documentation>
+        </ref>
+        <ref name="cs-terms.extension"/>
+      </choice>
+    </define>
+    <define name="cs-terms.gender-assignable">
+      <a:documentation>Terms to which a gender may be assigned</a:documentation>
+      <choice>
+        <value>month-01</value>
+        <a:documentation>Months</a:documentation>
+        <value>month-02</value>
+        <value>month-03</value>
+        <value>month-04</value>
+        <value>month-05</value>
+        <value>month-06</value>
+        <value>month-07</value>
+        <value>month-08</value>
+        <value>month-09</value>
+        <value>month-10</value>
+        <value>month-11</value>
+        <value>month-12</value>
+        <ref name="cs-terms.non-locator-number-variables">
+          <a:documentation>Non-locator terms accompanying number variables</a:documentation>
+        </ref>
+        <ref name="cs-terms.locator-number-variables">
+          <a:documentation>Locator terms with matching number variables</a:documentation>
+        </ref>
+      </choice>
+    </define>
+    <define name="cs-terms.gender-variants">
+      <a:documentation>Terms for which gender variants may be specified</a:documentation>
+      <choice>
+        <value>ordinal-01</value>
+        <a:documentation>Ordinals</a:documentation>
+        <value>ordinal-02</value>
+        <value>ordinal-03</value>
+        <value>ordinal-04</value>
+        <value>long-ordinal-01</value>
+        <a:documentation>Long Ordinals</a:documentation>
+        <value>long-ordinal-02</value>
+        <value>long-ordinal-03</value>
+        <value>long-ordinal-04</value>
+        <value>long-ordinal-05</value>
+        <value>long-ordinal-06</value>
+        <value>long-ordinal-07</value>
+        <value>long-ordinal-08</value>
+        <value>long-ordinal-09</value>
+        <value>long-ordinal-10</value>
+      </choice>
+    </define>
+    <define name="cs-terms.locator">
+      <a:documentation>Locators</a:documentation>
+      <choice>
+        <value>book</value>
+        <value>chapter</value>
+        <value>column</value>
+        <value>figure</value>
+        <value>folio</value>
+        <value>line</value>
+        <value>note</value>
+        <value>opus</value>
+        <value>page</value>
+        <value>paragraph</value>
+        <value>part</value>
+        <value>section</value>
+        <value>sub verbo</value>
+        <value>verse</value>
+        <ref name="cs-terms.locator-number-variables">
+          <a:documentation>Locator terms with matching number variables</a:documentation>
+        </ref>
+      </choice>
+    </define>
+    <define name="cs-terms.locator-number-variables">
+      <a:documentation>Locator terms with matching number variables</a:documentation>
+      <choice>
+        <value>issue</value>
+        <value>volume</value>
+      </choice>
+    </define>
+    <define name="cs-terms.non-locator-number-variables">
+      <a:documentation>Non-locator terms accompanying number variables</a:documentation>
+      <choice>
+        <value>chapter-number</value>
+        <value>collection-number</value>
+        <value>edition</value>
+        <value>number</value>
+        <value>number-of-pages</value>
+        <value>number-of-volumes</value>
+      </choice>
+    </define>
+  </div>
+</grammar>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/schema/csl-types.rng	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://relaxng.org/ns/structure/1.0">
+  <div>
+    <a:documentation>CSL Types</a:documentation>
+    <define name="cs-types">
+      <choice>
+        <value>article</value>
+        <value>article-journal</value>
+        <value>article-magazine</value>
+        <value>article-newspaper</value>
+        <value>bill</value>
+        <value>book</value>
+        <value>broadcast</value>
+        <value>chapter</value>
+        <value>entry</value>
+        <value>entry-dictionary</value>
+        <value>entry-encyclopedia</value>
+        <value>figure</value>
+        <value>graphic</value>
+        <value>interview</value>
+        <value>legal_case</value>
+        <value>legislation</value>
+        <value>manuscript</value>
+        <value>map</value>
+        <value>motion_picture</value>
+        <value>musical_score</value>
+        <value>pamphlet</value>
+        <value>paper-conference</value>
+        <value>patent</value>
+        <value>personal_communication</value>
+        <value>post</value>
+        <value>post-weblog</value>
+        <value>report</value>
+        <value>review</value>
+        <value>review-book</value>
+        <value>song</value>
+        <value>speech</value>
+        <value>thesis</value>
+        <value>treaty</value>
+        <value>webpage</value>
+      </choice>
+    </define>
+  </div>
+</grammar>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/schema/csl-variables.rng	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns="http://relaxng.org/ns/structure/1.0">
+  <div>
+    <a:documentation>name variables</a:documentation>
+    <define name="cs-names">
+      <choice>
+        <value>author</value>
+        <value>collection-editor</value>
+        <value>composer</value>
+        <value>container-author</value>
+        <value>editor</value>
+        <value>editorial-director</value>
+        <value>illustrator</value>
+        <value>interviewer</value>
+        <value>original-author</value>
+        <value>recipient</value>
+        <value>translator</value>
+      </choice>
+    </define>
+  </div>
+  <div>
+    <a:documentation>date variables</a:documentation>
+    <define name="cs-dates">
+      <choice>
+        <value>accessed</value>
+        <value>container</value>
+        <value>event-date</value>
+        <value>issued</value>
+        <value>original-date</value>
+        <value>submitted</value>
+      </choice>
+    </define>
+  </div>
+  <div>
+    <a:documentation>number variables</a:documentation>
+    <define name="cs-numbers">
+      <choice>
+        <value>chapter-number</value>
+        <value>collection-number</value>
+        <value>edition</value>
+        <value>issue</value>
+        <value>number</value>
+        <value>number-of-pages</value>
+        <value>number-of-volumes</value>
+        <value>volume</value>
+      </choice>
+    </define>
+  </div>
+  <div>
+    <a:documentation>standard variables</a:documentation>
+    <define name="cs-variables">
+      <choice>
+        <value>abstract</value>
+        <value>annote</value>
+        <value>archive</value>
+        <value>archive_location</value>
+        <value>archive-place</value>
+        <value>authority</value>
+        <value>call-number</value>
+        <value>citation-label</value>
+        <value>citation-number</value>
+        <value>collection-title</value>
+        <value>container-title</value>
+        <value>container-title-short</value>
+        <value>dimensions</value>
+        <value>DOI</value>
+        <value>event</value>
+        <value>event-place</value>
+        <value>first-reference-note-number</value>
+        <value>genre</value>
+        <value>ISBN</value>
+        <value>ISSN</value>
+        <value>jurisdiction</value>
+        <value>keyword</value>
+        <value>locator</value>
+        <value>medium</value>
+        <value>note</value>
+        <value>original-publisher</value>
+        <value>original-publisher-place</value>
+        <value>original-title</value>
+        <value>page</value>
+        <value>page-first</value>
+        <value>PMID</value>
+        <value>PMCID</value>
+        <value>publisher</value>
+        <value>publisher-place</value>
+        <value>references</value>
+        <value>section</value>
+        <value>source</value>
+        <value>status</value>
+        <value>title</value>
+        <value>title-short</value>
+        <value>URL</value>
+        <value>version</value>
+        <value>year-suffix</value>
+        <ref name="cs-numbers">
+          <a:documentation>number variables</a:documentation>
+        </ref>
+      </choice>
+    </define>
+  </div>
+</grammar>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/schema/csl.rng	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1751 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grammar xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0" xmlns:sch="http://www.ascc.net/xml/schematron" xmlns:cs="http://purl.org/net/xbiblio/csl" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+  <!-- CSL schema metadata -->
+  <dc:title>Citation Style Language</dc:title>
+  <dc:creator>Bruce D'Arcus</dc:creator>
+  <dc:creator>Simon Kornblith</dc:creator>
+  <dc:contributor>Frank Bennett</dc:contributor>
+  <dc:contributor>Rintze Zelle</dc:contributor>
+  <dc:copyright>Bruce D'Arcus and Simon Kornblith, 2007-2011</dc:copyright>
+  <dc:rights>Permission to freely use, copy and distribute.</dc:rights>
+  <dc:description>Citation Style Language (CSL) schema for describing bibliographic and citation formatting.</dc:description>
+  <start>
+    <choice>
+      <ref name="independent-style"/>
+      <ref name="dependent-style"/>
+      <ref name="locale"/>
+    </choice>
+  </start>
+  <include href="csl-terms.rng">
+    <a:documentation>Subparts of the CSL schema</a:documentation>
+  </include>
+  <include href="csl-types.rng"/>
+  <include href="csl-variables.rng"/>
+  <include href="csl-categories.rng"/>
+  <!--
+    Embedded Schematron rules to detect calls in cs:text & cs:key to nonexistent
+    macros
+  -->
+  <sch:ns uri="http://purl.org/net/xbiblio/csl" prefix="cs"/>
+  <sch:pattern name="Non-existing macros">
+    <sch:rule context="//cs:text[@macro]">
+      <sch:assert test="@macro = /cs:style/cs:macro/@name">This macro call has no corresponding macro.</sch:assert>
+    </sch:rule>
+    <sch:rule context="//cs:key[@macro]">
+      <sch:assert test="@macro = /cs:style/cs:macro/@name">This macro call has no corresponding macro.</sch:assert>
+    </sch:rule>
+  </sch:pattern>
+  <div>
+    <a:documentation>Independent CSL style</a:documentation>
+    <define name="independent-style">
+      <element name="cs:style">
+        <optional>
+          <attribute name="default-locale">
+            <a:documentation>Set a default style locale.</a:documentation>
+            <data type="language"/>
+          </attribute>
+        </optional>
+        <attribute name="class">
+          <a:documentation>Select whether citations appear in-text or as notes.</a:documentation>
+          <choice>
+            <value>in-text</value>
+            <value>note</value>
+          </choice>
+        </attribute>
+        <ref name="style-options"/>
+        <ref name="version"/>
+        <ref name="info"/>
+        <optional>
+          <interleave>
+            <zeroOrMore>
+              <ref name="style-locale"/>
+            </zeroOrMore>
+            <zeroOrMore>
+              <ref name="macro"/>
+            </zeroOrMore>
+            <ref name="citation"/>
+            <optional>
+              <ref name="bibliography"/>
+            </optional>
+          </interleave>
+        </optional>
+      </element>
+    </define>
+  </div>
+  <div>
+    <a:documentation>Dependent CSL style</a:documentation>
+    <define name="dependent-style">
+      <element name="cs:style">
+        <ref name="version"/>
+        <ref name="info-dependent-style"/>
+        <ref name="legacy-attributes-dependent-style"/>
+      </element>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Style and Locale Metadata</xhtml:h2>
+    </a:documentation>
+    <define name="version">
+      <attribute name="version" a:defaultValue="1.0">
+        <a:documentation>Set the CSL version of the style ("1.0" for CSL 1.0-compatible
+styles).</a:documentation>
+        <value>1.0</value>
+      </attribute>
+    </define>
+    <define name="info">
+      <a:documentation>Metadata for independent styles.</a:documentation>
+      <element name="cs:info">
+        <interleave>
+          <zeroOrMore>
+            <ref name="info-author"/>
+          </zeroOrMore>
+          <zeroOrMore>
+            <ref name="info-category"/>
+          </zeroOrMore>
+          <zeroOrMore>
+            <ref name="info-contributor"/>
+          </zeroOrMore>
+          <ref name="info-id"/>
+          <zeroOrMore>
+            <ref name="info-issn"/>
+          </zeroOrMore>
+          <optional>
+            <ref name="info-eissn"/>
+          </optional>
+          <optional>
+            <ref name="info-issnl"/>
+          </optional>
+          <zeroOrMore>
+            <ref name="info-link"/>
+          </zeroOrMore>
+          <optional>
+            <ref name="info-published"/>
+          </optional>
+          <optional>
+            <ref name="info-rights"/>
+          </optional>
+          <optional>
+            <ref name="info-summary"/>
+          </optional>
+          <ref name="info-title"/>
+          <optional>
+            <ref name="info-title-short"/>
+          </optional>
+          <ref name="info-updated"/>
+        </interleave>
+      </element>
+    </define>
+    <define name="info-dependent-style">
+      <a:documentation>Metadata for dependent styles.</a:documentation>
+      <element name="cs:info">
+        <interleave>
+          <zeroOrMore>
+            <ref name="info-author"/>
+          </zeroOrMore>
+          <zeroOrMore>
+            <ref name="info-category"/>
+          </zeroOrMore>
+          <zeroOrMore>
+            <ref name="info-contributor"/>
+          </zeroOrMore>
+          <ref name="info-id"/>
+          <zeroOrMore>
+            <ref name="info-issn"/>
+          </zeroOrMore>
+          <optional>
+            <ref name="info-eissn"/>
+          </optional>
+          <optional>
+            <ref name="info-issnl"/>
+          </optional>
+          <oneOrMore>
+            <ref name="info-link-dependent-style"/>
+          </oneOrMore>
+          <optional>
+            <ref name="info-published"/>
+          </optional>
+          <optional>
+            <ref name="info-rights"/>
+          </optional>
+          <optional>
+            <ref name="info-summary"/>
+          </optional>
+          <ref name="info-title"/>
+          <optional>
+            <ref name="info-title-short"/>
+          </optional>
+          <ref name="info-updated"/>
+        </interleave>
+      </element>
+    </define>
+    <define name="info-locale">
+      <a:documentation>Metadata for locale files.</a:documentation>
+      <element name="cs:info">
+        <interleave>
+          <zeroOrMore>
+            <ref name="info-translator"/>
+          </zeroOrMore>
+          <optional>
+            <ref name="info-rights"/>
+          </optional>
+          <optional>
+            <ref name="info-updated"/>
+          </optional>
+        </interleave>
+      </element>
+    </define>
+    <define name="info-author">
+      <element name="cs:author">
+        <ref name="info-contributor-pattern"/>
+      </element>
+    </define>
+    <define name="info-contributor">
+      <element name="cs:contributor">
+        <ref name="info-contributor-pattern"/>
+      </element>
+    </define>
+    <define name="info-translator">
+      <element name="cs:translator">
+        <ref name="info-contributor-pattern"/>
+      </element>
+    </define>
+    <define name="info-contributor-pattern">
+      <interleave>
+        <element name="cs:name">
+          <text/>
+        </element>
+        <optional>
+          <element name="cs:email">
+            <text/>
+          </element>
+        </optional>
+        <optional>
+          <element name="cs:uri">
+            <data type="anyURI"/>
+          </element>
+        </optional>
+      </interleave>
+    </define>
+    <define name="info-category">
+      <element name="cs:category">
+        <a:documentation>Specify the citation format of the style (using the "citation-format"
+attribute) or the fields and disciplines for which the style is
+relevant (using the "field" attribute).</a:documentation>
+        <choice>
+          <attribute name="citation-format">
+            <ref name="info-format-categories"/>
+          </attribute>
+          <attribute name="field">
+            <ref name="info-field-categories"/>
+          </attribute>
+        </choice>
+      </element>
+    </define>
+    <define name="info-id">
+      <element name="cs:id">
+        <a:documentation>Specify the URI to establish the identity of the style. The URI
+should be stable, unique and dereferenceable URI.</a:documentation>
+        <data type="anyURI"/>
+      </element>
+    </define>
+    <define name="info-issn">
+      <element name="cs:issn">
+        <a:documentation>Specify the journal's ISSN(s) for journal-specific styles. An ISSN
+must consist of four digits, a hyphen, three digits, and a check
+digit (a numeral digit or roman X), e.g. "1234-1231".</a:documentation>
+        <data type="string">
+          <param name="pattern">\d{4}\-\d{3}(\d|x|X)</param>
+        </data>
+      </element>
+    </define>
+    <define name="info-eissn">
+      <element name="cs:eissn">
+        <a:documentation>Specify the journal's eISSN for journal-specific styles.</a:documentation>
+        <data type="string">
+          <param name="pattern">\d{4}\-\d{3}(\d|x|X)</param>
+        </data>
+      </element>
+    </define>
+    <define name="info-issnl">
+      <element name="cs:issnl">
+        <a:documentation>Specify the journal's ISSN-L for journal-specific styles.</a:documentation>
+        <data type="string">
+          <param name="pattern">\d{4}\-\d{3}(\d|x|X)</param>
+        </data>
+      </element>
+    </define>
+    <define name="info-link">
+      <element name="cs:link">
+        <attribute name="href">
+          <data type="anyURI"/>
+        </attribute>
+        <attribute name="rel">
+          <a:documentation>Specify how the URL relates to the style.</a:documentation>
+          <choice>
+            <value>self</value>
+            <a:documentation>The URI of the CSL style itself.</a:documentation>
+            <value>template</value>
+            <a:documentation>URI of the style from which the current style is derived.</a:documentation>
+            <value>documentation</value>
+            <a:documentation>URI of style documentation.</a:documentation>
+            <value>independent-parent</value>
+            <a:documentation>Obsolete for independent styles. Will be disallowed with
+CSL 1.1.</a:documentation>
+          </choice>
+        </attribute>
+        <ref name="info-text"/>
+      </element>
+    </define>
+    <define name="info-link-dependent-style">
+      <element name="cs:link">
+        <attribute name="href">
+          <data type="anyURI"/>
+        </attribute>
+        <attribute name="rel">
+          <a:documentation>Specify how the URL relates to the style.</a:documentation>
+          <choice>
+            <value>self</value>
+            <a:documentation>The URI of the CSL style itself.</a:documentation>
+            <value>independent-parent</value>
+            <a:documentation>URI of the CSL style whose content should be used for
+processing. Required for dependent styles.</a:documentation>
+            <value>documentation</value>
+            <a:documentation>URI of style documentation.</a:documentation>
+            <value>template</value>
+            <a:documentation>Obsolete for dependent styles. Will be disallowed with CSL
+1.1.</a:documentation>
+          </choice>
+        </attribute>
+        <ref name="info-text"/>
+      </element>
+    </define>
+    <define name="info-published">
+      <element name="cs:published">
+        <a:documentation>Specify when the style was initially created or made available.</a:documentation>
+        <data type="dateTime"/>
+      </element>
+    </define>
+    <define name="info-rights">
+      <element name="cs:rights">
+        <optional>
+          <attribute name="license">
+            <data type="anyURI"/>
+          </attribute>
+        </optional>
+        <ref name="info-text"/>
+      </element>
+    </define>
+    <define name="info-summary">
+      <element name="cs:summary">
+        <ref name="info-text"/>
+      </element>
+    </define>
+    <define name="info-title">
+      <element name="cs:title">
+        <ref name="info-text"/>
+      </element>
+    </define>
+    <define name="info-title-short">
+      <element name="cs:title-short">
+        <a:documentation>Specify an abbreviated style title (e.g., "APA")</a:documentation>
+        <ref name="info-text"/>
+      </element>
+    </define>
+    <define name="info-updated">
+      <element name="cs:updated">
+        <a:documentation>Specify when the style was last updated (e.g.,
+"2007-10-26T21:32:52+02:00")</a:documentation>
+        <data type="dateTime"/>
+      </element>
+    </define>
+    <define name="info-text">
+      <optional>
+        <attribute name="xml:lang">
+          <data type="language"/>
+        </attribute>
+      </optional>
+      <text/>
+    </define>
+    <define name="legacy-attributes-dependent-style">
+      <a:documentation>Obsolete for dependent styles. Will be disallowed with CSL 1.1.</a:documentation>
+      <optional>
+        <attribute name="class">
+          <choice>
+            <value>in-text</value>
+            <value>note</value>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="default-locale">
+          <data type="language"/>
+        </attribute>
+      </optional>
+      <ref name="style-options"/>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Localization</xhtml:h2>
+    </a:documentation>
+    <define name="locale">
+      <a:documentation>CSL locale file (locales-xx-XX.xml)</a:documentation>
+      <element name="cs:locale">
+        <attribute name="xml:lang">
+          <a:documentation>Specify the locale of the locale file.</a:documentation>
+          <data type="language"/>
+        </attribute>
+        <attribute name="version" a:defaultValue="1.0">
+          <a:documentation>Set the CSL version of the locale file ("1.0" for CSL
+1.0-compatible locale files).</a:documentation>
+          <value>1.0</value>
+        </attribute>
+        <optional>
+          <ref name="info-locale"/>
+        </optional>
+        <interleave>
+          <ref name="localized-terms"/>
+          <oneOrMore>
+            <ref name="localized-dates"/>
+          </oneOrMore>
+          <ref name="localized-options"/>
+        </interleave>
+      </element>
+    </define>
+    <define name="style-locale">
+      <element name="cs:locale">
+        <a:documentation>Use to (re)define localized terms, dates and options.</a:documentation>
+        <optional>
+          <attribute name="xml:lang">
+            <a:documentation>Specify the affected locale(s). If "xml:lang" is not set, the
+"cs:locale" element affects all locales.</a:documentation>
+            <data type="language"/>
+          </attribute>
+        </optional>
+        <interleave>
+          <optional>
+            <ref name="localized-terms"/>
+          </optional>
+          <zeroOrMore>
+            <ref name="localized-dates"/>
+          </zeroOrMore>
+          <optional>
+            <ref name="localized-options"/>
+          </optional>
+        </interleave>
+      </element>
+    </define>
+    <define name="localized-terms">
+      <element name="cs:terms">
+        <oneOrMore>
+          <choice>
+            <ref name="simple-term"/>
+            <ref name="compound-term"/>
+          </choice>
+        </oneOrMore>
+      </element>
+    </define>
+    <define name="term-attributes">
+      <choice>
+        <group>
+          <attribute name="name">
+            <ref name="cs-terms"/>
+          </attribute>
+          <optional>
+            <attribute name="form" a:defaultValue="long">
+              <ref name="cs-term-forms"/>
+            </attribute>
+          </optional>
+        </group>
+        <group>
+          <attribute name="name">
+            <ref name="cs-terms.gender-variants"/>
+          </attribute>
+          <optional>
+            <attribute name="form">
+              <value>long</value>
+            </attribute>
+          </optional>
+          <attribute name="gender-form">
+            <choice>
+              <value>masculine</value>
+              <value>feminine</value>
+            </choice>
+          </attribute>
+        </group>
+        <group>
+          <attribute name="name">
+            <ref name="cs-terms.gender-assignable"/>
+          </attribute>
+          <optional>
+            <attribute name="form">
+              <value>long</value>
+            </attribute>
+          </optional>
+          <attribute name="gender">
+            <choice>
+              <value>masculine</value>
+              <value>feminine</value>
+            </choice>
+          </attribute>
+        </group>
+      </choice>
+    </define>
+    <define name="cs-term-forms">
+      <a:documentation>"verb-short" reverts to "verb" if the "verb-short" form is not available
+"symbol" reverts to "short" if the "symbol" form is not available
+"verb" and "short" revert to "long" if the specified form is not available</a:documentation>
+      <choice>
+        <value>long</value>
+        <value>verb</value>
+        <value>short</value>
+        <value>verb-short</value>
+        <value>symbol</value>
+        <ref name="cs-term-forms.extension"/>
+      </choice>
+    </define>
+    <div>
+      <a:documentation>Extension structures. You may override these in a customization schema.
+If you do, please contact the CSL project team to add the term or form to
+the official schema.</a:documentation>
+      <define name="cs-terms.extension">
+        <notAllowed/>
+      </define>
+      <define name="cs-term-forms.extension">
+        <notAllowed/>
+      </define>
+    </div>
+    <define name="simple-term">
+      <a:documentation>Simple terms are basic strings, used to represent genres, media, etc.</a:documentation>
+      <element name="cs:term">
+        <ref name="term-attributes"/>
+        <text/>
+      </element>
+    </define>
+    <define name="compound-term">
+      <a:documentation>Compound terms are those whose output can be either singular or plural. 
+Typically used for things like page number or editor labels.</a:documentation>
+      <element name="cs:term">
+        <ref name="term-attributes"/>
+        <ref name="single-term"/>
+        <ref name="multiple-term"/>
+      </element>
+    </define>
+    <define name="multiple-term">
+      <element name="cs:multiple">
+        <a:documentation>Plural version of the term.</a:documentation>
+        <text/>
+      </element>
+    </define>
+    <define name="single-term">
+      <element name="cs:single">
+        <a:documentation>Singular version of the term.</a:documentation>
+        <text/>
+      </element>
+    </define>
+    <define name="localized-dates">
+      <element name="cs:date">
+        <attribute name="form">
+          <a:documentation>Select the localized date format ("text" or "numeric") that will
+be defined.</a:documentation>
+          <choice>
+            <value>text</value>
+            <a:documentation>Text date form (e.g., "December 15, 2005" for "en-US").</a:documentation>
+            <value>numeric</value>
+            <a:documentation>Numeric date form (e.g., "12-15-2005" for "en-US").</a:documentation>
+          </choice>
+        </attribute>
+        <ref name="font-formatting"/>
+        <ref name="delimiter"/>
+        <ref name="text-case"/>
+        <oneOrMore>
+          <element name="cs:date-part">
+            <ref name="affixes"/>
+            <ref name="text-case"/>
+            <ref name="font-formatting"/>
+            <choice>
+              <ref name="month"/>
+              <ref name="day"/>
+              <ref name="year"/>
+            </choice>
+          </element>
+        </oneOrMore>
+      </element>
+    </define>
+    <define name="localized-options">
+      <a:documentation>Localized global options are specified as attributes in the
+cs:style-options element. If future versions of CSL include localized
+options that are citation or bibliography specific, the elements
+cs:citation-options and cs:bibliography-options can be added.</a:documentation>
+      <element name="cs:style-options">
+        <optional>
+          <attribute name="punctuation-in-quote" a:defaultValue="false">
+            <a:documentation>Specify whether punctuation (a period or comma) is placed within
+or outside (default) the closing quotation mark.</a:documentation>
+            <data type="boolean"/>
+          </attribute>
+        </optional>
+      </element>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Macros</xhtml:h2>
+    </a:documentation>
+    <define name="macro">
+      <element name="cs:macro">
+        <a:documentation>Use to create collections of (reusable) formatting instructions.</a:documentation>
+        <attribute name="name">
+          <data type="NMTOKEN"/>
+        </attribute>
+        <ref name="cs-element"/>
+      </element>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Citation and Bibliography</xhtml:h2>
+    </a:documentation>
+    <define name="citation">
+      <element name="cs:citation">
+        <a:documentation>Use to describe the formatting of citations.</a:documentation>
+        <interleave>
+          <ref name="citation-options"/>
+          <optional>
+            <ref name="sort"/>
+          </optional>
+        </interleave>
+        <ref name="citation-layout"/>
+      </element>
+    </define>
+    <define name="bibliography">
+      <element name="cs:bibliography">
+        <a:documentation>Use to describe the formatting of the bibliography.</a:documentation>
+        <interleave>
+          <ref name="bibliography-options"/>
+          <optional>
+            <ref name="sort"/>
+          </optional>
+        </interleave>
+        <ref name="bibliography-layout"/>
+      </element>
+    </define>
+    <define name="citation-layout">
+      <element name="cs:layout">
+        <ref name="affixes"/>
+        <ref name="font-formatting"/>
+        <ref name="delimiter"/>
+        <ref name="cs-element"/>
+      </element>
+    </define>
+    <define name="bibliography-layout">
+      <element name="cs:layout">
+        <ref name="affixes"/>
+        <ref name="font-formatting"/>
+        <ref name="cs-element"/>
+      </element>
+    </define>
+    <define name="cs-element">
+      <oneOrMore>
+        <choice>
+          <ref name="names"/>
+          <ref name="date"/>
+          <ref name="label"/>
+          <ref name="cs-text"/>
+          <ref name="cs-number"/>
+          <ref name="choose"/>
+          <ref name="group"/>
+        </choice>
+      </oneOrMore>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Contributor Names</xhtml:h2>
+    </a:documentation>
+    <define name="names-opt">
+      <a:documentation>Options affecting cs:names, for cs:style, cs:citation and cs:bibliography.</a:documentation>
+      <optional>
+        <attribute name="names-delimiter">
+          <a:documentation>Inheritable name option, companion for "delimiter" on cs:names.</a:documentation>
+        </attribute>
+      </optional>
+    </define>
+    <define name="names-attributes">
+      <ref name="affixes"/>
+      <ref name="display"/>
+      <ref name="font-formatting"/>
+      <ref name="delimiter">
+        <a:documentation>Specify the delimiter for name lists of name variables rendered by
+the same cs:names element.</a:documentation>
+      </ref>
+      <attribute name="variable">
+        <list>
+          <oneOrMore>
+            <ref name="cs-names"/>
+          </oneOrMore>
+        </list>
+      </attribute>
+    </define>
+    <define name="name-opt">
+      <a:documentation>Options affecting cs:name, for cs:style, cs:citation and cs:bibliography.</a:documentation>
+      <ref name="name-attributes"/>
+      <optional>
+        <attribute name="name-form" a:defaultValue="long">
+          <a:documentation>Inheritable name option, companion for "form" on cs:name.</a:documentation>
+          <choice>
+            <value>long</value>
+            <value>short</value>
+            <value>count</value>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="name-delimiter">
+          <a:documentation>Inheritable name option, companion for "delimiter" on cs:name.</a:documentation>
+        </attribute>
+      </optional>
+    </define>
+    <define name="name-attributes">
+      <optional>
+        <attribute name="and">
+          <a:documentation>Use to separate the second-to-last and last name of a name list by
+the "and" term or ampersand.</a:documentation>
+          <choice>
+            <value>text</value>
+            <a:documentation>Use the "and" term (e.g., "Doe, Johnson and Smith").</a:documentation>
+            <value>symbol</value>
+            <a:documentation>Use the "ampersand" (e.g., "Doe, Johnson &amp; Smith").</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="delimiter-precedes-et-al" a:defaultValue="contextual">
+          <a:documentation>Specify when the name delimiter is used between a truncated name list
+and the "et-al" (or "and others") term in case of et-al abbreviation
+(e.g., "Smith, Doe et al." or "Smith, Doe, et al.").</a:documentation>
+          <choice>
+            <value>contextual</value>
+            <a:documentation>The name delimiter is only used when the truncated name list
+consists of two or more names.</a:documentation>
+            <value>always</value>
+            <a:documentation>The name delimiter is always used.</a:documentation>
+            <value>never</value>
+            <a:documentation>The name delimiter is never used.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="delimiter-precedes-last" a:defaultValue="contextual">
+          <a:documentation>Specify when the name delimiter is used between the second-to-last
+and last name of a non-truncated name list. Only has an effect when
+the "and" term or ampersand is used (e.g., "Doe and Smith" or "Doe,
+and Smith").</a:documentation>
+          <choice>
+            <value>contextual</value>
+            <a:documentation>The name delimiter is only used when the name list consists of
+three or more names.</a:documentation>
+            <value>always</value>
+            <a:documentation>The name delimiter is always used.</a:documentation>
+            <value>never</value>
+            <a:documentation>The name delimiter is never used.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="et-al-min">
+          <a:documentation>Set the minimum number of names needed in a name variable to activate
+et-al abbreviation.</a:documentation>
+          <data type="integer"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="et-al-use-first">
+          <a:documentation>Set the number of names to render when et-al abbreviation is active.</a:documentation>
+          <data type="integer"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="et-al-subsequent-min">
+          <a:documentation>As "et-al-min", but only affecting subsequent citations to an item.</a:documentation>
+          <data type="integer"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="et-al-subsequent-use-first">
+          <a:documentation>As "et-al-use-first", but only affecting subsequent citations to an
+item.</a:documentation>
+          <data type="integer"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="et-al-use-last" a:defaultValue="false">
+          <a:documentation>If set to "true", the "et-al" (or "and others") term is replaced by
+an ellipsis followed by the last name of the name variable.</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="initialize" a:defaultValue="true">
+          <a:documentation>If set to "false", names are not initialized and "initialize-with"
+only affects initials already present in the input data.</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="initialize-with">
+          <a:documentation>Activate initializing of given names. The attribute value is appended
+to each initial (e.g., with ". ", "Orson Welles" becomes "O. Welles").</a:documentation>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="name-as-sort-order">
+          <a:documentation>Specify whether (and which) names should be rendered in their sort
+order (e.g., "Doe, John" instead of "John Doe").</a:documentation>
+          <choice>
+            <value>first</value>
+            <a:documentation>Render the first name of each name variable in sort order.</a:documentation>
+            <value>all</value>
+            <a:documentation>Render all names in sort order.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="sort-separator" a:defaultValue=", ">
+          <a:documentation>Sets the delimiter for name-parts that have switched positions as a
+result of "name-as-sort-order" (e.g., ", " in "Doe, John").</a:documentation>
+        </attribute>
+      </optional>
+    </define>
+    <define name="names">
+      <element name="cs:names">
+        <ref name="names-attributes"/>
+        <interleave>
+          <group>
+            <optional>
+              <ref name="name"/>
+            </optional>
+            <optional>
+              <ref name="et-al"/>
+            </optional>
+          </group>
+          <zeroOrMore>
+            <ref name="name-label"/>
+          </zeroOrMore>
+        </interleave>
+        <optional>
+          <ref name="substitute"/>
+        </optional>
+      </element>
+    </define>
+    <define name="names-short">
+      <a:documentation>Short version of "names" element, without children, allowed in &lt;substitute/&gt;</a:documentation>
+      <element name="cs:names">
+        <ref name="names-attributes"/>
+      </element>
+    </define>
+    <define name="name">
+      <element name="cs:name">
+        <ref name="name-attributes"/>
+        <ref name="affixes"/>
+        <ref name="font-formatting"/>
+        <optional>
+          <attribute name="form" a:defaultValue="long">
+            <a:documentation>Select the "long" (first name + last name, for Western names),
+"short" (last name only, for Western names), or "count" name form
+(returning the number of names in the name variable, which can be
+useful for some sorting algorithms).</a:documentation>
+            <choice>
+              <value>long</value>
+              <value>short</value>
+              <value>count</value>
+            </choice>
+          </attribute>
+        </optional>
+        <ref name="delimiter" a:defaultValue=", ">
+          <a:documentation>Set the delimiter for names in a name variable (e.g., ", " in
+"Doe, Smith")</a:documentation>
+        </ref>
+        <zeroOrMore>
+          <element name="cs:name-part">
+            <a:documentation>Use to format individual name parts (e.g., "Jane DOE").</a:documentation>
+            <attribute name="name">
+              <choice>
+                <value>family</value>
+                <value>given</value>
+              </choice>
+            </attribute>
+            <ref name="text-case"/>
+            <ref name="affixes"/>
+            <ref name="font-formatting"/>
+          </element>
+        </zeroOrMore>
+      </element>
+    </define>
+    <define name="name-label">
+      <a:documentation>Inherits variable from the parent cs:names element.</a:documentation>
+      <element name="cs:label">
+        <optional>
+          <attribute name="form" a:defaultValue="long">
+            <ref name="cs-term-forms"/>
+          </attribute>
+        </optional>
+        <ref name="label-primitives"/>
+      </element>
+    </define>
+    <define name="et-al">
+      <element name="cs:et-al">
+        <a:documentation>Specify the term used for et-al abbreviation and its formatting. </a:documentation>
+        <optional>
+          <attribute name="term" a:defaultValue="et-al">
+            <a:documentation>Select the term to use for et-al abbreviation.</a:documentation>
+            <choice>
+              <value>et-al</value>
+              <value>and others</value>
+            </choice>
+          </attribute>
+        </optional>
+        <ref name="affixes"/>
+        <ref name="font-formatting"/>
+      </element>
+    </define>
+    <define name="substitute">
+      <element name="cs:substitute">
+        <a:documentation>Specify substitution options when the name variables selected on the
+parent cs:names element are empty.</a:documentation>
+        <oneOrMore>
+          <choice>
+            <ref name="names-short"/>
+            <ref name="cs-element"/>
+          </choice>
+        </oneOrMore>
+      </element>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Dates</xhtml:h2>
+    </a:documentation>
+    <define name="date">
+      <element name="cs:date">
+        <attribute name="variable">
+          <ref name="cs-dates"/>
+        </attribute>
+        <choice>
+          <group>
+            <attribute name="form">
+              <a:documentation>Use to select a localized date format.</a:documentation>
+              <choice>
+                <value>text</value>
+                <a:documentation>Use the localized text form of the date (e.g., "December
+15, 2005" for en-US).</a:documentation>
+                <value>numeric</value>
+                <a:documentation>Use the localized numeric form of the date (e.g.,
+"12-15-2005" for en-US)</a:documentation>
+              </choice>
+            </attribute>
+            <optional>
+              <attribute name="date-parts" a:defaultValue="year-month-day">
+                <a:documentation>Limit the date parts rendered.</a:documentation>
+                <choice>
+                  <value>year-month-day</value>
+                  <a:documentation>Year, month and day</a:documentation>
+                  <value>year-month</value>
+                  <a:documentation>Year and month</a:documentation>
+                  <value>year</value>
+                  <a:documentation>Year only</a:documentation>
+                </choice>
+              </attribute>
+            </optional>
+            <zeroOrMore>
+              <element name="cs:date-part">
+                <a:documentation>Specify overriding formatting for localized dates (affixes
+cannot be overridden, as these are considered locale-specific).
+Example uses are forcing the use of leading-zeros, or of the
+"short" month form. Has no effect on which, and in what order,
+date parts are rendered.</a:documentation>
+                <ref name="text-case"/>
+                <ref name="font-formatting"/>
+                <choice>
+                  <ref name="month"/>
+                  <ref name="day"/>
+                  <ref name="year"/>
+                </choice>
+              </element>
+            </zeroOrMore>
+          </group>
+          <group>
+            <oneOrMore>
+              <element name="cs:date-part">
+                <a:documentation>Specify, in the desired order, the date parts that should be
+rendered and their formatting.</a:documentation>
+                <ref name="affixes"/>
+                <ref name="text-case"/>
+                <ref name="font-formatting"/>
+                <choice>
+                  <ref name="month"/>
+                  <ref name="day"/>
+                  <ref name="year"/>
+                </choice>
+              </element>
+            </oneOrMore>
+            <ref name="delimiter"/>
+          </group>
+        </choice>
+        <ref name="affixes"/>
+        <ref name="display"/>
+        <ref name="font-formatting"/>
+        <ref name="text-case"/>
+      </element>
+    </define>
+    <define name="range-delimiter">
+      <optional>
+        <attribute name="range-delimiter" a:defaultValue="–">
+          <a:documentation>Specify a delimiter for date ranges (by default the en-dash). A custom
+delimiter is retrieved from the largest date part ("day", "month" or
+"year") that differs between the two dates.</a:documentation>
+        </attribute>
+      </optional>
+    </define>
+    <define name="day">
+      <attribute name="name">
+        <value>day</value>
+      </attribute>
+      <optional>
+        <attribute name="form" a:defaultValue="numeric">
+          <a:documentation>Day forms: "numeric" ("5"), "numeric-leading-zeros" ("05"), "ordinal"
+("5th").</a:documentation>
+          <choice>
+            <value>numeric</value>
+            <value>numeric-leading-zeros</value>
+            <value>ordinal</value>
+          </choice>
+        </attribute>
+      </optional>
+      <ref name="range-delimiter"/>
+    </define>
+    <define name="month">
+      <attribute name="name">
+        <value>month</value>
+      </attribute>
+      <optional>
+        <attribute name="form" a:defaultValue="long">
+          <a:documentation>Months forms: "long" (e.g., "January"), "short" ("Jan."), "numeric"
+("1"), and "numeric-leading-zeros" ("01").</a:documentation>
+          <choice>
+            <value>long</value>
+            <value>short</value>
+            <value>numeric</value>
+            <value>numeric-leading-zeros</value>
+          </choice>
+        </attribute>
+      </optional>
+      <ref name="range-delimiter"/>
+      <ref name="strip-periods"/>
+    </define>
+    <define name="year">
+      <attribute name="name">
+        <value>year</value>
+      </attribute>
+      <optional>
+        <attribute name="form" a:defaultValue="long">
+          <a:documentation>Year forms: "long" ("2005"), "short" ("05").</a:documentation>
+          <choice>
+            <value>short</value>
+            <value>long</value>
+          </choice>
+        </attribute>
+      </optional>
+      <ref name="range-delimiter"/>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Formatting Text</xhtml:h2>
+    </a:documentation>
+    <define name="cs-text">
+      <element name="cs:text">
+        <a:documentation>Use to call macros, render variables, terms, or verbatim text.</a:documentation>
+        <ref name="affixes"/>
+        <ref name="display"/>
+        <ref name="font-formatting"/>
+        <ref name="quotes"/>
+        <ref name="strip-periods"/>
+        <ref name="text-case"/>
+        <choice>
+          <attribute name="macro">
+            <a:documentation>Select a macro.</a:documentation>
+            <data type="NMTOKEN"/>
+          </attribute>
+          <group>
+            <attribute name="term">
+              <a:documentation>Select a term.</a:documentation>
+              <ref name="cs-terms"/>
+            </attribute>
+            <optional>
+              <attribute name="form" a:defaultValue="long">
+                <ref name="cs-term-forms"/>
+              </attribute>
+            </optional>
+            <optional>
+              <attribute name="plural" a:defaultValue="false">
+                <a:documentation>Specify term plurality: singular ("false") or plural ("true").</a:documentation>
+                <data type="boolean"/>
+              </attribute>
+            </optional>
+          </group>
+          <attribute name="value">
+            <a:documentation>Specify verbatim text.</a:documentation>
+          </attribute>
+          <group>
+            <attribute name="variable">
+              <a:documentation>Select a variable.</a:documentation>
+              <ref name="cs-variables"/>
+            </attribute>
+            <optional>
+              <attribute name="form" a:defaultValue="long">
+                <choice>
+                  <value>short</value>
+                  <value>long</value>
+                </choice>
+              </attribute>
+            </optional>
+          </group>
+        </choice>
+      </element>
+    </define>
+    <define name="cs-number">
+      <element name="cs:number">
+        <a:documentation>Use to render a number variable.</a:documentation>
+        <ref name="affixes"/>
+        <ref name="display"/>
+        <ref name="font-formatting"/>
+        <ref name="text-case"/>
+        <attribute name="variable">
+          <ref name="cs-numbers"/>
+        </attribute>
+        <optional>
+          <attribute name="form" a:defaultValue="numeric">
+            <a:documentation>Number forms: "numeric" ("4"), "ordinal" ("4th"), "long-ordinal"
+("fourth"), "roman" ("iv").</a:documentation>
+            <choice>
+              <value>numeric</value>
+              <value>ordinal</value>
+              <value>long-ordinal</value>
+              <value>roman</value>
+            </choice>
+          </attribute>
+        </optional>
+      </element>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Label Text</xhtml:h2>
+    </a:documentation>
+    <define name="label">
+      <element name="cs:label">
+        <a:documentation>Use to render a term whose pluralization depends on the content of a
+variable. E.g., if "page" variable holds a range, the plural label
+"pp." is selected instead of the singular "p.".</a:documentation>
+        <ref name="label-primitives"/>
+        <attribute name="variable">
+          <choice>
+            <ref name="cs-numbers"/>
+            <value>locator</value>
+            <value>page</value>
+          </choice>
+        </attribute>
+        <optional>
+          <attribute name="form" a:defaultValue="long">
+            <choice>
+              <value>long</value>
+              <value>short</value>
+              <value>symbol</value>
+            </choice>
+          </attribute>
+        </optional>
+      </element>
+    </define>
+    <define name="label-primitives">
+      <ref name="affixes"/>
+      <ref name="font-formatting"/>
+      <ref name="text-case"/>
+      <ref name="strip-periods"/>
+      <optional>
+        <attribute name="plural" a:defaultValue="contextual">
+          <a:documentation>Specify when the plural version of a term is selected.</a:documentation>
+          <choice>
+            <value>always</value>
+            <value>never</value>
+            <value>contextual</value>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Groups</xhtml:h2>
+    </a:documentation>
+    <define name="group">
+      <element name="cs:group">
+        <a:documentation>Use to group rendering elements. Groups are useful for setting a
+delimiter for the group children, for organizing the layout of
+bibliographic entries (using the "display" attribute), and for
+suppressing the rendering of terms and verbatim text when variables
+are empty.</a:documentation>
+        <ref name="affixes"/>
+        <ref name="display"/>
+        <ref name="font-formatting"/>
+        <ref name="delimiter"/>
+        <oneOrMore>
+          <ref name="cs-element"/>
+        </oneOrMore>
+      </element>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Options</xhtml:h2>
+    </a:documentation>
+    <define name="style-options">
+      <ref name="demote-non-dropping-particle-opt"/>
+      <ref name="initialize-with-hyphen-opt"/>
+      <ref name="page-range-format-opt"/>
+      <ref name="name-opt"/>
+      <ref name="names-opt"/>
+    </define>
+    <define name="citation-options">
+      <ref name="cite-group-delimiter-opt"/>
+      <ref name="collapse-opt"/>
+      <ref name="disambiguate-opt"/>
+      <ref name="note-distance-opt"/>
+      <ref name="name-opt"/>
+      <ref name="names-opt"/>
+    </define>
+    <define name="bibliography-options">
+      <ref name="hanging-indent-opt"/>
+      <ref name="line-formatting-opt"/>
+      <ref name="second-field-align-opt"/>
+      <ref name="subsequent-author-substitute-opt"/>
+      <ref name="name-opt"/>
+      <ref name="names-opt"/>
+    </define>
+    <define name="demote-non-dropping-particle-opt">
+      <optional>
+        <attribute name="demote-non-dropping-particle" a:defaultValue="display-and-sort">
+          <a:documentation>Specify whether the non-dropping particle is demoted in inverted
+names (e.g., "Koning, W. de").</a:documentation>
+          <choice>
+            <value>never</value>
+            <value>sort-only</value>
+            <value>display-and-sort</value>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+    <define name="initialize-with-hyphen-opt">
+      <optional>
+        <attribute name="initialize-with-hyphen" a:defaultValue="true">
+          <a:documentation>Specify whether compound given names (e.g., "Jean-Luc") are
+initialized with ("J-L") or without a hyphen ("JL").</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+    </define>
+    <define name="page-range-format-opt">
+      <optional>
+        <attribute name="page-range-format">
+          <a:documentation>Reformat page ranges in the "page" variable.</a:documentation>
+          <choice>
+            <value>expanded</value>
+            <value>minimal</value>
+            <value>chicago</value>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+    <define name="cite-group-delimiter-opt">
+      <optional>
+        <attribute name="cite-group-delimiter" a:defaultValue=", ">
+          <a:documentation>Activate cite grouping and specify the delimiter for cites within a
+cite group.</a:documentation>
+        </attribute>
+      </optional>
+    </define>
+    <define name="collapse-opt">
+      <optional>
+        <attribute name="collapse">
+          <a:documentation>Activate cite grouping and specify the method of citation collapsing.</a:documentation>
+          <choice>
+            <value>citation-number</value>
+            <a:documentation>Collapse ranges of numeric cites, e.g. from "[1,2,3]" to "[1-3]".</a:documentation>
+            <value>year</value>
+            <a:documentation>Collapse cites by suppressing repeated names, e.g. from "(Doe
+2000, Doe 2001)" to "(Doe 2000, 2001)".</a:documentation>
+            <value>year-suffix</value>
+            <a:documentation>Collapse cites as with "year", but also suppresses repeated
+years, e.g. from "(Doe 2000a, Doe 2000b)" to "(Doe 2000a, b)".</a:documentation>
+            <value>year-suffix-ranged</value>
+            <a:documentation>Collapses cites as with "year-suffix", but also collapses
+ranges of year-suffixes, e.g. from "(Doe 2000a, Doe 2000b,
+Doe 2000c)" to "(Doe 2000a-c)".</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="year-suffix-delimiter">
+          <a:documentation>Specify the delimiter between year-suffixes. Defaults to the cite
+delimiter.</a:documentation>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="after-collapse-delimiter">
+          <a:documentation>Specify the delimiter following a group of collapsed cites. Defaults
+to the cite delimiter.</a:documentation>
+        </attribute>
+      </optional>
+    </define>
+    <define name="disambiguate-opt">
+      <optional>
+        <attribute name="disambiguate-add-names" a:defaultValue="false">
+          <a:documentation>Set to "true" to activate disambiguation by showing names that were
+originally hidden as a result of et-al abbreviation.</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="disambiguate-add-givenname" a:defaultValue="false">
+          <a:documentation>Set to "true" to activate disambiguation by expanding names, showing
+initials or full given names.</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="disambiguate-add-year-suffix" a:defaultValue="false">
+          <a:documentation>Set to "true" to activate disambiguation by adding year-suffixes
+(e.g., "(Doe 2007a, Doe 2007b)") for items from the same author(s)
+and year.</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="givenname-disambiguation-rule" a:defaultValue="by-cite">
+          <a:documentation>Specify how name are expanded for disambiguation.</a:documentation>
+          <choice>
+            <value>all-names</value>
+            <a:documentation>Each ambiguous names is progressively transformed until
+disambiguated (when disambiguation is not possible, the name
+remains in its original form).</a:documentation>
+            <value>all-names-with-initials</value>
+            <a:documentation>As "all-names", but name expansion is limited to showing
+initials.</a:documentation>
+            <value>primary-name</value>
+            <a:documentation>As "all-names", but disambiguation is limited to the first name
+of each cite.</a:documentation>
+            <value>primary-name-with-initials</value>
+            <a:documentation>As "all-names-with-initials", but disambiguation is limited to
+the first name of each cite.</a:documentation>
+            <value>by-cite</value>
+            <a:documentation>As "all-names", but only ambiguous names in ambiguous cites are
+expanded.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+    <define name="note-distance-opt">
+      <optional>
+        <attribute name="near-note-distance" a:defaultValue="5">
+          <a:documentation>Set the number of preceding notes (footnotes or endnotes) within
+which the current item needs to have been previously cited in order
+for the "near-note" position to be "true".</a:documentation>
+          <data type="integer"/>
+        </attribute>
+      </optional>
+    </define>
+    <define name="hanging-indent-opt">
+      <optional>
+        <attribute name="hanging-indent" a:defaultValue="false">
+          <a:documentation>Set to "true" to render bibliographic entries with hanging indents.</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+    </define>
+    <define name="line-formatting-opt">
+      <optional>
+        <attribute name="entry-spacing" a:defaultValue="1">
+          <a:documentation>Set the spacing between bibliographic entries.</a:documentation>
+          <data type="nonNegativeInteger"/>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="line-spacing" a:defaultValue="1">
+          <a:documentation>Set the spacing between bibliographic lines.</a:documentation>
+          <data type="integer">
+            <param name="minExclusive">0</param>
+          </data>
+        </attribute>
+      </optional>
+    </define>
+    <define name="second-field-align-opt">
+      <optional>
+        <attribute name="second-field-align">
+          <a:documentation>Use to align any subsequent lines of bibliographic entries with the
+beginning of the second field.</a:documentation>
+          <choice>
+            <value>flush</value>
+            <a:documentation>Align the first field with the margin.</a:documentation>
+            <value>margin</value>
+            <a:documentation>Put the first field in the margin and align all subsequent
+lines of text with the margin.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+    <define name="subsequent-author-substitute-opt">
+      <optional>
+        <attribute name="subsequent-author-substitute">
+          <a:documentation>Substitute names that repeat in subsequent bibliographic entries by
+the attribute value.</a:documentation>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="subsequent-author-substitute-rule" a:defaultValue="complete-all">
+          <a:documentation>Specify the method of substitution of names repeated in subsequent
+bibliographic entries.</a:documentation>
+          <choice>
+            <value>complete-all</value>
+            <a:documentation>Requires a match of all rendered names in the name variable, and
+substitutes once for all names.</a:documentation>
+            <value>complete-each</value>
+            <a:documentation>Requires a match of all rendered names in the name variable,
+and substitutes for each name.</a:documentation>
+            <value>partial-each</value>
+            <a:documentation>Substitutes for each name, until the first mismatch.</a:documentation>
+            <value>partial-first</value>
+            <a:documentation>Substitutes the first name if it matches.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Sorting</xhtml:h2>
+    </a:documentation>
+    <define name="all-variables">
+      <choice>
+        <ref name="cs-variables"/>
+        <ref name="cs-dates"/>
+        <ref name="cs-names"/>
+      </choice>
+    </define>
+    <define name="sort">
+      <element name="cs:sort">
+        <a:documentation>Specify how cites and bibliographic entries should be sorted. By
+default, items appear in the order in which they were cited.</a:documentation>
+        <oneOrMore>
+          <ref name="key"/>
+        </oneOrMore>
+      </element>
+    </define>
+    <define name="key">
+      <element name="cs:key">
+        <choice>
+          <attribute name="variable">
+            <ref name="all-variables"/>
+          </attribute>
+          <attribute name="macro">
+            <data type="NMTOKEN"/>
+          </attribute>
+        </choice>
+        <optional>
+          <attribute name="sort" a:defaultValue="ascending">
+            <a:documentation>Select between an ascending and descending sort.</a:documentation>
+            <choice>
+              <value>ascending</value>
+              <value>descending</value>
+            </choice>
+          </attribute>
+        </optional>
+        <optional>
+          <attribute name="names-min">
+            <a:documentation>The minimum number of names needed in a name variable to activate
+name list truncation. Overrides the values set on any
+"et-al-(subsequent-)min" attributes.</a:documentation>
+            <data type="integer"/>
+          </attribute>
+        </optional>
+        <optional>
+          <attribute name="names-use-first">
+            <a:documentation>The number of names to render when name list truncation is
+activated. Overrides the values set on the
+"et-al-(subsequent-)use-first" attributes.</a:documentation>
+            <data type="integer"/>
+          </attribute>
+        </optional>
+        <optional>
+          <attribute name="names-use-last">
+            <a:documentation>Use to override the value of the "et-at-use-last" attribute.</a:documentation>
+            <data type="boolean"/>
+          </attribute>
+        </optional>
+      </element>
+    </define>
+  </div>
+  <div>
+    <a:documentation>
+      <xhtml:h2>Conditional Statements</xhtml:h2>
+    </a:documentation>
+    <define name="choose">
+      <element name="cs:choose">
+        <a:documentation>Use to conditionally render rendering elements.</a:documentation>
+        <ref name="if"/>
+        <zeroOrMore>
+          <ref name="else-if"/>
+        </zeroOrMore>
+        <optional>
+          <ref name="else"/>
+        </optional>
+      </element>
+    </define>
+    <define name="if">
+      <element name="cs:if">
+        <oneOrMore>
+          <ref name="condition"/>
+        </oneOrMore>
+        <ref name="match"/>
+        <zeroOrMore>
+          <ref name="cs-element"/>
+        </zeroOrMore>
+      </element>
+    </define>
+    <define name="else-if">
+      <element name="cs:else-if">
+        <oneOrMore>
+          <ref name="condition"/>
+        </oneOrMore>
+        <ref name="match"/>
+        <zeroOrMore>
+          <ref name="cs-element"/>
+        </zeroOrMore>
+      </element>
+    </define>
+    <define name="else">
+      <element name="cs:else">
+        <oneOrMore>
+          <ref name="cs-element"/>
+        </oneOrMore>
+      </element>
+    </define>
+    <define name="condition">
+      <choice>
+        <attribute name="disambiguate" a:defaultValue="true">
+          <a:documentation>If used, the element content is only rendered if it disambiguates two
+otherwise identical citations. This attempt at disambiguation is only
+made after all other disambiguation methods have failed.</a:documentation>
+          <value>true</value>
+        </attribute>
+        <attribute name="is-numeric">
+          <a:documentation>Tests whether the given variables contain numeric text.</a:documentation>
+          <list>
+            <oneOrMore>
+              <ref name="all-variables"/>
+            </oneOrMore>
+          </list>
+        </attribute>
+        <attribute name="is-uncertain-date">
+          <a:documentation>Tests whether the given date variables contain approximate dates.</a:documentation>
+          <list>
+            <oneOrMore>
+              <ref name="cs-dates"/>
+            </oneOrMore>
+          </list>
+        </attribute>
+        <attribute name="locator">
+          <a:documentation>Tests whether the locator matches the given locator types.</a:documentation>
+          <list>
+            <oneOrMore>
+              <choice>
+                <ref name="cs-terms.locator"/>
+                <value>sub-verbo</value>
+              </choice>
+            </oneOrMore>
+          </list>
+        </attribute>
+        <attribute name="position">
+          <a:documentation>Tests whether the cite position matches the given positions.</a:documentation>
+          <list>
+            <oneOrMore>
+              <choice>
+                <value>first</value>
+                <value>subsequent</value>
+                <value>ibid</value>
+                <value>ibid-with-locator</value>
+                <value>near-note</value>
+              </choice>
+            </oneOrMore>
+          </list>
+        </attribute>
+        <attribute name="type">
+          <a:documentation>Tests whether the item matches the given types.</a:documentation>
+          <list>
+            <oneOrMore>
+              <ref name="cs-types"/>
+            </oneOrMore>
+          </list>
+        </attribute>
+        <attribute name="variable">
+          <a:documentation>Tests whether the default ("long") forms of the given variables
+contain non-empty values.</a:documentation>
+          <list>
+            <oneOrMore>
+              <ref name="all-variables"/>
+            </oneOrMore>
+          </list>
+        </attribute>
+      </choice>
+    </define>
+    <define name="match">
+      <optional>
+        <attribute name="match" a:defaultValue="all">
+          <a:documentation>Set the testing logic.</a:documentation>
+          <choice>
+            <value>all</value>
+            <a:documentation>Element only tests "true" when all conditions test "true" for all
+given test values.</a:documentation>
+            <value>any</value>
+            <a:documentation>Element tests "true" when any condition tests "true" for any given
+test value.</a:documentation>
+            <value>none</value>
+            <a:documentation>Element only tests "true" when none of the conditions test "true"
+for any given test value.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+  </div>
+  <div>
+    <a:documentation>Formatting attributes.</a:documentation>
+    <define name="affixes">
+      <optional>
+        <attribute name="prefix" a:defaultValue=""/>
+      </optional>
+      <optional>
+        <attribute name="suffix" a:defaultValue=""/>
+      </optional>
+    </define>
+    <define name="delimiter">
+      <optional>
+        <attribute name="delimiter"/>
+      </optional>
+    </define>
+    <define name="display">
+      <optional>
+        <attribute name="display">
+          <a:documentation>By default, bibliographic entries consist of continuous runs of text.
+With the "display" attribute, portions of each entry can be
+individually positioned.</a:documentation>
+          <choice>
+            <value>block</value>
+            <a:documentation>Places the content in a block stretching from margin to margin.</a:documentation>
+            <value>left-margin</value>
+            <a:documentation>Places the content in a block starting at the left margin.</a:documentation>
+            <value>right-inline</value>
+            <a:documentation>Places the content in a block to the right of a preceding
+"left-margin" block.</a:documentation>
+            <value>indent</value>
+            <a:documentation>Places the content in a block indented to the right by a standard
+amount.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+    <define name="font-formatting">
+      <a:documentation>The font-formatting attributes are based on those of CSS and XSL-FO.</a:documentation>
+      <optional>
+        <attribute name="font-style" a:defaultValue="normal">
+          <choice>
+            <value>italic</value>
+            <value>normal</value>
+            <value>oblique</value>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="font-variant" a:defaultValue="normal">
+          <choice>
+            <value>normal</value>
+            <value>small-caps</value>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="font-weight" a:defaultValue="normal">
+          <choice>
+            <value>normal</value>
+            <value>bold</value>
+            <value>light</value>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="text-decoration" a:defaultValue="none">
+          <choice>
+            <value>none</value>
+            <value>underline</value>
+          </choice>
+        </attribute>
+      </optional>
+      <optional>
+        <attribute name="vertical-align" a:defaultValue="baseline">
+          <choice>
+            <value>baseline</value>
+            <value>sup</value>
+            <value>sub</value>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+    <define name="quotes">
+      <optional>
+        <attribute name="quotes" a:defaultValue="false">
+          <a:documentation>When set to "true", quotes are placed around the rendered text.</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+    </define>
+    <define name="strip-periods">
+      <optional>
+        <attribute name="strip-periods" a:defaultValue="false">
+          <a:documentation>When set to "true", periods are removed from the rendered text.</a:documentation>
+          <data type="boolean"/>
+        </attribute>
+      </optional>
+    </define>
+    <define name="text-case">
+      <optional>
+        <attribute name="text-case">
+          <choice>
+            <value>lowercase</value>
+            <a:documentation>Renders text in lowercase.</a:documentation>
+            <value>uppercase</value>
+            <a:documentation>Renders text in uppercase.</a:documentation>
+            <value>capitalize-first</value>
+            <a:documentation>Capitalizes the first character (other characters remain in
+their original case).</a:documentation>
+            <value>capitalize-all</value>
+            <a:documentation>Capitalizes the first character of every word (other characters
+remain in their original case).</a:documentation>
+            <value>title</value>
+            <a:documentation>Renders text in title case.</a:documentation>
+            <value>sentence</value>
+            <a:documentation>Renders text in sentence case.</a:documentation>
+          </choice>
+        </attribute>
+      </optional>
+    </define>
+  </div>
+</grammar>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/american-medical-association.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only" default-locale="en-US">
+  <info>
+    <title>American Medical Association (AMA)</title>
+    <id>http://www.zotero.org/styles/american-medical-association</id>
+    <link href="http://www.zotero.org/styles/american-medical-association" rel="self"/>
+    <link href="http://www.samford.edu/schools/pharmacy/dic/amaquickref07.pdf" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <category citation-format="numeric"/>
+    <category field="medicine"/>
+    <summary>The American Medical Association style as used in JAMA.</summary>
+    <updated>2012-09-30T23:10:36+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <macro name="editor">
+    <names variable="editor">
+      <name name-as-sort-order="all" sort-separator=" " initialize-with="" delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="author">
+    <group suffix=".">
+      <names variable="author">
+        <name name-as-sort-order="all" sort-separator=" " initialize-with="" delimiter=", " delimiter-precedes-last="always"/>
+        <label form="short" prefix=", "/>
+        <substitute>
+          <names variable="editor"/>
+          <text macro="title"/>
+        </substitute>
+      </names>
+    </group>
+  </macro>
+  <macro name="author-short">
+    <names variable="author">
+      <name form="short" and="symbol" delimiter=", " initialize-with="."/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if type="article-newspaper" match="none">
+        <choose>
+          <if variable="DOI">
+            <text value="doi:"/>
+            <text variable="DOI"/>
+          </if>
+          <else-if variable="URL">
+            <text value="Available at:" suffix=" "/>
+            <group delimiter=". ">
+              <text variable="URL"/>
+              <group>
+                <text term="accessed" text-case="capitalize-first" suffix=" "/>
+                <date variable="accessed">
+                  <date-part name="month" suffix=" "/>
+                  <date-part name="day" suffix=", "/>
+                  <date-part name="year"/>
+                </date>
+              </group>
+            </group>
+          </else-if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <text variable="title" font-style="italic"/>
+      </if>
+      <else>
+        <text variable="title"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": ">
+      <text variable="publisher-place"/>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="year-date">
+    <group prefix=" ">
+      <choose>
+        <if variable="issued">
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </if>
+        <else>
+          <text term="no date" form="short"/>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition" suffix="."/>
+      </else>
+    </choose>
+  </macro>
+  <citation collapse="citation-number">
+    <sort>
+      <key variable="citation-number"/>
+    </sort>
+    <layout delimiter="," vertical-align="sup">
+      <text variable="citation-number"/>
+      <group prefix="(" suffix=")">
+        <label variable="locator" form="short" strip-periods="true"/>
+        <text variable="locator"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="false" et-al-min="7" et-al-use-first="3">
+    <layout>
+      <text variable="citation-number" suffix=". "/>
+      <text macro="author"/>
+      <text macro="title" prefix=" " suffix="."/>
+      <choose>
+        <if type="bill book graphic legislation motion_picture report song" match="any">
+          <group suffix="." prefix=" " delimiter=" ">
+            <text macro="edition"/>
+            <text macro="editor" prefix="(" suffix=")"/>
+          </group>
+          <text prefix=" " macro="publisher"/>
+          <group suffix="." prefix="; ">
+            <date variable="issued">
+              <date-part name="year"/>
+            </date>
+            <text variable="page" prefix=":"/>
+          </group>
+        </if>
+        <else-if type="chapter paper-conference" match="any">
+          <group prefix=" ">
+            <text term="in" text-case="capitalize-first" suffix=": "/>
+            <text macro="editor"/>
+            <text variable="container-title" font-style="italic" prefix=" " suffix="."/>
+            <text variable="volume" prefix="Vol " suffix="."/>
+            <text macro="edition" prefix=" "/>
+            <text variable="collection-title" prefix=" " suffix="."/>
+            <group suffix=".">
+              <text macro="publisher" prefix=" "/>
+              <group suffix="." prefix="; ">
+                <date variable="issued">
+                  <date-part name="year"/>
+                </date>
+                <text variable="page" prefix=":"/>
+              </group>
+            </group>
+          </group>
+        </else-if>
+        <else-if type="article-newspaper">
+          <text variable="container-title" font-style="italic" prefix=" " suffix=". "/>
+          <choose>
+            <if variable="URL">
+              <group delimiter=". " suffix=".">
+                <text variable="URL"/>
+                <group prefix="Published ">
+                  <date variable="issued">
+                    <date-part name="month" suffix=" "/>
+                    <date-part name="day" suffix=", "/>
+                    <date-part name="year"/>
+                  </date>
+                </group>
+                <group>
+                  <text term="accessed" text-case="capitalize-first" suffix=" "/>
+                  <date variable="accessed">
+                    <date-part name="month" suffix=" "/>
+                    <date-part name="day" suffix=", "/>
+                    <date-part name="year"/>
+                  </date>
+                </group>
+              </group>
+            </if>
+            <else>
+              <group delimiter=":" suffix=".">
+                <group>
+                  <date variable="issued">
+                    <date-part name="month" suffix=" "/>
+                    <date-part name="day" suffix=", "/>
+                    <date-part name="year"/>
+                  </date>
+                </group>
+                <text variable="page"/>
+              </group>
+            </else>
+          </choose>
+        </else-if>
+        <else-if type="legal_case">
+          <group suffix="," prefix=" " delimiter=" ">
+            <text macro="editor" prefix="(" suffix=")"/>
+          </group>
+          <group prefix=" " delimiter=" ">
+            <text variable="container-title"/>
+            <text variable="volume"/>
+          </group>
+          <text variable="page" prefix=", " suffix=" "/>
+          <group prefix="(" suffix=")." delimiter=" ">
+            <text variable="authority"/>
+            <date variable="issued">
+              <date-part name="year"/>
+            </date>
+          </group>
+        </else-if>
+        <else>
+          <text macro="editor" prefix=" " suffix="."/>
+          <group prefix=" " suffix=".">
+            <text variable="container-title" font-style="italic" form="short" suffix="."/>
+            <group delimiter=";" prefix=" ">
+              <date variable="issued">
+                <date-part name="year"/>
+              </date>
+              <group>
+                <text variable="volume"/>
+                <text variable="issue" prefix="(" suffix=")"/>
+              </group>
+            </group>
+            <text variable="page" prefix=":"/>
+          </group>
+        </else>
+      </choose>
+      <text prefix=" " macro="access" suffix="."/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/apa.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="never">
+  <!-- This style was edited with the Visual CSL Editor (http://steveridout.com/csl/visualEditor/) -->
+  <info>
+    <title>American Psychological Association 6th Edition</title>
+    <id>http://www.zotero.org/styles/apa</id>
+    <link href="http://www.zotero.org/styles/apa" rel="self"/>
+    <link href="http://owl.english.purdue.edu/owl/resource/560/01/" rel="documentation"/>
+    <author>
+      <name>Simon Kornblith</name>
+      <email>simon@simonster.com</email>
+    </author>
+    <contributor>
+      <name>Bruce D'Arcus</name>
+    </contributor>
+    <contributor>
+      <name>Curtis M. Humphrey</name>
+    </contributor>
+    <contributor>
+      <name>Richard Karnesky</name>
+      <email>karnesky+zotero@gmail.com</email>
+      <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
+    </contributor>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <category citation-format="author-date"/>
+    <category field="psychology"/>
+    <category field="generic-base"/>
+    <updated>2012-09-27T22:06:38+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="editortranslator" form="short">
+        <single>ed. &amp; trans.</single>
+        <multiple>eds. &amp; trans.</multiple>
+      </term>
+      <term name="translator" form="short">
+        <single>trans.</single>
+        <multiple>trans.</multiple>
+      </term>
+    </terms>
+  </locale>
+  <macro name="container-contributors">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <names variable="editor translator" delimiter=", " suffix=", ">
+          <name and="symbol" initialize-with=". " delimiter=", "/>
+          <label form="short" prefix=" (" text-case="title" suffix=")"/>
+        </names>
+      </if>
+    </choose>
+  </macro>
+  <macro name="secondary-contributors">
+    <choose>
+      <if type="chapter paper-conference" match="none">
+        <names variable="translator editor" delimiter=", " prefix=" (" suffix=")">
+          <name and="symbol" initialize-with=". " delimiter=", "/>
+          <label form="short" prefix=", " text-case="title" suffix=""/>
+        </names>
+      </if>
+    </choose>
+  </macro>
+  <macro name="author">
+    <names variable="author">
+      <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=" (" suffix=")" text-case="capitalize-first"/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <choose>
+          <if type="report">
+            <text variable="publisher"/>
+            <text macro="title"/>
+          </if>
+          <else>
+            <text macro="title"/>
+          </else>
+        </choose>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="author-short">
+    <names variable="author">
+      <name form="short" and="symbol" delimiter=", " initialize-with=". "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <choose>
+          <if type="report">
+            <text variable="publisher"/>
+            <text variable="title" form="short" font-style="italic"/>
+          </if>
+          <else-if type="bill book graphic legal_case legislation motion_picture song" match="any">
+            <text variable="title" form="short" font-style="italic"/>
+          </else-if>
+          <else>
+            <text variable="title" form="short" quotes="true"/>
+          </else>
+        </choose>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if type="thesis">
+        <choose>
+          <if variable="archive" match="any">
+            <group>
+              <text term="retrieved" text-case="capitalize-first" suffix=" "/>
+              <text term="from" suffix=" "/>
+              <text variable="archive" suffix="."/>
+              <text variable="archive_location" prefix=" (" suffix=")"/>
+            </group>
+          </if>
+          <else>
+            <group>
+              <text term="retrieved" text-case="capitalize-first" suffix=" "/>
+              <text term="from" suffix=" "/>
+              <text variable="URL"/>
+            </group>
+          </else>
+        </choose>
+      </if>
+      <else>
+        <choose>
+          <if variable="DOI">
+            <text variable="DOI" prefix="doi:"/>
+          </if>
+          <else>
+            <choose>
+              <if type="webpage">
+                <group delimiter=" ">
+                  <text term="retrieved" text-case="capitalize-first" suffix=" "/>
+                  <group>
+                    <date variable="accessed" form="text" suffix=", "/>
+                  </group>
+                  <text term="from"/>
+                  <text variable="URL"/>
+                </group>
+              </if>
+              <else>
+                <group>
+                  <text term="retrieved" text-case="capitalize-first" suffix=" "/>
+                  <text term="from" suffix=" "/>
+                  <text variable="URL"/>
+                </group>
+              </else>
+            </choose>
+          </else>
+        </choose>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="report thesis" match="any">
+        <text variable="title" font-style="italic"/>
+        <group prefix=" (" suffix=")" delimiter=" ">
+          <text variable="genre"/>
+          <text variable="number" prefix="No. "/>
+        </group>
+      </if>
+      <else-if type="book graphic  motion_picture report song manuscript speech" match="any">
+        <text variable="title" font-style="italic"/>
+      </else-if>
+      <else>
+        <text variable="title"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <choose>
+      <if type="report" match="any">
+        <group delimiter=": ">
+          <text variable="publisher-place"/>
+          <text variable="publisher"/>
+        </group>
+      </if>
+      <else-if type="thesis" match="any">
+        <group delimiter=", ">
+          <text variable="publisher"/>
+          <text variable="publisher-place"/>
+        </group>
+      </else-if>
+      <else>
+        <group delimiter=", ">
+          <choose>
+            <if variable="event" match="none">
+              <text variable="genre"/>
+            </if>
+          </choose>
+          <choose>
+            <if type="article-journal article-magazine" match="none">
+              <group delimiter=": ">
+                <text variable="publisher-place"/>
+                <text variable="publisher"/>
+              </group>
+            </if>
+          </choose>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="event">
+    <choose>
+      <if variable="event">
+        <choose>
+          <if variable="genre" match="none">
+            <text term="presented at" text-case="capitalize-first" suffix=" "/>
+            <text variable="event"/>
+          </if>
+          <else>
+            <group delimiter=" ">
+              <text variable="genre" text-case="capitalize-first"/>
+              <text term="presented at"/>
+              <text variable="event"/>
+            </group>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issued">
+    <choose>
+      <if type="bill legal_case legislation" match="none">
+        <choose>
+          <if variable="issued">
+            <group prefix=" (" suffix=")">
+              <date variable="issued">
+                <date-part name="year"/>
+              </date>
+              <text variable="year-suffix"/>
+              <choose>
+                <if type="article-journal bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="none">
+                  <date variable="issued">
+                    <date-part prefix=", " name="month"/>
+                    <date-part prefix=" " name="day"/>
+                  </date>
+                </if>
+              </choose>
+            </group>
+          </if>
+          <else>
+            <group prefix=" (" suffix=")">
+              <text term="no date" form="short"/>
+              <text variable="year-suffix" prefix="-"/>
+            </group>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issued-sort">
+    <choose>
+      <if type="article-journal bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="none">
+        <date variable="issued">
+          <date-part name="year"/>
+          <date-part name="month"/>
+          <date-part name="day"/>
+        </date>
+      </if>
+      <else>
+        <date variable="issued">
+          <date-part name="year"/>
+        </date>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issued-year">
+    <choose>
+      <if variable="issued">
+        <date variable="issued">
+          <date-part name="year"/>
+        </date>
+        <text variable="year-suffix"/>
+      </if>
+      <else>
+        <text term="no date" form="short"/>
+        <text variable="year-suffix" prefix="-"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition" suffix="."/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="locators">
+    <choose>
+      <if type="article-journal article-magazine" match="any">
+        <group prefix=", " delimiter=", ">
+          <group>
+            <text variable="volume" font-style="italic"/>
+            <text variable="issue" prefix="(" suffix=")"/>
+          </group>
+          <text variable="page"/>
+        </group>
+      </if>
+      <else-if type="article-newspaper">
+        <group delimiter=" " prefix=", ">
+          <label variable="page" form="short"/>
+          <text variable="page"/>
+        </group>
+      </else-if>
+      <else-if type="book graphic motion_picture report song chapter paper-conference" match="any">
+        <group prefix=" (" suffix=")" delimiter=", ">
+          <text macro="edition"/>
+          <group>
+            <text term="volume" form="short" plural="true" text-case="capitalize-first" suffix=" "/>
+            <number variable="number-of-volumes" form="numeric" prefix="1-"/>
+          </group>
+          <group>
+            <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
+            <number variable="volume" form="numeric"/>
+          </group>
+          <group>
+            <label variable="page" form="short" suffix=" "/>
+            <text variable="page"/>
+          </group>
+        </group>
+      </else-if>
+      <else-if type="legal_case">
+        <group prefix=" (" suffix=")" delimiter=" ">
+          <text variable="authority"/>
+          <date variable="issued" form="text"/>
+        </group>
+      </else-if>
+      <else-if type="bill legislation" match="any">
+        <date variable="issued" prefix=" (" suffix=")">
+          <date-part name="year"/>
+        </date>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="citation-locator">
+    <group>
+      <choose>
+        <if locator="chapter">
+          <label variable="locator" form="long" text-case="capitalize-first"/>
+        </if>
+        <else>
+          <label variable="locator" form="short"/>
+        </else>
+      </choose>
+      <text variable="locator" prefix=" "/>
+    </group>
+  </macro>
+  <macro name="container">
+    <group>
+      <choose>
+        <if type="chapter paper-conference entry-encyclopedia" match="any">
+          <text term="in" text-case="capitalize-first" suffix=" "/>
+        </if>
+      </choose>
+      <text macro="container-contributors"/>
+      <text macro="secondary-contributors"/>
+      <text macro="container-title"/>
+    </group>
+  </macro>
+  <macro name="container-title">
+    <choose>
+      <if type="bill legal_case legislation" match="none">
+        <text variable="container-title" font-style="italic"/>
+      </if>
+      <else>
+        <group delimiter=" " prefix=", ">
+          <choose>
+            <if variable="container-title">
+              <text variable="volume"/>
+              <text variable="container-title"/>
+              <group delimiter=" ">
+                <!--change to label variable="section" as that becomes available -->
+                <text term="section" form="symbol"/>
+                <text variable="section"/>
+              </group>
+              <text variable="page"/>
+            </if>
+            <else>
+              <choose>
+                <if type="legal_case">
+                  <text variable="number" prefix="No. "/>
+                </if>
+                <else>
+                  <text variable="number" prefix="Pub. L. No. "/>
+                  <group delimiter=" ">
+                    <!--change to label variable="section" as that becomes available -->
+                    <text term="section" form="symbol"/>
+                    <text variable="section"/>
+                  </group>
+                </else>
+              </choose>
+            </else>
+          </choose>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <citation et-al-min="6" et-al-use-first="1" et-al-subsequent-min="3" et-al-subsequent-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" collapse="year" givenname-disambiguation-rule="primary-name">
+    <sort>
+      <key macro="author"/>
+      <key macro="issued-sort"/>
+    </sort>
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=", ">
+        <text macro="author-short"/>
+        <text macro="issued-year"/>
+        <text macro="citation-locator"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="8" et-al-use-first="6" et-al-use-last="true" entry-spacing="0" line-spacing="2">
+    <sort>
+      <key macro="author"/>
+      <key macro="issued-sort" sort="ascending"/>
+    </sort>
+    <layout>
+      <group suffix=".">
+        <group delimiter=". ">
+          <text macro="author"/>
+          <text macro="issued"/>
+          <text macro="title" prefix=" "/>
+          <text macro="container"/>
+        </group>
+        <text macro="locators"/>
+        <group delimiter=", " prefix=". ">
+          <text macro="event"/>
+          <text macro="publisher"/>
+        </group>
+      </group>
+      <text macro="access" prefix=" "/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/apsa.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" page-range-format="chicago" demote-non-dropping-particle="sort-only">
+  <!-- This style was edited with the Visual CSL Editor (http://steveridout.com/csl/visualEditor/) -->
+  <info>
+    <title>American Political Science Association</title>
+    <id>http://www.zotero.org/styles/apsa</id>
+    <link href="http://www.zotero.org/styles/apsa" rel="self"/>
+    <link href="http://www.apsanet.org/media/PDFs/Publications/APSAStyleManual2006.pdf" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <category citation-format="author-date"/>
+    <category field="political_science"/>
+    <summary>The American Political Science Association style.</summary>
+    <updated>2012-09-14T22:11:27+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en-US">
+    <date form="text">
+      <date-part name="month" suffix=" "/>
+      <date-part name="day" suffix=", "/>
+      <date-part name="year"/>
+    </date>
+  </locale>
+  <locale xml:lang="nb-NO">
+    <date form="text">
+      <date-part name="day" suffix=" "/>
+      <date-part name="month" suffix=" "/>
+      <date-part name="year"/>
+    </date>
+  </locale>
+  <locale xml:lang="nn-NO">
+    <date form="text">
+      <date-part name="day" suffix=" "/>
+      <date-part name="month" suffix=" "/>
+      <date-part name="year"/>
+    </date>
+  </locale>
+  <macro name="editor">
+    <names variable="editor" delimiter=", ">
+      <label form="short" text-case="lowercase" suffix=". " strip-periods="true"/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="author">
+    <names variable="author">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", " suffix="." text-case="lowercase" strip-periods="true"/>
+      <substitute>
+        <names variable="editor"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="author-short">
+    <names variable="author">
+      <name form="short" and="text" delimiter=", " initialize-with=". " sort-separator=", "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if type="legal_case" match="none">
+        <choose>
+          <if variable="URL">
+            <group delimiter=" ">
+              <text variable="URL"/>
+              <group prefix="(" suffix=")">
+                <date variable="accessed" form="text"/>
+              </group>
+            </group>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <text variable="title" font-style="italic" text-case="title"/>
+      </if>
+      <else>
+        <text variable="title" quotes="true" text-case="title"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="legal_case">
+    <group prefix=" " delimiter=" ">
+      <text variable="volume"/>
+      <text variable="container-title"/>
+    </group>
+    <text variable="authority" prefix=" (" suffix=")"/>
+  </macro>
+  <macro name="publisher">
+    <choose>
+      <if type="thesis" match="none">
+        <group delimiter=": ">
+          <text variable="publisher-place"/>
+          <text variable="publisher"/>
+        </group>
+        <text variable="genre" prefix=". "/>
+      </if>
+      <else>
+        <group delimiter=". ">
+          <text variable="genre"/>
+          <text variable="publisher"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="year-date">
+    <choose>
+      <if variable="issued">
+        <date variable="issued">
+          <date-part name="year"/>
+        </date>
+      </if>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short" suffix="." strip-periods="true"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition" suffix="."/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="locator">
+    <choose>
+      <if locator="page">
+        <text variable="locator"/>
+      </if>
+      <else>
+        <group delimiter=" ">
+          <label variable="locator" form="short"/>
+          <text variable="locator"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" givenname-disambiguation-rule="primary-name" collapse="year">
+    <sort>
+      <key macro="author-short"/>
+      <key macro="year-date"/>
+    </sort>
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=", ">
+        <group delimiter=" ">
+          <text macro="author-short"/>
+          <text macro="year-date"/>
+        </group>
+        <text macro="locator"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" subsequent-author-substitute="&#8212;&#8212;&#8212;">
+    <sort>
+      <key macro="author"/>
+      <key macro="year-date"/>
+      <key variable="title"/>
+    </sort>
+    <layout suffix=".">
+      <text macro="author" suffix="."/>
+      <date variable="issued" prefix=" " suffix=".">
+        <date-part name="year"/>
+      </date>
+      <choose>
+        <if type="bill book graphic legal_case legislation manuscript motion_picture report song thesis" match="any">
+          <text macro="legal_case"/>
+          <group prefix=" " delimiter=" ">
+            <text macro="title" suffix="."/>
+            <text macro="edition"/>
+            <text macro="editor" suffix="."/>
+          </group>
+          <text prefix=" " suffix="." macro="publisher"/>
+        </if>
+        <else-if type="chapter paper-conference" match="any">
+          <text macro="title" prefix=" " suffix="."/>
+          <group prefix=" " delimiter=" ">
+            <text term="in" text-case="capitalize-first"/>
+            <text variable="container-title" font-style="italic" suffix=","/>
+            <text variable="collection-title" suffix=","/>
+            <text macro="editor" suffix="."/>
+            <group suffix=".">
+              <text macro="publisher"/>
+              <text variable="page" prefix=", "/>
+            </group>
+          </group>
+        </else-if>
+        <else>
+          <group prefix=" " delimiter=" " suffix=".">
+            <text macro="title"/>
+            <text macro="editor"/>
+          </group>
+          <choose>
+            <if type="speech">
+              <group prefix=" " delimiter=" " suffix=".">
+                <text term="presented at" text-case="capitalize-first"/>
+                <group delimiter=", ">
+                  <text variable="event"/>
+                  <text variable="event-place"/>
+                </group>
+              </group>
+            </if>
+          </choose>
+          <group prefix=" " suffix=".">
+            <text variable="container-title" font-style="italic"/>
+            <group prefix=" ">
+              <text variable="volume"/>
+              <text variable="issue" prefix="(" suffix=")"/>
+            </group>
+            <text variable="page" prefix=": "/>
+          </group>
+        </else>
+      </choose>
+      <text prefix=" " macro="access" suffix="."/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/asa.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only" page-range-format="chicago">
+  <info>
+    <title>American Sociological Association</title>
+    <id>http://www.zotero.org/styles/asa</id>
+    <link href="http://www.zotero.org/styles/asa" rel="self"/>
+    <link href="http://www.asanet.org/Quick%20Style%20Guide.pdf" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <category citation-format="author-date"/>
+    <category field="sociology"/>
+    <summary>The ASA style.</summary>
+    <updated>2012-09-27T22:06:38+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <macro name="editor">
+    <names variable="editor">
+      <label form="verb" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="series-editor">
+    <names variable="original-author">
+      <label form="short" text-case="capitalize-first" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="anon">
+    <text term="anonymous" form="short" text-case="capitalize-first" strip-periods="true"/>
+  </macro>
+  <macro name="author">
+    <names variable="author">
+      <name and="text" name-as-sort-order="first" sort-separator=", " delimiter=", " delimiter-precedes-last="always" initialize="false" initialize-with=". "/>
+      <label form="short" prefix=", "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <choose>
+          <if type="report">
+            <text variable="publisher"/>
+          </if>
+        </choose>
+        <text macro="anon"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="author-short">
+    <names variable="author">
+      <name form="short" and="text" delimiter=", " initialize-with=". "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <choose>
+          <if type="report">
+            <text variable="publisher"/>
+          </if>
+        </choose>
+        <text macro="anon"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="access">
+    <group>
+      <choose>
+        <if variable="URL">
+          <text term="retrieved" text-case="capitalize-first" suffix=" "/>
+          <date variable="accessed">
+            <date-part name="month" suffix=" "/>
+            <date-part name="day" suffix=", "/>
+            <date-part name="year"/>
+          </date>
+          <group prefix=" (" suffix=")">
+            <text variable="URL"/>
+          </group>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="thesis">
+        <text variable="title"/>
+      </if>
+      <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <text variable="title" font-style="italic"/>
+      </else-if>
+      <else>
+        <text variable="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": ">
+      <text variable="publisher-place"/>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="year-date">
+    <choose>
+      <if variable="issued">
+        <date variable="issued">
+          <date-part name="year"/>
+        </date>
+      </if>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="day-month">
+    <date variable="issued">
+      <date-part name="month"/>
+      <date-part name="day" prefix=" "/>
+    </date>
+  </macro>
+  <macro name="pages">
+    <label variable="page" form="short" suffix=" " text-case="capitalize-first"/>
+    <text variable="page"/>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition" suffix="."/>
+      </else>
+    </choose>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" et-al-subsequent-min="3" et-al-subsequent-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" collapse="year">
+    <sort>
+      <key macro="author-short"/>
+      <key macro="year-date"/>
+    </sort>
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=":">
+        <group delimiter=" ">
+          <text macro="author-short"/>
+          <text macro="year-date"/>
+        </group>
+        <text variable="locator"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="6" et-al-use-first="1">
+    <sort>
+      <key macro="author"/>
+      <key macro="year-date"/>
+      <key variable="title"/>
+    </sort>
+    <layout suffix=".">
+      <group delimiter=" ">
+        <text macro="author" suffix="."/>
+        <text macro="year-date" suffix="."/>
+      </group>
+      <choose>
+        <if type="article-newspaper article-magazine" match="any">
+          <group delimiter=" ">
+            <text macro="title" prefix=" " suffix="."/>
+          </group>
+          <group prefix=" " delimiter=", ">
+            <text variable="container-title" font-style="italic"/>
+            <text macro="day-month"/>
+            <text variable="edition"/>
+            <text variable="page"/>
+          </group>
+        </if>
+        <else-if type="thesis">
+          <text macro="title" prefix=" " suffix="." quotes="true"/>
+          <group prefix=" " delimiter=", ">
+            <text macro="edition"/>
+            <text macro="editor" suffix="."/>
+            <text variable="genre"/>
+            <text macro="publisher"/>
+          </group>
+        </else-if>
+        <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+          <group delimiter=" ">
+            <text macro="title" prefix=" " suffix="."/>
+            <text macro="edition"/>
+            <text macro="editor" suffix="."/>
+            <text macro="publisher"/>
+          </group>
+        </else-if>
+        <else-if type="chapter paper-conference" match="any">
+          <group delimiter=" ">
+            <text macro="title" prefix=" " suffix="."/>
+            <group delimiter=", " suffix=".">
+              <group delimiter=" ">
+                <text macro="pages"/>
+                <text term="in" text-case="lowercase"/>
+                <text variable="container-title" font-style="italic"/>
+              </group>
+              <text variable="volume" prefix="vol. "/>
+              <text variable="collection-title" font-style="italic"/>
+              <text macro="editor"/>
+            </group>
+            <text macro="publisher"/>
+          </group>
+        </else-if>
+        <else>
+          <group suffix=".">
+            <text macro="title" prefix=" "/>
+            <text macro="editor" prefix=" "/>
+          </group>
+          <group prefix=" " suffix="." delimiter=" ">
+            <text variable="container-title" font-style="italic"/>
+            <group delimiter=":">
+              <group>
+                <text variable="volume"/>
+                <text variable="issue" prefix="(" suffix=")"/>
+              </group>
+              <text variable="page"/>
+            </group>
+          </group>
+        </else>
+      </choose>
+      <text prefix=". " macro="access"/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/chicago-author-date.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,481 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only">
+  <info>
+    <title>Chicago Manual of Style (author-date)</title>
+    <id>http://www.zotero.org/styles/chicago-author-date</id>
+    <link href="http://www.zotero.org/styles/chicago-author-date" rel="self"/>
+    <link href="http://www.chicagomanualofstyle.org/tools_citationguide.html" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <contributor>
+      <name>Richard Karnesky</name>
+      <email>karnesky+zotero@gmail.com</email>
+      <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
+    </contributor>
+    <category citation-format="author-date"/>
+    <category field="generic-base"/>
+    <summary>The author-date variant of the Chicago style</summary>
+    <updated>2012-12-06T03:10:19+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale>
+    <terms>
+      <term name="editor" form="verb-short">ed.</term>
+      <term name="container-author" form="verb">by</term>
+      <term name="translator" form="verb-short">trans.</term>
+    </terms>
+  </locale>
+  <macro name="secondary-contributors">
+    <choose>
+      <if type="chapter paper-conference" match="none">
+        <group delimiter=". ">
+          <choose>
+            <if variable="author">
+              <names variable="editor">
+                <label form="verb" text-case="capitalize-first" suffix=" " plural="never"/>
+                <name and="text" delimiter=", "/>
+              </names>
+            </if>
+          </choose>
+          <choose>
+            <if variable="author editor" match="any">
+              <names variable="translator">
+                <label form="verb" text-case="capitalize-first" suffix=" " plural="never"/>
+                <name and="text" delimiter=", "/>
+              </names>
+            </if>
+          </choose>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-contributors">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <group prefix=", " delimiter=", ">
+          <choose>
+            <if variable="author">
+              <names variable="container-author editor" delimiter=", ">
+                <label form="verb" suffix=" " plural="never"/>
+                <name and="text" delimiter=", "/>
+              </names>
+            </if>
+          </choose>
+          <choose>
+            <if variable="author editor" match="any">
+              <names variable="translator">
+                <label form="short" plural="never" suffix=" "/>
+                <name and="text" delimiter=", "/>
+              </names>
+            </if>
+          </choose>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="editor">
+    <names variable="editor">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="translator">
+    <names variable="translator">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", " plural="never"/>
+    </names>
+  </macro>
+  <macro name="recipient">
+    <choose>
+      <if type="personal_communication">
+        <choose>
+          <if variable="genre">
+            <text variable="genre" text-case="capitalize-first"/>
+          </if>
+          <else>
+            <text term="letter" text-case="capitalize-first"/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+    <names variable="recipient" delimiter=", ">
+      <label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="contributors">
+    <names variable="author">
+      <name and="text" name-as-sort-order="first" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" plural="never" prefix=", "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+    <text macro="recipient"/>
+  </macro>
+  <macro name="contributors-short">
+    <names variable="author">
+      <name form="short" and="text" delimiter=", " initialize-with=". "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="interviewer">
+    <names variable="interviewer" delimiter=", ">
+      <label form="verb" prefix=" " text-case="capitalize-first" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="archive">
+    <group delimiter=". ">
+      <text variable="archive_location" text-case="capitalize-first"/>
+      <text variable="archive"/>
+      <text variable="archive-place"/>
+    </group>
+  </macro>
+  <macro name="access">
+    <group delimiter=". ">
+      <choose>
+        <if type="graphic report" match="any">
+          <text macro="archive"/>
+        </if>
+        <else-if type="article-magazine article-newspaper bill book chapter graphic legal_case legislation motion_picture paper-conference report song thesis" match="none">
+          <text macro="archive"/>
+        </else-if>
+      </choose>
+      <text variable="DOI" prefix="doi:"/>
+      <choose>
+        <if variable="DOI issued" match="none">
+          <choose>
+            <if variable="URL accessed" match="all">
+              <group delimiter=" ">
+                <text term="accessed" text-case="capitalize-first"/>
+                <date variable="accessed" delimiter=" ">
+                  <date-part name="month"/>
+                  <date-part name="day"/>
+                </date>
+              </group>
+            </if>
+          </choose>
+        </if>
+        <else-if type="webpage">
+          <date variable="issued" delimiter=" ">
+            <date-part name="month"/>
+            <date-part name="day"/>
+          </date>
+        </else-if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <text variable="URL"/>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if variable="title" match="none">
+        <choose>
+          <if type="personal_communication" match="none">
+            <text variable="genre" text-case="capitalize-first"/>
+          </if>
+        </choose>
+      </if>
+      <else-if type="bill book graphic legal_case legislation motion_picture song" match="any">
+        <text variable="title" text-case="title" font-style="italic"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" " prefix=". ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition" prefix=". "/>
+          </else>
+        </choose>
+      </if>
+      <else-if type="chapter  paper-conference" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" " prefix=", ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition" prefix=", "/>
+          </else>
+        </choose>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators">
+    <choose>
+      <if type="article-journal">
+        <text variable="volume" prefix=" "/>
+        <text variable="issue" prefix=" (" suffix=")"/>
+      </if>
+      <else-if type="legal_case">
+        <text variable="volume" prefix=", "/>
+        <text variable="container-title" prefix=" "/>
+        <text variable="page" prefix=" "/>
+      </else-if>
+      <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <group prefix=". " delimiter=". ">
+          <group>
+            <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
+            <number variable="volume" form="numeric"/>
+          </group>
+          <group>
+            <number variable="number-of-volumes" form="numeric"/>
+            <text term="volume" form="short" prefix=" " plural="true"/>
+          </group>
+        </group>
+      </else-if>
+      <else-if type="chapter paper-conference" match="any">
+        <choose>
+          <if variable="page" match="none">
+            <group prefix=". ">
+              <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
+              <number variable="volume" form="numeric"/>
+            </group>
+          </if>
+        </choose>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators-chapter">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <choose>
+          <if variable="page">
+            <group prefix=", ">
+              <text variable="volume" suffix=":"/>
+              <text variable="page"/>
+            </group>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-article">
+    <choose>
+      <if type="article-newspaper">
+        <group prefix=", " delimiter=", ">
+          <group>
+            <text variable="edition" suffix=" "/>
+            <text term="edition" prefix=" "/>
+          </group>
+          <group>
+            <text term="section" form="short" suffix=" "/>
+            <text variable="section"/>
+          </group>
+        </group>
+      </if>
+      <else-if type="article-journal">
+        <text variable="page" prefix=": "/>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="point-locators">
+    <choose>
+      <if variable="locator">
+        <choose>
+          <if locator="page" match="none">
+            <choose>
+              <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+                <choose>
+                  <if variable="volume">
+                    <group>
+                      <text term="volume" form="short" suffix=" "/>
+                      <number variable="volume" form="numeric"/>
+                      <label variable="locator" form="short" prefix=", " suffix=" "/>
+                    </group>
+                  </if>
+                  <else>
+                    <label variable="locator" form="short" suffix=" "/>
+                  </else>
+                </choose>
+              </if>
+              <else>
+                <label variable="locator" form="short" suffix=" "/>
+              </else>
+            </choose>
+          </if>
+          <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+            <number variable="volume" form="numeric" suffix=":"/>
+          </else-if>
+        </choose>
+        <text variable="locator"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-prefix">
+    <text term="in" text-case="capitalize-first"/>
+  </macro>
+  <macro name="container-title">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <text macro="container-prefix" suffix=" "/>
+      </if>
+    </choose>
+    <choose>
+      <if type="legal_case" match="none">
+        <text variable="container-title" text-case="title" font-style="italic"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": ">
+      <text variable="publisher-place"/>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="date">
+    <choose>
+      <if variable="issued">
+        <date variable="issued">
+          <date-part name="year"/>
+        </date>
+      </if>
+      <else-if variable="accessed">
+        <date variable="accessed">
+          <date-part name="year"/>
+        </date>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="day-month">
+    <date variable="issued">
+      <date-part name="month"/>
+      <date-part name="day" prefix=" "/>
+    </date>
+  </macro>
+  <macro name="collection-title">
+    <text variable="collection-title" text-case="title"/>
+    <text variable="collection-number" prefix=" "/>
+  </macro>
+  <macro name="event">
+    <group>
+      <text term="presented at" suffix=" "/>
+      <text variable="event"/>
+    </group>
+  </macro>
+  <macro name="description">
+    <choose>
+      <if type="interview">
+        <group delimiter=". ">
+          <text macro="interviewer"/>
+          <text variable="medium" text-case="capitalize-first"/>
+        </group>
+      </if>
+      <else>
+        <text variable="medium" text-case="capitalize-first" prefix=". "/>
+      </else>
+    </choose>
+    <choose>
+      <if variable="title" match="none"/>
+      <else-if type="thesis"/>
+      <else>
+        <group delimiter=" " prefix=". ">
+          <text variable="genre" text-case="capitalize-first"/>
+          <choose>
+            <if type="report">
+              <text variable="number"/>
+            </if>
+          </choose>
+        </group>
+      </else>
+    </choose>
+    <!--This is for computer programs only. Localization new to 1.0.1, so may be missing in many locales-->
+    <group delimiter=" " prefix=" (" suffix=")">
+      <text term="version"/>
+      <text variable="version"/>
+    </group>
+  </macro>
+  <macro name="issue">
+    <choose>
+      <if type="article-journal">
+        <text macro="day-month" prefix=" (" suffix=")"/>
+      </if>
+      <else-if type="legal_case">
+        <text variable="authority" prefix=". "/>
+      </else-if>
+      <else-if type="speech">
+        <group prefix=" " delimiter=", ">
+          <text macro="event"/>
+          <text macro="day-month"/>
+          <text variable="event-place"/>
+        </group>
+      </else-if>
+      <else-if type="article-newspaper article-magazine" match="any">
+        <text macro="day-month" prefix=", "/>
+      </else-if>
+      <else>
+        <group prefix=". " delimiter=", ">
+          <choose>
+            <if type="thesis">
+              <text variable="genre" text-case="capitalize-first"/>
+            </if>
+          </choose>
+          <text macro="publisher"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" givenname-disambiguation-rule="primary-name">
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=", ">
+        <group delimiter=" ">
+          <text macro="contributors-short"/>
+          <text macro="date"/>
+        </group>
+        <text macro="point-locators"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" subsequent-author-substitute="&#8212;&#8212;&#8212;" entry-spacing="0">
+    <sort>
+      <key macro="contributors"/>
+      <key variable="issued"/>
+    </sort>
+    <layout suffix=".">
+      <group delimiter=". ">
+        <text macro="contributors"/>
+        <text macro="date"/>
+        <text macro="title"/>
+      </group>
+      <text macro="description"/>
+      <text macro="secondary-contributors" prefix=". "/>
+      <text macro="container-title" prefix=". "/>
+      <text macro="container-contributors"/>
+      <text macro="edition"/>
+      <text macro="locators-chapter"/>
+      <text macro="locators"/>
+      <text macro="collection-title" prefix=". "/>
+      <text macro="issue"/>
+      <text macro="locators-article"/>
+      <text macro="access" prefix=". "/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/chicago-fullnote-bibliography.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1045 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="note" version="1.0" demote-non-dropping-particle="sort-only">
+  <info>
+    <title>Chicago Manual of Style (full note)</title>
+    <id>http://www.zotero.org/styles/chicago-fullnote-bibliography</id>
+    <link href="http://www.zotero.org/styles/chicago-fullnote-bibliography" rel="self"/>
+    <link href="http://www.chicagomanualofstyle.org/tools_citationguide.html" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <contributor>
+      <name>Simon Kornblith</name>
+      <email>simon@simonster.com</email>
+    </contributor>
+    <contributor>
+      <name>Elena Razlogova</name>
+      <email>elena.razlogova@gmail.com</email>
+    </contributor>
+    <contributor>
+      <name>Frank Bennett</name>
+      <email>biercenator@gmail.com</email>
+    </contributor>
+    <category citation-format="note"/>
+    <category field="generic-base"/>
+    <summary>Chicago format with full notes and bibliography</summary>
+    <updated>2012-10-26T01:15:26+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="editortranslator" form="verb-short">
+        <single>trans. and ed.</single>
+        <multiple>trans. and ed.</multiple>
+      </term>
+      <term name="editortranslator" form="verb">
+        <single>Translated and edited by</single>
+        <multiple>Translated and edited by</multiple>
+      </term>
+      <term name="editor" form="verb-short">ed.</term>
+      <term name="translator" form="verb-short">trans.</term>
+    </terms>
+  </locale>
+  <macro name="editor-translator">
+    <group delimiter=", ">
+      <choose>
+        <if variable="author">
+          <group delimiter=" ">
+            <choose>
+              <if variable="container-author">
+                <group>
+                  <names variable="container-author">
+                    <label form="verb-short" text-case="lowercase" suffix=" "/>
+                    <name and="text" delimiter=", "/>
+                  </names>
+                </group>
+              </if>
+            </choose>
+          </group>
+          <names variable="editor translator" delimiter=", ">
+            <label form="verb-short" text-case="lowercase" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="secondary-contributors-note">
+    <choose>
+      <if type="chapter paper-conference" match="none">
+        <text macro="editor-translator"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-contributors-note">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <text macro="editor-translator"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="secondary-contributors">
+    <choose>
+      <if type="chapter paper-conference" match="none">
+        <group delimiter=". ">
+          <choose>
+            <if variable="author">
+              <names variable="editor translator" delimiter=". ">
+                <label form="verb" text-case="capitalize-first" suffix=" "/>
+                <name and="text" delimiter=", "/>
+              </names>
+            </if>
+          </choose>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-contributors">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <group delimiter=", ">
+          <choose>
+            <if variable="author">
+              <choose>
+                <if variable="container-author">
+                  <names variable="container-author">
+                    <label form="verb-short" text-case="lowercase" suffix=" "/>
+                    <name and="text" delimiter=", "/>
+                  </names>
+                </if>
+              </choose>
+              <choose>
+                <if variable="container-author author" match="all">
+                  <group delimiter=". ">
+                    <text variable="page"/>
+                    <names variable="editor translator" delimiter=", ">
+                      <label form="verb" suffix=" "/>
+                      <name and="text" delimiter=", "/>
+                    </names>
+                  </group>
+                </if>
+                <else>
+                  <names variable="editor translator" delimiter=", ">
+                    <label form="verb" text-case="lowercase" suffix=" "/>
+                    <name and="text" delimiter=", "/>
+                  </names>
+                </else>
+              </choose>
+            </if>
+          </choose>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="recipient-note">
+    <names variable="recipient" delimiter=", ">
+      <label form="verb" text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="contributors-note">
+    <group delimiter=" ">
+      <names variable="author">
+        <name and="text" sort-separator=", " delimiter=", "/>
+        <label form="short" prefix=", "/>
+        <substitute>
+          <names variable="editor"/>
+          <names variable="translator"/>
+        </substitute>
+      </names>
+      <text macro="recipient-note"/>
+    </group>
+  </macro>
+  <macro name="editor">
+    <names variable="editor">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="translator">
+    <names variable="translator">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="verb-short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="recipient">
+    <group delimiter=" ">
+      <choose>
+        <if type="personal_communication">
+          <choose>
+            <if variable="genre">
+              <text variable="genre" text-case="capitalize-first"/>
+            </if>
+            <else>
+              <text term="letter" text-case="capitalize-first"/>
+            </else>
+          </choose>
+        </if>
+      </choose>
+      <text macro="recipient-note"/>
+    </group>
+  </macro>
+  <macro name="contributors">
+    <group delimiter=". ">
+      <names variable="author">
+        <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+        <substitute>
+          <text macro="editor"/>
+          <text macro="translator"/>
+        </substitute>
+      </names>
+      <text macro="recipient"/>
+    </group>
+  </macro>
+  <macro name="recipient-short">
+    <names variable="recipient">
+      <label form="verb" text-case="lowercase" suffix=" "/>
+      <name form="short" and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="contributors-short">
+    <group delimiter=" ">
+      <names variable="author">
+        <name form="short" and="text" delimiter=", "/>
+        <substitute>
+          <names variable="editor"/>
+          <names variable="translator"/>
+        </substitute>
+      </names>
+      <text macro="recipient-short"/>
+    </group>
+  </macro>
+  <macro name="contributors-sort">
+    <names variable="author">
+      <name name-as-sort-order="all" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="interviewer-note">
+    <names variable="interviewer" delimiter=", ">
+      <label form="verb" text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="interviewer">
+    <names variable="interviewer" delimiter=", ">
+      <label form="verb" text-case="capitalize-first" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="title-note">
+    <choose>
+      <if variable="title" match="none">
+        <text variable="genre"/>
+      </if>
+      <else-if type="bill book graphic  legislation motion_picture report song" match="any">
+        <text variable="title" text-case="title" font-style="italic"/>
+        <group delimiter=" " prefix=", ">
+          <text term="version"/>
+          <text variable="version"/>
+        </group>
+      </else-if>
+      <else-if type="legal_case interview" match="any">
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if variable="title" match="none">
+        <choose>
+          <if type="personal_communication" match="none">
+            <text variable="genre" text-case="capitalize-first"/>
+          </if>
+        </choose>
+      </if>
+      <else-if type="bill book graphic legislation motion_picture report song" match="any">
+        <text variable="title" text-case="title" font-style="italic"/>
+        <group prefix=" (" suffix=")" delimiter=" ">
+          <text term="version"/>
+          <text variable="version"/>
+        </group>
+      </else-if>
+      <else-if type="legal_case interview" match="any">
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title-short">
+    <choose>
+      <if variable="title" match="none">
+        <choose>
+          <if type="interview">
+            <text term="interview"/>
+          </if>
+          <else-if type="manuscript speech" match="any">
+            <text variable="genre" form="short"/>
+          </else-if>
+          <else-if type="personal_communication">
+            <text macro="issued"/>
+          </else-if>
+        </choose>
+      </if>
+      <else-if type="bill book graphic legislation motion_picture report song" match="any">
+        <text variable="title" text-case="title" form="short" font-style="italic"/>
+      </else-if>
+      <else-if type="legal_case interview" match="any">
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" form="short" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date-disambiguate">
+    <choose>
+      <if disambiguate="true">
+        <text macro="issued"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="description-note">
+    <group delimiter=", ">
+      <text macro="interviewer-note"/>
+      <text variable="medium"/>
+      <choose>
+        <if variable="title" match="none"/>
+        <else-if type="thesis speech" match="any"/>
+        <else>
+          <text variable="genre"/>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="description">
+    <group delimiter=", ">
+      <group delimiter=". ">
+        <text macro="interviewer"/>
+        <text variable="medium" text-case="capitalize-first"/>
+      </group>
+      <choose>
+        <if variable="title" match="none"/>
+        <else-if type="thesis speech" match="any"/>
+        <else>
+          <text variable="genre" text-case="capitalize-first"/>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="container-title-note">
+    <group delimiter=" ">
+      <choose>
+        <if type="chapter paper-conference" match="any">
+          <text term="in" text-case="lowercase"/>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <text variable="container-title" text-case="title" font-style="italic"/>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="container-title">
+    <group delimiter=" ">
+      <choose>
+        <if type="chapter paper-conference" match="any">
+          <text term="in" text-case="capitalize-first"/>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <text variable="container-title" text-case="title" font-style="italic"/>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="collection-title">
+    <group delimiter=" ">
+      <text variable="collection-title" text-case="title"/>
+      <text variable="collection-number"/>
+    </group>
+  </macro>
+  <macro name="edition-note">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <number variable="edition" suffix="."/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <number variable="edition" text-case="capitalize-first" suffix="."/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-note-join-with-space">
+    <choose>
+      <if type="article-journal">
+        <text macro="locators-note"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-note-join-with-comma">
+    <choose>
+      <if type="article-journal" match="none">
+        <text macro="locators-note"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-note">
+    <choose>
+      <if type="article-journal">
+        <group delimiter=", ">
+          <number variable="volume"/>
+          <group delimiter=" ">
+            <text term="issue" form="short"/>
+            <number variable="issue"/>
+          </group>
+        </group>
+      </if>
+      <else-if type="legal_case">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <number variable="volume"/>
+            <text variable="container-title"/>
+            <text variable="page"/>
+          </group>
+          <text variable="locator"/>
+        </group>
+      </else-if>
+      <else-if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <text term="volume" form="short"/>
+            <number variable="volume" form="numeric"/>
+          </group>
+          <choose>
+            <if variable="locator" match="none">
+              <group delimiter=" ">
+                <number variable="number-of-volumes" form="numeric"/>
+                <text term="volume" form="short" plural="true"/>
+              </group>
+            </if>
+          </choose>
+          <text macro="edition-note"/>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators-join-with-space">
+    <choose>
+      <if type="article-journal">
+        <text macro="locators"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-join-with-comma">
+    <choose>
+      <if type="legal_case">
+        <text macro="locators"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-join-with-period">
+    <choose>
+      <if type="legal_case article-journal" match="none">
+        <text macro="locators"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators">
+    <choose>
+      <if type="article-journal">
+        <group delimiter=", ">
+          <number variable="volume"/>
+          <group delimiter=" ">
+            <text term="issue" form="short"/>
+            <number variable="issue"/>
+          </group>
+        </group>
+      </if>
+      <else-if type="legal_case">
+        <group delimiter=" ">
+          <number variable="volume"/>
+          <text variable="container-title"/>
+          <text variable="page"/>
+        </group>
+      </else-if>
+      <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <group delimiter=". ">
+          <group delimiter=" ">
+            <text term="volume" form="short" text-case="capitalize-first"/>
+            <number variable="volume" form="numeric"/>
+          </group>
+          <group delimiter=" ">
+            <number variable="number-of-volumes" form="numeric"/>
+            <text term="volume" form="short" plural="true"/>
+          </group>
+          <text macro="edition"/>
+        </group>
+      </else-if>
+      <else-if type="chapter paper-conference" match="any">
+        <group delimiter=". ">
+          <choose>
+            <if variable="page" match="none">
+              <group delimiter=" ">
+                <text term="volume" form="short" text-case="capitalize-first"/>
+                <number variable="volume" form="numeric"/>
+              </group>
+            </if>
+          </choose>
+          <text macro="edition"/>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators-newspaper">
+    <choose>
+      <if type="article-newspaper">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <number variable="edition"/>
+            <text term="edition"/>
+          </group>
+          <group delimiter=" ">
+            <text term="section" form="short"/>
+            <text variable="section"/>
+          </group>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="event">
+    <group delimiter=" ">
+      <text term="presented at"/>
+      <text variable="event"/>
+    </group>
+  </macro>
+  <macro name="publisher">
+    <choose>
+      <if type="thesis">
+        <text variable="publisher"/>
+      </if>
+      <else>
+        <group delimiter=": ">
+          <text variable="publisher-place"/>
+          <text variable="publisher"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issued">
+    <choose>
+      <if variable="issued">
+        <choose>
+          <if type="graphic report" match="any">
+            <date variable="issued" form="text"/>
+          </if>
+          <else-if type="legal_case">
+            <group delimiter=" ">
+              <text variable="authority"/>
+              <date variable="issued">
+                <date-part name="year"/>
+              </date>
+            </group>
+          </else-if>
+          <else-if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song thesis" match="any">
+            <date variable="issued">
+              <date-part name="year"/>
+            </date>
+          </else-if>
+          <else>
+            <date variable="issued" form="text"/>
+          </else>
+        </choose>
+      </if>
+      <else-if variable="accessed URL" match="all"/>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="point-locators-subsequent">
+    <choose>
+      <if variable="locator">
+        <choose>
+          <if locator="page" match="none">
+            <group delimiter=" ">
+              <choose>
+                <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+                  <choose>
+                    <if variable="volume">
+                      <group delimiter=", ">
+                        <group delimiter=" ">
+                          <text term="volume" form="short" text-case="lowercase"/>
+                          <number variable="volume" form="numeric"/>
+                        </group>
+                        <label variable="locator" form="short"/>
+                      </group>
+                    </if>
+                    <else>
+                      <label variable="locator" form="short"/>
+                    </else>
+                  </choose>
+                </if>
+                <else>
+                  <label variable="locator" form="short"/>
+                </else>
+              </choose>
+              <text variable="locator"/>
+            </group>
+          </if>
+          <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+            <group delimiter=":">
+              <number variable="volume" form="numeric"/>
+              <text variable="locator"/>
+            </group>
+          </else-if>
+          <else>
+            <text variable="locator"/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="point-locators-join-with-colon">
+    <choose>
+      <if type="article-journal">
+        <choose>
+          <if variable="locator page" match="any">
+            <text macro="point-locators"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="point-locators-join-with-comma">
+    <choose>
+      <if type="article-journal" match="none">
+        <text macro="point-locators"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="point-locators">
+    <choose>
+      <if variable="locator" match="none">
+        <choose>
+          <if type="article-journal chapter paper-conference" match="any">
+            <text variable="page"/>
+          </if>
+        </choose>
+      </if>
+      <else-if type="article-journal">
+        <group delimiter=" ">
+          <choose>
+            <if locator="page" match="none">
+              <label variable="locator" form="short" suffix=" "/>
+            </if>
+          </choose>
+          <text variable="locator"/>
+        </group>
+      </else-if>
+      <else-if type="legal_case"/>
+      <else>
+        <group delimiter=" ">
+          <choose>
+            <if locator="page" match="none">
+              <label variable="locator" form="short"/>
+            </if>
+          </choose>
+          <text variable="locator"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="locators-chapter">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <choose>
+          <if variable="page">
+            <number variable="volume" suffix=":"/>
+            <text variable="page"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-journal">
+    <choose>
+      <if type="article-journal">
+        <text variable="page"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="archive-note">
+    <choose>
+      <if type="thesis">
+        <group delimiter=" ">
+          <text variable="archive"/>
+          <text variable="archive_location" prefix="(" suffix=")"/>
+        </group>
+      </if>
+      <else>
+        <group delimiter=", ">
+          <text variable="archive_location"/>
+          <text variable="archive"/>
+          <text variable="archive-place"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="archive">
+    <choose>
+      <if type="thesis">
+        <group delimiter=" ">
+          <text variable="archive"/>
+          <text variable="archive_location" prefix="(" suffix=")"/>
+        </group>
+      </if>
+      <else>
+        <group delimiter=". ">
+          <text variable="archive_location" text-case="capitalize-first"/>
+          <text variable="archive"/>
+          <text variable="archive-place"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issue-note-join-with-space">
+    <choose>
+      <if type="article-journal legal_case" variable="publisher-place publisher" match="any">
+        <choose>
+          <if type="article-newspaper" match="none">
+            <text macro="issue-note"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issue-note-join-with-comma">
+    <choose>
+      <if type="article-journal legal_case" variable="publisher-place publisher" match="none">
+        <text macro="issue-note"/>
+      </if>
+      <else-if type="article-newspaper">
+        <text macro="issue-note"/>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="issue-note">
+    <choose>
+      <if type="article-journal legal_case" match="any">
+        <text macro="issued" prefix="(" suffix=")"/>
+      </if>
+      <else-if type="article-newspaper">
+        <text macro="issued"/>
+      </else-if>
+      <else-if variable="publisher-place publisher" match="any">
+        <group prefix="(" suffix=")" delimiter=", ">
+          <group delimiter=" ">
+            <choose>
+              <if variable="title" match="none"/>
+              <else-if type="thesis speech" match="any">
+                <text variable="genre"/>
+              </else-if>
+            </choose>
+            <text macro="event"/>
+          </group>
+          <text macro="publisher"/>
+          <text macro="issued"/>
+        </group>
+      </else-if>
+      <else>
+        <text macro="issued"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issue-join-with-space">
+    <choose>
+      <if type="article-journal legal_case" match="any">
+        <text macro="issue"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issue-join-with-period">
+    <choose>
+      <if type="article-journal legal_case" match="none">
+        <choose>
+          <if type="speech" variable="publisher publisher-place" match="any">
+            <text macro="issue"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issue-join-with-comma">
+    <choose>
+      <if type="article-journal legal_case" match="none">
+        <choose>
+          <if type="speech" variable="publisher publisher-place" match="none">
+            <text macro="issue"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issue">
+    <choose>
+      <if type="article-journal legal_case" match="any">
+        <text macro="issued" prefix="(" suffix=")"/>
+      </if>
+      <else-if type="speech">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <choose>
+              <if variable="title" match="none"/>
+              <else>
+                <text variable="genre" text-case="capitalize-first"/>
+              </else>
+            </choose>
+            <text macro="event"/>
+          </group>
+          <text variable="event-place"/>
+          <text macro="issued"/>
+        </group>
+      </else-if>
+      <else-if type="article-newspaper">
+        <text macro="issued"/>
+      </else-if>
+      <else-if variable="publisher-place publisher" match="any">
+        <group delimiter=", ">
+          <choose>
+            <if type="thesis">
+              <text variable="genre" text-case="capitalize-first"/>
+            </if>
+          </choose>
+          <text macro="publisher"/>
+          <text macro="issued"/>
+        </group>
+      </else-if>
+      <else>
+        <text macro="issued"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="access-note">
+    <group delimiter=", ">
+      <choose>
+        <if type="graphic report" match="any">
+          <text macro="archive-note"/>
+        </if>
+        <else-if type="article-journal article-magazine article-newspaper bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="none">
+          <text macro="archive-note"/>
+        </else-if>
+      </choose>
+      <choose>
+        <if variable="issued" match="none">
+          <group delimiter=" ">
+            <text term="accessed"/>
+            <date variable="accessed" form="text"/>
+          </group>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <choose>
+            <if variable="DOI">
+              <text variable="DOI" prefix="doi:"/>
+            </if>
+            <else>
+              <text variable="URL"/>
+            </else>
+          </choose>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="access">
+    <group delimiter=". ">
+      <choose>
+        <if type="graphic report" match="any">
+          <text macro="archive"/>
+        </if>
+        <else-if type="article-journal article-magazine article-newspaper bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="none">
+          <text macro="archive"/>
+        </else-if>
+      </choose>
+      <choose>
+        <if variable="issued" match="none">
+          <group delimiter=" ">
+            <text term="accessed" text-case="capitalize-first"/>
+            <date variable="accessed" form="text"/>
+          </group>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <choose>
+            <if variable="DOI">
+              <text variable="DOI" prefix="doi:"/>
+            </if>
+            <else>
+              <text variable="URL"/>
+            </else>
+          </choose>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="case-locator-subsequent">
+    <choose>
+      <if type="legal_case">
+        <text macro="locators-note"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="case-issue-subsequent">
+    <choose>
+      <if type="legal_case">
+        <text macro="issue"/>
+      </if>
+    </choose>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" disambiguate-add-names="true">
+    <layout suffix="." delimiter="; ">
+      <choose>
+        <if position="ibid-with-locator">
+          <group delimiter=", ">
+            <text term="ibid"/>
+            <text macro="point-locators-subsequent"/>
+          </group>
+        </if>
+        <else-if position="ibid">
+          <text term="ibid"/>
+        </else-if>
+        <else-if position="subsequent">
+          <group delimiter=", ">
+            <text macro="contributors-short"/>
+            <group delimiter=" ">
+              <group delimiter=", ">
+                <text macro="title-short"/>
+                <text macro="date-disambiguate"/>
+                <text macro="case-locator-subsequent"/>
+              </group>
+              <text macro="case-issue-subsequent"/>
+            </group>
+            <text macro="point-locators-subsequent"/>
+          </group>
+        </else-if>
+        <else>
+          <group delimiter=", ">
+            <group delimiter=": ">
+              <group delimiter=", ">
+                <group delimiter=" ">
+                  <group delimiter=", ">
+                    <group delimiter=" ">
+                      <group delimiter=", ">
+                        <group delimiter=", ">
+                          <text macro="contributors-note"/>
+                          <text macro="title-note"/>
+                        </group>
+                        <text macro="description-note"/>
+                        <text macro="secondary-contributors-note"/>
+                        <text macro="container-title-note"/>
+                        <text macro="container-contributors-note"/>
+                      </group>
+                      <text macro="locators-note-join-with-space"/>
+                    </group>
+                    <text macro="locators-note-join-with-comma"/>
+                    <text macro="collection-title"/>
+                    <text macro="issue-note-join-with-comma"/>
+                  </group>
+                  <text macro="issue-note-join-with-space"/>
+                </group>
+                <text macro="locators-newspaper"/>
+                <text macro="point-locators-join-with-comma"/>
+              </group>
+              <text macro="point-locators-join-with-colon"/>
+            </group>
+            <text macro="access-note"/>
+          </group>
+        </else>
+      </choose>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" subsequent-author-substitute="&#8212;&#8212;&#8212;" entry-spacing="0">
+    <sort>
+      <key macro="contributors-sort"/>
+      <key variable="title"/>
+      <key variable="genre"/>
+      <key variable="issued"/>
+    </sort>
+    <layout suffix=".">
+      <group delimiter=". ">
+        <group delimiter=": ">
+          <group delimiter=", ">
+            <group delimiter=" ">
+              <group delimiter=". ">
+                <group delimiter=" ">
+                  <group delimiter=", ">
+                    <group delimiter=". ">
+                      <group delimiter=". ">
+                        <text macro="contributors"/>
+                        <text macro="title"/>
+                      </group>
+                      <text macro="description"/>
+                      <text macro="secondary-contributors"/>
+                      <group delimiter=", ">
+                        <text macro="container-title"/>
+                        <text macro="container-contributors"/>
+                        <text macro="locators-chapter"/>
+                      </group>
+                      <text macro="locators-join-with-period"/>
+                    </group>
+                    <text macro="locators-join-with-comma"/>
+                  </group>
+                  <text macro="locators-join-with-space"/>
+                </group>
+                <text macro="collection-title"/>
+                <text macro="issue-join-with-period"/>
+              </group>
+              <text macro="issue-join-with-space"/>
+            </group>
+            <text macro="issue-join-with-comma"/>
+            <text macro="locators-newspaper"/>
+          </group>
+          <text macro="locators-journal"/>
+        </group>
+        <text macro="access"/>
+      </group>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/chicago-note-bibliography.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1016 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="note" version="1.0" demote-non-dropping-particle="sort-only">
+  <info>
+    <title>Chicago Manual of Style (note)</title>
+    <id>http://www.zotero.org/styles/chicago-note-bibliography</id>
+    <link href="http://www.zotero.org/styles/chicago-note-bibliography" rel="self"/>
+    <link href="http://www.chicagomanualofstyle.org/tools_citationguide.html" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <contributor>
+      <name>Simon Kornblith</name>
+      <email>simon@simonster.com</email>
+    </contributor>
+    <contributor>
+      <name>Elena Razlogova</name>
+      <email>elena.razlogova@gmail.com</email>
+    </contributor>
+    <contributor>
+      <name>Frank Bennett</name>
+      <email>biercenator@gmail.com</email>
+    </contributor>
+    <category citation-format="note"/>
+    <category field="generic-base"/>
+    <summary>Chicago format with short notes and bibliography</summary>
+    <updated>2012-10-25T21:15:26+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="editortranslator" form="verb-short">
+        <single>trans. and ed.</single>
+        <multiple>trans. and ed.</multiple>
+      </term>
+      <term name="editortranslator" form="verb">
+        <single>Translated and edited by</single>
+        <multiple>Translated and edited by</multiple>
+      </term>
+      <term name="editor" form="verb-short">ed.</term>
+      <term name="translator" form="verb-short">trans.</term>
+    </terms>
+  </locale>
+  <macro name="editor-translator">
+    <group delimiter=", ">
+      <choose>
+        <if variable="author">
+          <group delimiter=" ">
+            <choose>
+              <if variable="container-author">
+                <group>
+                  <names variable="container-author">
+                    <label form="verb-short" text-case="lowercase" suffix=" "/>
+                    <name and="text" delimiter=", "/>
+                  </names>
+                </group>
+              </if>
+            </choose>
+          </group>
+          <names variable="editor translator" delimiter=", ">
+            <label form="verb-short" text-case="lowercase" suffix=" "/>
+            <name and="text" delimiter=", "/>
+          </names>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="secondary-contributors-note">
+    <choose>
+      <if type="chapter paper-conference" match="none">
+        <text macro="editor-translator"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-contributors-note">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <text macro="editor-translator"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="secondary-contributors">
+    <choose>
+      <if type="chapter paper-conference" match="none">
+        <group delimiter=". ">
+          <choose>
+            <if variable="author">
+              <names variable="editor translator" delimiter=". ">
+                <label form="verb" text-case="capitalize-first" suffix=" "/>
+                <name and="text" delimiter=", "/>
+              </names>
+            </if>
+          </choose>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-contributors">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <group delimiter=", ">
+          <choose>
+            <if variable="author">
+              <choose>
+                <if variable="container-author">
+                  <names variable="container-author">
+                    <label form="verb-short" text-case="lowercase" suffix=" "/>
+                    <name and="text" delimiter=", "/>
+                  </names>
+                </if>
+              </choose>
+              <!--This includes page numers after the container author, e.g. for Introductions -->
+              <choose>
+                <if variable="container-author author" match="all">
+                  <group delimiter=". ">
+                    <text variable="page"/>
+                    <names variable="editor translator" delimiter=", ">
+                      <label form="verb" suffix=" "/>
+                      <name and="text" delimiter=", "/>
+                    </names>
+                  </group>
+                </if>
+                <else>
+                  <names variable="editor translator" delimiter=", ">
+                    <label form="verb" text-case="lowercase" suffix=" "/>
+                    <name and="text" delimiter=", "/>
+                  </names>
+                </else>
+              </choose>
+            </if>
+          </choose>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="recipient-note">
+    <names variable="recipient" delimiter=", ">
+      <label form="verb" text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="contributors-note">
+    <group delimiter=" ">
+      <names variable="author">
+        <name and="text" sort-separator=", " delimiter=", "/>
+        <label form="short" prefix=", "/>
+        <substitute>
+          <names variable="editor"/>
+          <names variable="translator"/>
+        </substitute>
+      </names>
+      <text macro="recipient-note"/>
+    </group>
+  </macro>
+  <macro name="editor">
+    <names variable="editor">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="translator">
+    <names variable="translator">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="verb-short" prefix=", "/>
+    </names>
+  </macro>
+  <macro name="recipient">
+    <group delimiter=" ">
+      <choose>
+        <if type="personal_communication">
+          <choose>
+            <if variable="genre">
+              <text variable="genre" text-case="capitalize-first"/>
+            </if>
+            <else>
+              <text term="letter" text-case="capitalize-first"/>
+            </else>
+          </choose>
+        </if>
+      </choose>
+      <text macro="recipient-note"/>
+    </group>
+  </macro>
+  <macro name="contributors">
+    <group delimiter=". ">
+      <names variable="author">
+        <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+        <substitute>
+          <text macro="editor"/>
+          <text macro="translator"/>
+        </substitute>
+      </names>
+      <text macro="recipient"/>
+    </group>
+  </macro>
+  <macro name="recipient-short">
+    <names variable="recipient">
+      <label form="verb" text-case="lowercase" suffix=" "/>
+      <name form="short" and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="contributors-short">
+    <group delimiter=" ">
+      <names variable="author">
+        <name form="short" and="text" delimiter=", "/>
+        <substitute>
+          <names variable="editor"/>
+          <names variable="translator"/>
+        </substitute>
+      </names>
+      <text macro="recipient-short"/>
+    </group>
+  </macro>
+  <macro name="contributors-sort">
+    <names variable="author">
+      <name name-as-sort-order="all" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="interviewer-note">
+    <names variable="interviewer" delimiter=", ">
+      <label form="verb" text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="interviewer">
+    <names variable="interviewer" delimiter=", ">
+      <label form="verb" text-case="capitalize-first" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="title-note">
+    <choose>
+      <if variable="title" match="none">
+        <text variable="genre"/>
+      </if>
+      <else-if type="bill book graphic  legislation motion_picture report song" match="any">
+        <text variable="title" text-case="title" font-style="italic"/>
+        <group delimiter=" " prefix=", ">
+          <text term="version"/>
+          <text variable="version"/>
+        </group>
+      </else-if>
+      <else-if type="legal_case interview" match="any">
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if variable="title" match="none">
+        <choose>
+          <if type="personal_communication" match="none">
+            <text variable="genre" text-case="capitalize-first"/>
+          </if>
+        </choose>
+      </if>
+      <else-if type="bill book graphic legislation motion_picture report song" match="any">
+        <text variable="title" text-case="title" font-style="italic"/>
+        <group prefix=" (" suffix=")" delimiter=" ">
+          <text term="version"/>
+          <text variable="version"/>
+        </group>
+      </else-if>
+      <else-if type="legal_case interview" match="any">
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title-short">
+    <choose>
+      <if variable="title" match="none">
+        <choose>
+          <if type="interview">
+            <text term="interview"/>
+          </if>
+          <else-if type="manuscript speech" match="any">
+            <text variable="genre" form="short"/>
+          </else-if>
+          <else-if type="personal_communication">
+            <text macro="issued"/>
+          </else-if>
+        </choose>
+      </if>
+      <else-if type="bill book graphic legislation motion_picture report song" match="any">
+        <text variable="title" text-case="title" form="short" font-style="italic"/>
+      </else-if>
+      <else-if type="legal_case interview" match="any">
+        <text variable="title"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" form="short" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date-disambiguate">
+    <choose>
+      <if disambiguate="true">
+        <text macro="issued"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="description-note">
+    <group delimiter=", ">
+      <text macro="interviewer-note"/>
+      <text variable="medium"/>
+      <choose>
+        <if variable="title" match="none"/>
+        <else-if type="thesis speech" match="any"/>
+        <else>
+          <text variable="genre"/>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="description">
+    <group delimiter=", ">
+      <group delimiter=". ">
+        <text macro="interviewer"/>
+        <text variable="medium" text-case="capitalize-first"/>
+      </group>
+      <choose>
+        <if variable="title" match="none"/>
+        <else-if type="thesis speech" match="any"/>
+        <else>
+          <text variable="genre" text-case="capitalize-first"/>
+        </else>
+      </choose>
+    </group>
+  </macro>
+  <macro name="container-title-note">
+    <group delimiter=" ">
+      <choose>
+        <if type="chapter paper-conference" match="any">
+          <text term="in" text-case="lowercase"/>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <text variable="container-title" text-case="title" font-style="italic"/>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="container-title">
+    <group delimiter=" ">
+      <choose>
+        <if type="chapter paper-conference" match="any">
+          <text term="in" text-case="capitalize-first"/>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <text variable="container-title" text-case="title" font-style="italic"/>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="collection-title">
+    <group delimiter=" ">
+      <text variable="collection-title" text-case="title"/>
+      <text variable="collection-number"/>
+    </group>
+  </macro>
+  <macro name="edition-note">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <number variable="edition" suffix="."/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <number variable="edition" text-case="capitalize-first" suffix="."/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-note-join-with-space">
+    <choose>
+      <if type="article-journal">
+        <text macro="locators-note"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-note-join-with-comma">
+    <choose>
+      <if type="article-journal" match="none">
+        <text macro="locators-note"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-note">
+    <choose>
+      <if type="article-journal">
+        <group delimiter=", ">
+          <number variable="volume"/>
+          <group delimiter=" ">
+            <text term="issue" form="short"/>
+            <number variable="issue"/>
+          </group>
+        </group>
+      </if>
+      <else-if type="legal_case">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <number variable="volume"/>
+            <text variable="container-title"/>
+            <text variable="page"/>
+          </group>
+          <text variable="locator"/>
+        </group>
+      </else-if>
+      <else-if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <text term="volume" form="short"/>
+            <number variable="volume" form="numeric"/>
+          </group>
+          <choose>
+            <if variable="locator" match="none">
+              <group delimiter=" ">
+                <number variable="number-of-volumes" form="numeric"/>
+                <text term="volume" form="short" plural="true"/>
+              </group>
+            </if>
+          </choose>
+          <text macro="edition-note"/>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators-join-with-space">
+    <choose>
+      <if type="article-journal">
+        <text macro="locators"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-join-with-comma">
+    <choose>
+      <if type="legal_case">
+        <text macro="locators"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-join-with-period">
+    <choose>
+      <if type="legal_case article-journal" match="none">
+        <text macro="locators"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators">
+    <choose>
+      <if type="article-journal">
+        <group delimiter=", ">
+          <number variable="volume"/>
+          <group delimiter=" ">
+            <text term="issue" form="short"/>
+            <number variable="issue"/>
+          </group>
+        </group>
+      </if>
+      <else-if type="legal_case">
+        <group delimiter=" ">
+          <number variable="volume"/>
+          <text variable="container-title"/>
+          <text variable="page"/>
+        </group>
+      </else-if>
+      <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <group delimiter=". ">
+          <group delimiter=" ">
+            <text term="volume" form="short" text-case="capitalize-first"/>
+            <number variable="volume" form="numeric"/>
+          </group>
+          <group delimiter=" ">
+            <number variable="number-of-volumes" form="numeric"/>
+            <text term="volume" form="short" plural="true"/>
+          </group>
+          <text macro="edition"/>
+        </group>
+      </else-if>
+      <else-if type="chapter paper-conference" match="any">
+        <group delimiter=". ">
+          <choose>
+            <if variable="page" match="none">
+              <group delimiter=" ">
+                <text term="volume" form="short" text-case="capitalize-first"/>
+                <number variable="volume" form="numeric"/>
+              </group>
+            </if>
+          </choose>
+          <text macro="edition"/>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="locators-newspaper">
+    <choose>
+      <if type="article-newspaper">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <number variable="edition"/>
+            <text term="edition"/>
+          </group>
+          <group delimiter=" ">
+            <text term="section" form="short"/>
+            <text variable="section"/>
+          </group>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="event">
+    <group delimiter=" ">
+      <text term="presented at"/>
+      <text variable="event"/>
+    </group>
+  </macro>
+  <macro name="publisher">
+    <choose>
+      <if type="thesis">
+        <text variable="publisher"/>
+      </if>
+      <else>
+        <group delimiter=": ">
+          <text variable="publisher-place"/>
+          <text variable="publisher"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issued">
+    <choose>
+      <if variable="issued">
+        <choose>
+          <if type="graphic report" match="any">
+            <date variable="issued" form="text"/>
+          </if>
+          <else-if type="legal_case">
+            <group delimiter=" ">
+              <text variable="authority"/>
+              <date variable="issued">
+                <date-part name="year"/>
+              </date>
+            </group>
+          </else-if>
+          <else-if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song thesis" match="any">
+            <date variable="issued">
+              <date-part name="year"/>
+            </date>
+          </else-if>
+          <else>
+            <date variable="issued" form="text"/>
+          </else>
+        </choose>
+      </if>
+      <else-if variable="accessed URL" match="all"/>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="point-locators-subsequent">
+    <choose>
+      <if variable="locator">
+        <choose>
+          <if locator="page" match="none">
+            <group delimiter=" ">
+              <choose>
+                <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+                  <choose>
+                    <if variable="volume">
+                      <group delimiter=", ">
+                        <group delimiter=" ">
+                          <text term="volume" form="short" text-case="lowercase"/>
+                          <number variable="volume" form="numeric"/>
+                        </group>
+                        <label variable="locator" form="short"/>
+                      </group>
+                    </if>
+                    <else>
+                      <label variable="locator" form="short"/>
+                    </else>
+                  </choose>
+                </if>
+                <else>
+                  <label variable="locator" form="short"/>
+                </else>
+              </choose>
+              <text variable="locator"/>
+            </group>
+          </if>
+          <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+            <group delimiter=":">
+              <number variable="volume" form="numeric"/>
+              <text variable="locator"/>
+            </group>
+          </else-if>
+          <else>
+            <text variable="locator"/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="point-locators-join-with-colon">
+    <choose>
+      <if type="article-journal">
+        <choose>
+          <if variable="locator page" match="any">
+            <text macro="point-locators"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="point-locators-join-with-comma">
+    <choose>
+      <if type="article-journal" match="none">
+        <text macro="point-locators"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="point-locators">
+    <choose>
+      <if variable="locator" match="none">
+        <choose>
+          <if type="article-journal chapter paper-conference" match="any">
+            <text variable="page"/>
+          </if>
+        </choose>
+      </if>
+      <else-if type="article-journal">
+        <group delimiter=" ">
+          <choose>
+            <if locator="page" match="none">
+              <label variable="locator" form="short" suffix=" "/>
+            </if>
+          </choose>
+          <text variable="locator"/>
+        </group>
+      </else-if>
+      <else-if type="legal_case"/>
+      <else>
+        <group delimiter=" ">
+          <choose>
+            <if locator="page" match="none">
+              <label variable="locator" form="short"/>
+            </if>
+          </choose>
+          <text variable="locator"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="locators-chapter">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <choose>
+          <if variable="page">
+            <number variable="volume" suffix=":"/>
+            <text variable="page"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="locators-journal">
+    <choose>
+      <if type="article-journal">
+        <text variable="page"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="archive-note">
+    <choose>
+      <if type="thesis">
+        <group delimiter=" ">
+          <text variable="archive"/>
+          <text variable="archive_location" prefix="(" suffix=")"/>
+        </group>
+      </if>
+      <else>
+        <group delimiter=", ">
+          <text variable="archive_location"/>
+          <text variable="archive"/>
+          <text variable="archive-place"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="archive">
+    <choose>
+      <if type="thesis">
+        <group delimiter=" ">
+          <text variable="archive"/>
+          <text variable="archive_location" prefix="(" suffix=")"/>
+        </group>
+      </if>
+      <else>
+        <group delimiter=". ">
+          <text variable="archive_location" text-case="capitalize-first"/>
+          <text variable="archive"/>
+          <text variable="archive-place"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issue-note-join-with-space">
+    <choose>
+      <if type="article-journal legal_case" variable="publisher-place publisher" match="any">
+        <!--Chicago doesn't use publisher/place for Newspapers and we want the date delimited by a comma-->
+        <choose>
+          <if type="article-newspaper" match="none">
+            <text macro="issue-note"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issue-note-join-with-comma">
+    <choose>
+      <if type="article-journal legal_case" variable="publisher-place publisher" match="none">
+        <text macro="issue-note"/>
+      </if>
+      <else-if type="article-newspaper">
+        <text macro="issue-note"/>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="issue-note">
+    <choose>
+      <if type="article-journal legal_case" match="any">
+        <text macro="issued" prefix="(" suffix=")"/>
+      </if>
+      <else-if type="article-newspaper">
+        <text macro="issued"/>
+      </else-if>
+      <else-if variable="publisher-place publisher" match="any">
+        <group prefix="(" suffix=")" delimiter=", ">
+          <group delimiter=" ">
+            <choose>
+              <if variable="title" match="none"/>
+              <else-if type="thesis speech" match="any">
+                <text variable="genre"/>
+              </else-if>
+            </choose>
+            <text macro="event"/>
+          </group>
+          <text macro="publisher"/>
+          <text macro="issued"/>
+        </group>
+      </else-if>
+      <else>
+        <text macro="issued"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="issue-join-with-space">
+    <choose>
+      <if type="article-journal legal_case" match="any">
+        <text macro="issue"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issue-join-with-period">
+    <choose>
+      <if type="article-journal legal_case" match="none">
+        <choose>
+          <if type="speech" variable="publisher publisher-place" match="any">
+            <text macro="issue"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issue-join-with-comma">
+    <choose>
+      <if type="article-journal legal_case" match="none">
+        <choose>
+          <if type="speech" variable="publisher publisher-place" match="none">
+            <text macro="issue"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issue">
+    <choose>
+      <if type="article-journal legal_case" match="any">
+        <text macro="issued" prefix=" (" suffix=")"/>
+      </if>
+      <else-if type="speech">
+        <group delimiter=", ">
+          <group delimiter=" ">
+            <choose>
+              <if variable="title" match="none"/>
+              <else>
+                <text variable="genre" text-case="capitalize-first"/>
+              </else>
+            </choose>
+            <text macro="event"/>
+          </group>
+          <text variable="event-place"/>
+          <text macro="issued"/>
+        </group>
+      </else-if>
+      <!--Chicago doesn't use publisher/place for Newspapers -->
+      <else-if type="article-newspaper">
+        <text macro="issued"/>
+      </else-if>
+      <else-if variable="publisher-place publisher" match="any">
+        <group delimiter=", ">
+          <choose>
+            <if type="thesis">
+              <text variable="genre" text-case="capitalize-first"/>
+            </if>
+          </choose>
+          <text macro="publisher"/>
+          <text macro="issued"/>
+        </group>
+      </else-if>
+      <else>
+        <text macro="issued"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="access-note">
+    <group delimiter=", ">
+      <choose>
+        <if type="graphic report" match="any">
+          <text macro="archive-note"/>
+        </if>
+        <else-if type="article-journal article-magazine article-newspaper bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="none">
+          <text macro="archive-note"/>
+        </else-if>
+      </choose>
+      <choose>
+        <if variable="issued" match="none">
+          <group delimiter=" ">
+            <text term="accessed"/>
+            <date variable="accessed" form="text"/>
+          </group>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <choose>
+            <if variable="DOI">
+              <text variable="DOI" prefix="doi:"/>
+            </if>
+            <else>
+              <text variable="URL"/>
+            </else>
+          </choose>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="access">
+    <group delimiter=". ">
+      <choose>
+        <if type="graphic report" match="any">
+          <text macro="archive"/>
+        </if>
+        <else-if type="article-journal article-magazine article-newspaper bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="none">
+          <text macro="archive"/>
+        </else-if>
+      </choose>
+      <choose>
+        <if variable="issued" match="none">
+          <group delimiter=" ">
+            <text term="accessed" text-case="capitalize-first"/>
+            <date variable="accessed" form="text"/>
+          </group>
+        </if>
+      </choose>
+      <choose>
+        <if type="legal_case" match="none">
+          <choose>
+            <if variable="DOI">
+              <text variable="DOI" prefix="doi:"/>
+            </if>
+            <else>
+              <text variable="URL"/>
+            </else>
+          </choose>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="case-locator-subsequent">
+    <choose>
+      <if type="legal_case">
+        <text macro="locators-note"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="case-issue-subsequent">
+    <choose>
+      <if type="legal_case">
+        <text macro="issue"/>
+      </if>
+    </choose>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" disambiguate-add-names="true">
+    <layout suffix="." delimiter="; ">
+      <choose>
+        <if position="ibid-with-locator">
+          <group delimiter=", ">
+            <text term="ibid"/>
+            <text macro="point-locators-subsequent"/>
+          </group>
+        </if>
+        <else-if position="ibid">
+          <text term="ibid"/>
+        </else-if>
+        <else>
+          <group delimiter=", ">
+            <text macro="contributors-short"/>
+            <group delimiter=" ">
+              <group delimiter=", ">
+                <text macro="title-short"/>
+                <!--if title & author are the same: -->
+                <text macro="date-disambiguate"/>
+                <text macro="case-locator-subsequent"/>
+              </group>
+              <text macro="case-issue-subsequent"/>
+            </group>
+            <text macro="point-locators-subsequent"/>
+          </group>
+        </else>
+      </choose>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="11" et-al-use-first="7" subsequent-author-substitute="&#8212;&#8212;&#8212;" entry-spacing="0">
+    <sort>
+      <key macro="contributors-sort"/>
+      <key variable="title"/>
+      <key variable="genre"/>
+      <key variable="issued"/>
+    </sort>
+    <layout suffix=".">
+      <group delimiter=". ">
+        <group delimiter=": ">
+          <group delimiter=", ">
+            <group delimiter=" ">
+              <group delimiter=". ">
+                <group delimiter=" ">
+                  <group delimiter=", ">
+                    <group delimiter=". ">
+                      <group delimiter=". ">
+                        <text macro="contributors"/>
+                        <text macro="title"/>
+                      </group>
+                      <text macro="description"/>
+                      <text macro="secondary-contributors"/>
+                      <group delimiter=", ">
+                        <text macro="container-title"/>
+                        <text macro="container-contributors"/>
+                        <text macro="locators-chapter"/>
+                      </group>
+                      <text macro="locators-join-with-period"/>
+                    </group>
+                    <text macro="locators-join-with-comma"/>
+                  </group>
+                  <text macro="locators-join-with-space"/>
+                </group>
+                <text macro="collection-title"/>
+                <text macro="issue-join-with-period"/>
+              </group>
+              <text macro="issue-join-with-space"/>
+            </group>
+            <text macro="issue-join-with-comma"/>
+            <text macro="locators-newspaper"/>
+          </group>
+          <text macro="locators-journal"/>
+        </group>
+        <text macro="access"/>
+      </group>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/council-of-science-editors.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only" default-locale="en-US">
+  <!-- This style was edited with the Visual CSL Editor (http://steveridout.com/csl/visualEditor/) -->
+  <info>
+    <title>Council of Science Editors (CSE)</title>
+    <id>http://www.zotero.org/styles/council-of-science-editors</id>
+    <link href="http://www.zotero.org/styles/council-of-science-editors" rel="self"/>
+    <link href="http://bcs.bedfordstmartins.com/resdoc5e/RES5e_ch11_o.html" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <category citation-format="numeric"/>
+    <category field="science"/>
+    <summary>The Council of Science Editors style.</summary>
+    <updated>2012-09-09T21:58:08+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <macro name="editor">
+    <names variable="editor">
+      <name name-as-sort-order="all" sort-separator=" " initialize-with="" delimiter=", " delimiter-precedes-last="always"/>
+      <label form="long" prefix=", " text-case="lowercase" suffix="."/>
+    </names>
+  </macro>
+  <macro name="anon">
+    <text term="anonymous" form="short" text-case="capitalize-first" strip-periods="true"/>
+  </macro>
+  <macro name="author">
+    <group suffix=".">
+      <names variable="author">
+        <name name-as-sort-order="all" sort-separator=" " initialize-with="" delimiter=", " delimiter-precedes-last="always"/>
+        <label form="short" prefix=" " suffix="" text-case="lowercase" strip-periods="true"/>
+        <substitute>
+          <names variable="editor"/>
+          <text macro="anon"/>
+        </substitute>
+      </names>
+    </group>
+  </macro>
+  <macro name="author-short">
+    <names variable="author">
+      <name form="short" and="symbol" delimiter=", " initialize-with="."/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="anon"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="access">
+    <group>
+      <text value="Available from:" suffix=" "/>
+      <text variable="URL"/>
+    </group>
+  </macro>
+  <macro name="title">
+    <group delimiter=" ">
+      <text variable="title"/>
+      <choose>
+        <if type="thesis" match="any">
+          <text variable="genre" form="long" prefix="[" suffix="]"/>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": ">
+      <text variable="publisher-place"/>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="issued">
+    <date variable="issued" delimiter=" ">
+      <date-part name="year"/>
+      <date-part name="month" prefix=" "/>
+      <date-part name="day" prefix=" "/>
+    </date>
+    <group prefix=" [" suffix="]" delimiter=" ">
+      <text term="cited"/>
+      <date variable="accessed">
+        <date-part name="year"/>
+        <date-part name="month" prefix=" "/>
+        <date-part name="day" prefix=" "/>
+      </date>
+    </group>
+  </macro>
+  <macro name="pages">
+    <label variable="page" form="short" suffix=". " strip-periods="true"/>
+    <text variable="page"/>
+  </macro>
+  <macro name="journal">
+    <text variable="container-title"/>
+    <choose>
+      <if variable="URL">
+        <text term="internet" prefix=" [" suffix="]" text-case="capitalize-first"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short" suffix="." strip-periods="true"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition" suffix="."/>
+      </else>
+    </choose>
+  </macro>
+  <citation collapse="citation-number">
+    <sort>
+      <key variable="citation-number"/>
+    </sort>
+    <layout delimiter="," vertical-align="sup">
+      <text variable="citation-number"/>
+      <group prefix="(" suffix=")">
+        <label variable="locator" form="short" strip-periods="true"/>
+        <text variable="locator"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="false" et-al-min="11" et-al-use-first="10">
+    <layout>
+      <text variable="citation-number" prefix="" suffix=". "/>
+      <text macro="author" suffix=""/>
+      <choose>
+        <if type="bill book graphic legal_case legislation motion_picture report song thesis" match="any">
+          <group prefix=" " suffix="." delimiter=" ">
+            <text macro="title" suffix="."/>
+            <text macro="edition"/>
+            <text macro="editor" prefix="(" suffix=")"/>
+          </group>
+          <text prefix=" " suffix="" macro="publisher"/>
+          <group suffix="." prefix="; " delimiter=" ">
+            <date variable="issued">
+              <date-part name="year"/>
+            </date>
+            <text macro="pages"/>
+          </group>
+        </if>
+        <else-if type="chapter paper-conference" match="any">
+          <text macro="title" prefix=" " suffix="."/>
+          <group prefix=" " delimiter=" ">
+            <text term="in" text-case="capitalize-first" suffix=":"/>
+            <text macro="editor"/>
+            <text variable="container-title" suffix="."/>
+            <text variable="volume" prefix="Vol. " suffix="."/>
+            <text macro="edition"/>
+            <text variable="collection-title" suffix="."/>
+            <group suffix=".">
+              <text macro="publisher"/>
+              <group suffix="." prefix="; " delimiter=". ">
+                <date variable="issued">
+                  <date-part name="year"/>
+                </date>
+                <text macro="pages"/>
+              </group>
+            </group>
+          </group>
+        </else-if>
+        <else>
+          <group suffix=".">
+            <text macro="title" prefix=" "/>
+            <text macro="editor" prefix=" "/>
+          </group>
+          <group prefix=" " suffix=".">
+            <text macro="journal" suffix="."/>
+            <group delimiter=";" prefix=" ">
+              <text macro="issued"/>
+              <group>
+                <text variable="volume"/>
+                <text variable="issue" prefix="(" suffix=")"/>
+              </group>
+            </group>
+            <text variable="page" prefix=":"/>
+          </group>
+        </else>
+      </choose>
+      <text prefix=" " macro="access"/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/harvard1.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only">
+  <info>
+    <title>Harvard Reference format 1 (author-date)</title>
+    <id>http://www.zotero.org/styles/harvard1</id>
+    <link href="http://www.zotero.org/styles/harvard1" rel="self"/>
+    <link href="http://libweb.anglia.ac.uk/referencing/harvard.htm" rel="documentation"/>
+    <author>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </author>
+    <category citation-format="author-date"/>
+    <category field="generic-base"/>
+    <summary>The Harvard author-date style</summary>
+    <updated>2012-09-27T22:06:38+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <macro name="editor">
+    <names variable="editor" delimiter=", ">
+      <name and="symbol" initialize-with=". " delimiter=", "/>
+      <label form="short" prefix=", " text-case="lowercase" suffix="." strip-periods="true"/>
+    </names>
+  </macro>
+  <macro name="anon">
+    <text term="anonymous" form="short" text-case="capitalize-first" strip-periods="true"/>
+  </macro>
+  <macro name="author">
+    <names variable="author">
+      <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with="." delimiter-precedes-last="never" delimiter=", "/>
+      <label form="short" prefix=" " suffix="." text-case="lowercase" strip-periods="true"/>
+      <substitute>
+        <names variable="editor"/>
+        <text macro="anon"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="author-short">
+    <names variable="author">
+      <name form="short" and="symbol" delimiter=", " delimiter-precedes-last="never" initialize-with=". "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="anon"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if variable="URL">
+        <text value="Available at:" suffix=" "/>
+        <text variable="URL"/>
+        <group prefix=" [" suffix="]">
+          <text term="accessed" text-case="capitalize-first" suffix=" "/>
+          <date variable="accessed">
+            <date-part name="month" suffix=" "/>
+            <date-part name="day" suffix=", "/>
+            <date-part name="year"/>
+          </date>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song thesis" match="any">
+        <text variable="title" font-style="italic"/>
+      </if>
+      <else>
+        <text variable="title"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": ">
+      <text variable="publisher-place"/>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="year-date">
+    <choose>
+      <if variable="issued">
+        <date variable="issued">
+          <date-part name="year"/>
+        </date>
+      </if>
+      <else>
+        <text term="no date" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short" suffix="." strip-periods="true"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition" suffix="."/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="pages">
+    <group>
+      <label variable="page" form="short" suffix=" "/>
+      <text variable="page"/>
+    </group>
+  </macro>
+  <citation et-al-min="3" et-al-use-first="1" et-al-subsequent-min="3" et-al-subsequent-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true">
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=", ">
+        <group delimiter=" ">
+          <text macro="author-short"/>
+          <text macro="year-date"/>
+        </group>
+        <group>
+          <label variable="locator" suffix="." form="short" strip-periods="true"/>
+          <text variable="locator"/>
+        </group>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="4" et-al-use-first="1">
+    <sort>
+      <key macro="author"/>
+      <key variable="title"/>
+    </sort>
+    <layout>
+      <text macro="author" suffix=","/>
+      <date variable="issued" prefix=" " suffix=".">
+        <date-part name="year"/>
+      </date>
+      <choose>
+        <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+          <group prefix=" " delimiter=" " suffix=",">
+            <text macro="title"/>
+            <text macro="edition"/>
+            <text macro="editor"/>
+          </group>
+          <text prefix=" " suffix="." macro="publisher"/>
+        </if>
+        <else-if type="chapter paper-conference" match="any">
+          <text macro="title" prefix=" " suffix="."/>
+          <group prefix=" " delimiter=" ">
+            <text term="in" text-case="capitalize-first"/>
+            <text macro="editor"/>
+            <text variable="container-title" font-style="italic" suffix="."/>
+            <text variable="collection-title" suffix="."/>
+            <text variable="event" suffix="."/>
+            <group suffix="." delimiter=", ">
+              <text macro="publisher" prefix=" "/>
+              <text macro="pages"/>
+            </group>
+          </group>
+        </else-if>
+        <else-if type="thesis">
+          <group prefix=" " suffix="." delimiter=". ">
+            <text macro="title"/>
+            <text variable="genre"/>
+            <text macro="publisher"/>
+          </group>
+        </else-if>
+        <else>
+          <group suffix=".">
+            <text macro="title" prefix=" "/>
+            <text macro="editor" prefix=" "/>
+          </group>
+          <group prefix=" " suffix=".">
+            <text variable="container-title" font-style="italic"/>
+            <group prefix=", ">
+              <text variable="volume"/>
+              <text variable="issue" prefix="(" suffix=")"/>
+            </group>
+            <group prefix=", ">
+              <label variable="page" suffix="." form="short" strip-periods="true"/>
+              <text variable="page"/>
+            </group>
+          </group>
+        </else>
+      </choose>
+      <text prefix=" " macro="access" suffix="."/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/ieee.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,299 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only">
+  <info>
+    <title>IEEE</title>
+    <id>http://www.zotero.org/styles/ieee</id>
+    <link href="http://www.zotero.org/styles/ieee" rel="self"/>
+    <link href="http://www.ieee.org/portal/cms_docs_iportals/iportals/publications/authors/transjnl/stylemanual.pdf" rel="documentation"/>
+    <link href="http://www.ieee.org/documents/auinfo07.pdf" rel="documentation"/>
+    <author>
+      <name>Michael Berkowitz</name>
+      <email>mberkowi@gmu.edu</email>
+    </author>
+    <contributor>
+      <name>Julian Onions</name>
+      <email>julian.onions@gmail.com</email>
+    </contributor>
+    <contributor>
+      <name>Rintze Zelle</name>
+      <uri>http://twitter.com/rintzezelle</uri>
+    </contributor>
+    <contributor>
+      <name>Stephen Frank</name>
+      <uri>http://www.zotero.org/sfrank</uri>
+    </contributor>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <category citation-format="numeric"/>
+    <category field="engineering"/>
+    <category field="generic-base"/>
+    <updated>2012-10-18T22:38:43+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <!-- Macros -->
+  <macro name="edition">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition" text-case="capitalize-first" suffix="."/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="issued">
+    <choose>
+      <if type="article-journal report" match="any">
+        <date variable="issued">
+          <date-part name="month" form="short" suffix=" "/>
+          <date-part name="year" form="long"/>
+        </date>
+      </if>
+      <else-if type=" bill book chapter graphic legal_case legislation motion_picture paper-conference song thesis" match="any">
+        <date variable="issued">
+          <date-part name="year" form="long"/>
+        </date>
+      </else-if>
+      <else>
+        <date variable="issued">
+          <date-part name="day" form="numeric-leading-zeros" suffix="-"/>
+          <date-part name="month" form="short" suffix="-" strip-periods="true"/>
+          <date-part name="year" form="long"/>
+        </date>
+      </else>
+    </choose>
+  </macro>
+  <macro name="author">
+    <names variable="author">
+      <name initialize-with=". " delimiter=", " and="text"/>
+      <label form="short" prefix=", " text-case="capitalize-first"/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="editor">
+    <names variable="editor">
+      <name initialize-with=". " delimiter=", " and="text"/>
+      <label form="short" prefix=", " text-case="capitalize-first"/>
+    </names>
+  </macro>
+  <macro name="locators">
+    <group delimiter=", ">
+      <text macro="edition"/>
+      <group delimiter=" ">
+        <text term="volume" form="short"/>
+        <number variable="volume" form="numeric"/>
+      </group>
+      <group delimiter=" ">
+        <number variable="number-of-volumes" form="numeric"/>
+        <text term="volume" form="short" plural="true"/>
+      </group>
+      <group delimiter=" ">
+        <text term="issue" form="short"/>
+        <number variable="issue" form="numeric"/>
+      </group>
+    </group>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture song" match="any">
+        <text variable="title" font-style="italic"/>
+      </if>
+      <else>
+        <text variable="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="publisher">
+    <choose>
+      <if type=" bill book chapter graphic legal_case legislation motion_picture paper-conference song" match="any">
+        <text variable="publisher-place" suffix=": "/>
+        <text variable="publisher"/>
+      </if>
+      <else>
+        <group delimiter=", ">
+          <text variable="publisher"/>
+          <text variable="publisher-place"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="event">
+    <choose>
+      <if type="paper-conference">
+        <choose>
+          <!-- Published Conference Paper -->
+          <if variable="container-title">
+            <group delimiter=", ">
+              <text variable="container-title" prefix="in " font-style="italic"/>
+              <text variable="event-place"/>
+            </group>
+          </if>
+          <!-- Unpublished Conference Paper -->
+          <else>
+            <group delimiter=", ">
+              <text variable="event" prefix="presented at the "/>
+              <text variable="event-place"/>
+            </group>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if type="webpage">
+        <choose>
+          <if variable="URL">
+            <group delimiter=". ">
+              <text value="[Online]"/>
+              <text variable="URL" prefix="Available: "/>
+              <group prefix="[" suffix="]">
+                <date variable="accessed" prefix="Accessed: ">
+                  <date-part name="day" form="numeric-leading-zeros" suffix="-"/>
+                  <date-part name="month" form="short" suffix="-" strip-periods="true"/>
+                  <date-part name="year" form="long"/>
+                </date>
+              </group>
+            </group>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="page">
+    <group>
+      <label variable="page" form="short" suffix=" "/>
+      <text variable="page"/>
+    </group>
+  </macro>
+  <!-- Citation -->
+  <citation collapse="citation-number">
+    <sort>
+      <key variable="citation-number"/>
+    </sort>
+    <layout delimiter=", ">
+      <text variable="citation-number" prefix="[" suffix="]"/>
+    </layout>
+  </citation>
+  <!-- Bibliography -->
+  <bibliography entry-spacing="0" second-field-align="flush">
+    <layout suffix=".">
+      <!-- Citation Number -->
+      <text variable="citation-number" prefix="[" suffix="]"/>
+      <!-- Author(s) -->
+      <text macro="author" suffix=", "/>
+      <!-- Rest of Citation -->
+      <choose>
+        <!-- Specific Formats -->
+        <if type="article-journal">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text variable="container-title" font-style="italic" form="short"/>
+            <text macro="locators"/>
+            <text macro="page"/>
+            <text macro="issued"/>
+          </group>
+        </if>
+        <else-if type="paper-conference">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text macro="event"/>
+            <text macro="issued"/>
+            <text macro="locators"/>
+            <text macro="page"/>
+          </group>
+        </else-if>
+        <else-if type="report">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text macro="publisher"/>
+            <group delimiter=" ">
+              <text variable="genre"/>
+              <text variable="number"/>
+            </group>
+            <text macro="issued"/>
+          </group>
+        </else-if>
+        <else-if type="thesis">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text variable="genre"/>
+            <text macro="publisher"/>
+            <text macro="issued"/>
+          </group>
+        </else-if>
+        <else-if type="webpage">
+          <group delimiter=", " suffix=". ">
+            <text macro="title"/>
+            <text variable="container-title" font-style="italic"/>
+            <text macro="issued"/>
+          </group>
+          <text macro="access"/>
+        </else-if>
+        <else-if type="patent">
+          <text macro="title" suffix=", "/>
+          <text variable="number" prefix="U.S. Patent "/>
+          <text macro="issued"/>
+        </else-if>
+        <!-- Generic/Fallback Formats -->
+        <else-if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+          <group delimiter=", " suffix=". ">
+            <text macro="title"/>
+            <text macro="locators"/>
+          </group>
+          <group delimiter=", ">
+            <text macro="publisher"/>
+            <text macro="issued"/>
+            <text macro="page"/>
+          </group>
+        </else-if>
+        <else-if type="article-magazine article-newspaper broadcast interview manuscript map patent personal_communication song speech thesis webpage" match="any">
+          <group delimiter=", ">
+            <text macro="title"/>
+            <text variable="container-title" font-style="italic"/>
+            <text macro="locators"/>
+            <text macro="publisher"/>
+            <text macro="page"/>
+            <text macro="issued"/>
+          </group>
+        </else-if>
+        <else-if type="chapter paper-conference" match="any">
+          <group delimiter=", " suffix=", ">
+            <text macro="title"/>
+            <text variable="container-title" prefix="in " font-style="italic"/>
+            <text macro="locators"/>
+          </group>
+          <text macro="editor" suffix=" "/>
+          <group delimiter=", ">
+            <text macro="publisher"/>
+            <text macro="issued"/>
+            <text macro="page"/>
+          </group>
+        </else-if>
+        <else>
+          <group delimiter=", " suffix=". ">
+            <text macro="title"/>
+            <text variable="container-title" font-style="italic"/>
+            <text macro="locators"/>
+          </group>
+          <group delimiter=", ">
+            <text macro="publisher"/>
+            <text macro="page"/>
+            <text macro="issued"/>
+          </group>
+        </else>
+      </choose>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/mhra.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,416 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="note" version="1.0" demote-non-dropping-particle="sort-only" default-locale="en-GB">
+  <info>
+    <title>Modern Humanities Research Association (note with bibliography)</title>
+    <id>http://www.zotero.org/styles/mhra</id>
+    <link href="http://www.zotero.org/styles/mhra" rel="self"/>
+    <link href="http://www.mhra.org.uk/Publications/Books/StyleGuide/download.shtml" rel="documentation"/>
+    <author>
+      <name>Rintze Zelle</name>
+      <uri>http://twitter.com/rintzezelle</uri>
+    </author>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <category citation-format="note"/>
+    <category field="generic-base"/>
+    <summary>MHRA format with full notes and bibliography</summary>
+    <updated>2012-09-27T22:06:38+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="et-al">and others</term>
+      <term name="editor" form="verb-short">ed. by</term>
+      <term name="edition" form="short">edn</term>
+      <term name="translator" form="verb-short">trans. by</term>
+    </terms>
+  </locale>
+  <macro name="author">
+    <names variable="author">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", " suffix="."/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title-note"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="contributors-note">
+    <names variable="author">
+      <name and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="never"/>
+    </names>
+    <text macro="recipient-note"/>
+  </macro>
+  <macro name="title-note">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <text variable="title" font-style="italic" text-case="title"/>
+      </if>
+      <else>
+        <text variable="title" quotes="true" text-case="title"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title-short">
+    <choose>
+      <if disambiguate="true">
+        <choose>
+          <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+            <text variable="title" font-style="italic" text-case="title" form="short"/>
+          </if>
+          <else>
+            <text variable="title" quotes="true" text-case="title" form="short"/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="title-sort-substitute">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <text variable="title" font-style="italic" text-case="title" form="short"/>
+      </if>
+      <else>
+        <text variable="title" quotes="true" text-case="title" form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="editor-translator">
+    <group delimiter=", ">
+      <names variable="editor" delimiter=", ">
+        <label form="verb-short" text-case="lowercase" suffix=" "/>
+        <name and="text" delimiter=", " delimiter-precedes-last="never"/>
+      </names>
+      <choose>
+        <if variable="author editor" match="any">
+          <names variable="translator" delimiter=", ">
+            <label form="verb-short" text-case="lowercase" suffix=" "/>
+            <name and="text" delimiter=", " delimiter-precedes-last="never"/>
+          </names>
+        </if>
+      </choose>
+    </group>
+  </macro>
+  <macro name="collection-title">
+    <text variable="collection-title" text-case="title"/>
+    <text variable="collection-number" prefix=", "/>
+  </macro>
+  <macro name="locators-note">
+    <choose>
+      <if type="article-journal">
+        <text variable="volume"/>
+      </if>
+      <else-if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <group delimiter=", ">
+          <text macro="edition-note"/>
+          <group>
+            <number variable="number-of-volumes" form="numeric"/>
+            <text term="volume" form="short" prefix=" " plural="true"/>
+          </group>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="volume">
+    <choose>
+      <if type="article-journal">
+        <text variable="volume"/>
+      </if>
+      <else-if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <group delimiter=", ">
+          <text macro="edition-note"/>
+          <group>
+            <number variable="number-of-volumes" form="numeric"/>
+            <text term="volume" form="short" prefix=" " plural="true"/>
+          </group>
+        </group>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="issue-note">
+    <choose>
+      <if type="article-journal">
+        <choose>
+          <if variable="volume">
+            <text macro="issued" prefix=" (" suffix=")"/>
+          </if>
+          <else>
+            <text macro="issued" prefix=", "/>
+          </else>
+        </choose>
+      </if>
+      <else-if variable="publisher-place publisher" match="any">
+        <group prefix=" (" suffix=")" delimiter=", ">
+          <group delimiter=" ">
+            <choose>
+              <if variable="title" match="none"/>
+              <else-if type="thesis speech" match="any">
+                <text variable="genre" prefix="unpublished "/>
+              </else-if>
+            </choose>
+            <text macro="event"/>
+          </group>
+          <text macro="publisher"/>
+          <text macro="issued"/>
+        </group>
+      </else-if>
+      <else>
+        <text macro="issued" prefix=", "/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="locators-specific-note">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <choose>
+          <if is-numeric="volume">
+            <number variable="volume" form="roman" font-variant="small-caps"/>
+          </if>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-title-note">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <text term="in" text-case="lowercase" suffix=" "/>
+      </if>
+    </choose>
+    <text variable="container-title" font-style="italic"/>
+  </macro>
+  <macro name="edition-note">
+    <choose>
+      <if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song" match="any">
+        <choose>
+          <if is-numeric="edition">
+            <group delimiter=" ">
+              <number variable="edition" form="ordinal"/>
+              <text term="edition" form="short"/>
+            </group>
+          </if>
+          <else>
+            <text variable="edition"/>
+          </else>
+        </choose>
+      </if>
+    </choose>
+  </macro>
+  <macro name="editor-note">
+    <names variable="editor">
+      <name and="text" sort-separator=", " delimiter=", "/>
+      <label form="short" prefix=", " suffix="."/>
+    </names>
+  </macro>
+  <macro name="translator-note">
+    <names variable="translator">
+      <name and="text" sort-separator=", " delimiter=", "/>
+      <label form="verb-short" prefix=", " suffix="."/>
+    </names>
+  </macro>
+  <macro name="recipient-note">
+    <names variable="recipient" delimiter=", ">
+      <label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="recipient-short">
+    <names variable="recipient">
+      <label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
+      <name form="short" and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="contributors-short">
+    <names variable="author">
+      <name form="short" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="never"/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title-sort-substitute"/>
+      </substitute>
+    </names>
+    <text macro="recipient-short"/>
+  </macro>
+  <macro name="interviewer-note">
+    <names variable="interviewer" delimiter=", ">
+      <label form="verb" prefix=" " text-case="lowercase" suffix=" "/>
+      <name and="text" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="locators-newspaper">
+    <choose>
+      <if type="article-newspaper">
+        <group delimiter=", ">
+          <group>
+            <text variable="edition" suffix=" "/>
+            <text term="edition" prefix=" "/>
+          </group>
+          <group>
+            <text term="section" suffix=" "/>
+            <text variable="section"/>
+          </group>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="event">
+    <group>
+      <text term="presented at" suffix=" "/>
+      <text variable="event"/>
+    </group>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": ">
+      <text variable="publisher-place"/>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="issued">
+    <choose>
+      <if type="graphic report article-newspaper" match="any">
+        <date variable="issued">
+          <date-part name="day" suffix=" "/>
+          <date-part name="month" suffix=" "/>
+          <date-part name="year"/>
+        </date>
+      </if>
+      <else-if type="bill book chapter graphic legal_case legislation motion_picture paper-conference report song thesis" match="any">
+        <date variable="issued">
+          <date-part name="year"/>
+        </date>
+      </else-if>
+      <else>
+        <date variable="issued">
+          <date-part name="year"/>
+        </date>
+      </else>
+    </choose>
+  </macro>
+  <macro name="pages">
+    <choose>
+      <if type="article-journal">
+        <text variable="page" prefix=", "/>
+      </if>
+      <else>
+        <choose>
+          <if variable="volume">
+            <text variable="page" prefix=", "/>
+          </if>
+          <else>
+            <label variable="page" form="short" prefix=", " suffix=" "/>
+            <text variable="page"/>
+          </else>
+        </choose>
+      </else>
+    </choose>
+  </macro>
+  <macro name="point-locators">
+    <text macro="pages"/>
+    <choose>
+      <if variable="page">
+        <group prefix=" (" suffix=")">
+          <label variable="locator" form="short" suffix=" "/>
+          <text variable="locator"/>
+        </group>
+      </if>
+      <else>
+        <label variable="locator" form="short" prefix=", " suffix=" "/>
+        <text variable="locator"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="point-locators-subsequent">
+    <label variable="locator" form="short" prefix=", " suffix=" "/>
+    <text variable="locator"/>
+  </macro>
+  <macro name="archive-note">
+    <group delimiter=", ">
+      <text variable="archive_location"/>
+      <text variable="archive"/>
+      <text variable="archive-place"/>
+    </group>
+  </macro>
+  <macro name="access-note">
+    <group delimiter=", ">
+      <choose>
+        <if type="graphic report" match="any">
+          <text macro="archive-note" prefix=", "/>
+        </if>
+        <else-if type="article-journal article-magazine article-newspaper bill book chapter graphic legal_case legislation motion_picture paper-conference report song thesis" match="none">
+          <text macro="archive-note" prefix=", "/>
+        </else-if>
+      </choose>
+    </group>
+    <choose>
+      <if variable="DOI">
+        <text variable="DOI" prefix=" &lt;doi:" suffix="&gt;"/>
+      </if>
+      <else>
+        <choose>
+          <if variable="URL">
+            <text variable="URL" prefix=" &lt;" suffix="&gt;"/>
+            <group prefix=" [" suffix="]">
+              <text term="accessed" text-case="lowercase"/>
+              <date variable="accessed">
+                <date-part name="day" prefix=" "/>
+                <date-part name="month" prefix=" "/>
+                <date-part name="year" prefix=" "/>
+              </date>
+            </group>
+          </if>
+        </choose>
+      </else>
+    </choose>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" disambiguate-add-names="true" disambiguate-add-givenname="true">
+    <layout prefix="" suffix="." delimiter="; ">
+      <choose>
+        <if position="subsequent">
+          <group delimiter=", ">
+            <text macro="contributors-short"/>
+            <text macro="title-short"/>
+            <text macro="locators-specific-note"/>
+          </group>
+          <text macro="point-locators-subsequent"/>
+        </if>
+        <else>
+          <group delimiter=", ">
+            <text macro="contributors-note"/>
+            <text macro="title-note"/>
+            <text macro="container-title-note"/>
+            <text macro="editor-translator"/>
+            <text macro="collection-title"/>
+            <text macro="locators-note"/>
+          </group>
+          <text macro="issue-note"/>
+          <text macro="locators-specific-note" prefix=", "/>
+          <text macro="locators-newspaper" prefix=", "/>
+          <text macro="point-locators"/>
+          <text macro="access-note"/>
+        </else>
+      </choose>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="7" et-al-use-first="6" subsequent-author-substitute="---">
+    <sort>
+      <key macro="author"/>
+      <key variable="title"/>
+    </sort>
+    <layout>
+      <group delimiter=", ">
+        <text macro="author"/>
+        <text macro="title-note"/>
+        <text macro="container-title-note"/>
+        <text macro="editor-translator"/>
+        <text macro="collection-title"/>
+        <text macro="volume"/>
+      </group>
+      <text macro="issue-note"/>
+      <text macro="locators-specific-note" prefix=", "/>
+      <text macro="locators-newspaper" prefix=", "/>
+      <text macro="pages"/>
+      <text macro="access-note"/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/mla.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only">
+  <info>
+    <title>Modern Language Association</title>
+    <id>http://www.zotero.org/styles/mla</id>
+    <link href="http://www.zotero.org/styles/mla" rel="self"/>
+    <link href="http://owl.english.purdue.edu/owl/section/2/11/" rel="documentation"/>
+    <author>
+      <name>Ilouise S. Bradford</name>
+      <email>isbradford@gmail.com</email>
+    </author>
+    <contributor>
+      <name>Sarah Ficke</name>
+      <email>sficke@email.unc.edu</email>
+    </contributor>
+    <contributor>
+      <name>Sebastian Karcher</name>
+      <email>karcher@u.northwestern.edu</email>
+    </contributor>
+    <contributor>
+      <name>Christian Werthschulte</name>
+      <email>Christian.Werthschulte@rub.de</email>
+    </contributor>
+    <contributor>
+      <name>Simon Kornblith</name>
+      <email>simon@simonster.com</email>
+    </contributor>
+    <contributor>
+      <name>James Johnston</name>
+      <email>thejamesjohnston@gmail.com</email>
+    </contributor>
+    <category citation-format="author"/>
+    <category field="generic-base"/>
+    <summary>This style adheres to the MLA 7th edition handbook and contains modifications to these types of sources: e-mail, forum posts, interviews, manuscripts, maps, presentations, TV broadcasts, and web pages.</summary>
+    <updated>2012-10-26T01:15:26+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="month-01" form="short">Jan.</term>
+      <term name="month-02" form="short">Feb.</term>
+      <term name="month-03" form="short">Mar.</term>
+      <term name="month-04" form="short">Apr.</term>
+      <term name="month-05" form="short">May</term>
+      <term name="month-06" form="short">June</term>
+      <term name="month-07" form="short">July</term>
+      <term name="month-08" form="short">Aug.</term>
+      <term name="month-09" form="short">Sept.</term>
+      <term name="month-10" form="short">Oct.</term>
+      <term name="month-11" form="short">Nov.</term>
+      <term name="month-12" form="short">Dec.</term>
+      <term name="volume" form="short">
+        <single>Vol.</single>
+        <multiple>vols</multiple>
+      </term>
+      <term name="edition" form="short">ed</term>
+      <term name="editor" form="verb-short">ed.</term>
+      <term name="translator" form="verb-short">trans.</term>
+    </terms>
+  </locale>
+  <macro name="editor-translator">
+    <names variable="editor translator" delimiter=". ">
+      <label form="verb-short" text-case="capitalize-first" suffix=". " strip-periods="true"/>
+      <name and="symbol" delimiter=", "/>
+    </names>
+  </macro>
+  <macro name="author">
+    <names variable="author">
+      <name name-as-sort-order="first" and="text" sort-separator=", " delimiter=", " delimiter-precedes-last="always"/>
+      <label form="short" prefix=", " suffix="." strip-periods="true"/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="author-short">
+    <names variable="author">
+      <name form="short" and="text" delimiter=", " initialize-with=". "/>
+      <substitute>
+        <names variable="editor"/>
+        <names variable="translator"/>
+        <text macro="title-short"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="access">
+    <group delimiter=" ">
+      <date variable="accessed">
+        <date-part name="day" suffix=" "/>
+        <date-part name="month" form="short" suffix=" " strip-periods="false"/>
+        <date-part name="year"/>
+      </date>
+    </group>
+  </macro>
+  <macro name="medium">
+    <choose>
+      <if type="motion_picture">
+        <choose>
+          <if variable="medium">
+            <text variable="medium" prefix=" "/>
+          </if>
+          <else>
+            <text value="Film" prefix=" "/>
+          </else>
+        </choose>
+      </if>
+      <else-if type="broadcast">
+        <choose>
+          <if variable="medium">
+            <text variable="medium" prefix=" "/>
+          </if>
+          <else>
+            <text value="Television" prefix=" "/>
+          </else>
+        </choose>
+      </else-if>
+      <else-if type="manuscript">
+        <text value=""/>
+      </else-if>
+      <else-if type="personal_communication" match="any">
+        <text value="" prefix=" "/>
+      </else-if>
+      <else-if type="speech" match="any">
+        <text value=""/>
+      </else-if>
+      <else-if type="interview">
+        <text variable="medium" prefix=" "/>
+      </else-if>
+      <else-if type="song">
+        <choose>
+          <if variable="medium">
+            <text variable="medium" prefix=" "/>
+          </if>
+          <else>
+            <text value="Audio Recording" prefix=" "/>
+          </else>
+        </choose>
+      </else-if>
+      <else>
+        <choose>
+          <if variable="URL DOI" match="any">
+            <text variable="source" prefix=" " suffix=". " font-style="italic"/>
+            <text value="Web" prefix=" "/>
+            <text prefix=". " suffix="." macro="access"/>
+          </if>
+          <else>
+            <text value="Print" prefix=" "/>
+          </else>
+        </choose>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title">
+    <choose>
+      <if type="bill book graphic legal_case legislation manuscript motion_picture report song" match="any">
+        <text variable="title" font-style="italic" text-case="title"/>
+      </if>
+      <else-if type="interview personal_communication" match="any">
+        <text variable="title" text-case="title" quotes="false"/>
+      </else-if>
+      <else>
+        <text variable="title" text-case="title" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title-short">
+    <choose>
+      <if type="bill book graphic legal_case legislation manuscript motion_picture report song" match="any">
+        <text variable="title" text-case="title" form="short" font-style="italic"/>
+      </if>
+      <else>
+        <text variable="title" text-case="title" form="short" quotes="true"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="pages">
+    <choose>
+      <if variable="page">
+        <text variable="page"/>
+      </if>
+      <else-if type="personal_communication interview" match="any">
+        <text value=""/>
+      </else-if>
+      <else>
+        <text value="n. pag"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short" suffix="." strip-periods="true"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="volume">
+    <choose>
+      <if is-numeric="volume">
+        <group delimiter=" ">
+          <text term="volume" form="short" strip-periods="false"/>
+          <number variable="volume"/>
+        </group>
+      </if>
+      <else>
+        <text variable="volume"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="number-of-volumes">
+    <choose>
+      <if is-numeric="number-of-volumes">
+        <group delimiter=" ">
+          <number variable="number-of-volumes"/>
+          <text term="volume" form="short" plural="true" strip-periods="true"/>
+        </group>
+      </if>
+      <else>
+        <text variable="number-of-volumes"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="collection-title">
+    <text variable="collection-title" text-case="title" prefix=" "/>
+  </macro>
+  <macro name="collection-number">
+    <text variable="collection-number" prefix=" " suffix="."/>
+  </macro>
+  <macro name="publisher-year">
+    <group delimiter=", ">
+      <group delimiter=": ">
+        <text variable="publisher-place"/>
+        <text variable="publisher"/>
+      </group>
+      <date variable="issued">
+        <date-part name="year"/>
+      </date>
+    </group>
+  </macro>
+  <citation et-al-min="4" et-al-use-first="1" disambiguate-add-names="true" disambiguate-add-givenname="true">
+    <layout prefix="(" suffix=")" delimiter="; ">
+      <group delimiter=" ">
+        <choose>
+          <if variable="author editor translator" match="any">
+            <group delimiter=", ">
+              <text macro="author-short"/>
+              <choose>
+                <if disambiguate="true">
+                  <text macro="title-short"/>
+                </if>
+              </choose>
+            </group>
+          </if>
+          <else>
+            <text macro="title-short"/>
+          </else>
+        </choose>
+        <text variable="locator"/>
+      </group>
+    </layout>
+  </citation>
+  <bibliography hanging-indent="true" et-al-min="4" et-al-use-first="1" line-spacing="2" entry-spacing="0" subsequent-author-substitute="---">
+    <sort>
+      <key macro="author"/>
+      <key variable="title"/>
+    </sort>
+    <layout suffix=".">
+      <text macro="author" suffix="."/>
+      <text macro="title" prefix=" " suffix="."/>
+      <choose>
+        <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+          <text macro="edition" prefix=" " suffix="."/>
+          <text macro="editor-translator" prefix=" " suffix="."/>
+          <text macro="volume" prefix=" " suffix="."/>
+          <text macro="number-of-volumes" prefix=" " suffix="."/>
+          <text macro="publisher-year" prefix=" " suffix="."/>
+        </if>
+        <else-if type="chapter paper-conference" match="any">
+          <group>
+            <text variable="container-title" text-case="title" font-style="italic" prefix=" " suffix="."/>
+            <text macro="edition" prefix=" " suffix="."/>
+            <text macro="editor-translator" prefix=" " suffix="."/>
+            <text macro="volume" prefix=" " suffix="."/>
+            <text macro="number-of-volumes" prefix=" " suffix="."/>
+            <text macro="publisher-year" prefix=" " suffix="."/>
+          </group>
+          <text variable="page" prefix=" " suffix="."/>
+        </else-if>
+        <else-if type="manuscript">
+          <date variable="issued" prefix=" " suffix=".">
+            <date-part name="year"/>
+          </date>
+          <text variable="genre" prefix=" " suffix="."/>
+          <text variable="archive_location" prefix=" " suffix="."/>
+          <text variable="publisher-place" prefix=" "/>
+        </else-if>
+        <else-if type="personal_communication">
+          <date variable="issued" prefix=" " suffix=".">
+            <date-part name="day" suffix=" "/>
+            <date-part name="month" form="short" suffix=" "/>
+            <date-part name="year"/>
+          </date>
+          <choose>
+            <if variable="genre">
+              <text prefix=" " suffix="." variable="genre"/>
+            </if>
+            <else>
+              <text prefix=" " suffix="." value="E-mail"/>
+            </else>
+          </choose>
+        </else-if>
+        <else-if type="map">
+          <text variable="genre" prefix=" " suffix="."/>
+          <text variable="publisher-place" prefix=" " suffix=":"/>
+          <text variable="publisher" prefix=" "/>
+          <date variable="issued" prefix=" " suffix=",">
+            <date-part name="year"/>
+          </date>
+        </else-if>
+        <else-if type="speech">
+          <text variable="event" prefix=" " suffix="."/>
+          <text variable="publisher-place" prefix=" " suffix="."/>
+          <date variable="issued" prefix=" " suffix=".">
+            <date-part name="year"/>
+          </date>
+          <text variable="genre" prefix=" " suffix="."/>
+        </else-if>
+        <else-if type="webpage">
+          <text variable="container-title" font-style="italic" prefix=" " suffix="."/>
+          <text variable="genre" prefix=" " suffix="."/>
+          <date variable="issued" prefix=" " suffix=".">
+            <date-part name="day" suffix=" "/>
+            <date-part name="month" form="short" suffix=" " strip-periods="false"/>
+            <date-part name="year"/>
+          </date>
+        </else-if>
+        <else-if type="broadcast">
+          <text variable="container-title" font-style="italic" prefix=" " suffix="."/>
+          <text variable="publisher" prefix=" " suffix=","/>
+          <date variable="issued" prefix=" " suffix=".">
+            <date-part name="day" suffix=" "/>
+            <date-part name="month" form="short" suffix=" " strip-periods="false"/>
+            <date-part name="year"/>
+          </date>
+        </else-if>
+        <else>
+          <group prefix=" " suffix="." delimiter=": ">
+            <group delimiter=" ">
+              <text macro="editor-translator" suffix="."/>
+              <text variable="container-title" font-style="italic"/>
+              <choose>
+                <if type="article-journal">
+                  <group delimiter=" ">
+                    <group delimiter=".">
+                      <text variable="volume"/>
+                      <text variable="issue"/>
+                    </group>
+                    <date variable="issued" prefix="(" suffix="):">
+                      <date-part name="year"/>
+                    </date>
+                  </group>
+                  <text macro="pages" prefix=" "/>
+                </if>
+                <else>
+                  <date variable="issued">
+                    <date-part name="day" suffix=" "/>
+                    <date-part name="month" form="short" suffix=" " strip-periods="false"/>
+                    <date-part name="year"/>
+                  </date>
+                  <choose>
+                    <if variable="URL DOI" match="any">
+                      <text variable="page" prefix=": "/>
+                    </if>
+                    <else>
+                      <text macro="pages" prefix=": "/>
+                    </else>
+                  </choose>
+                </else>
+              </choose>
+            </group>
+          </group>
+        </else>
+      </choose>
+      <text macro="medium" suffix="."/>
+      <text macro="collection-title"/>
+      <text macro="collection-number"/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/national-library-of-medicine-grant.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only" default-locale="en-US">
+  <info>
+    <title>National Library of Medicine (NLM) - Grant with PMID</title>
+    <id>http://www.zotero.org/styles/national-library-of-medicine-grant</id>
+    <link href="http://www.zotero.org/styles/national-library-of-medicine-grant" rel="self"/>
+    <link href="http://www.nlm.nih.gov/pubs/formats/recommendedformats1991-full.pdf" rel="documentation"/>
+    <author>
+      <name>Michael Berkowitz</name>
+      <email>mberkowi@gmu.edu</email>
+    </author>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <contributor>
+      <name>Matt Tracy</name>
+    </contributor>
+    <category citation-format="numeric"/>
+    <category field="medicine"/>
+    <summary>Edited this to add PMID from extra field in bibliography </summary>
+    <updated>2012-09-27T22:06:38+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="retrieved">available</term>
+      <term name="section" form="short">sect.</term>
+    </terms>
+  </locale>
+  <locale xml:lang="de">
+    <terms>
+      <term name="retrieved">verfügbar</term>
+      <term name="from">unter</term>
+    </terms>
+  </locale>
+  <macro name="author">
+    <names variable="author">
+      <name sort-separator=" " initialize-with="" name-as-sort-order="all" delimiter=", " delimiter-precedes-last="always"/>
+      <label form="long" prefix=", "/>
+      <substitute>
+        <names variable="editor"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="editor">
+    <group delimiter=": ">
+      <choose>
+        <if type="chapter paper-conference" match="any">
+          <text term="in" text-case="capitalize-first"/>
+        </if>
+      </choose>
+      <names variable="editor" suffix=".">
+        <name sort-separator=" " initialize-with="" name-as-sort-order="all" delimiter=", " delimiter-precedes-last="always"/>
+        <label form="long" prefix=", "/>
+      </names>
+    </group>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": " suffix=";">
+      <choose>
+        <if type="thesis">
+          <text variable="publisher-place" prefix="[" suffix="]"/>
+        </if>
+        <else>
+          <text variable="publisher-place"/>
+        </else>
+      </choose>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if variable="URL">
+        <group delimiter=": ">
+          <group delimiter=" ">
+            <text term="retrieved" text-case="capitalize-first"/>
+            <text term="from"/>
+          </group>
+          <text variable="URL"/>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="accessed-date">
+    <choose>
+      <if variable="URL">
+        <group prefix="[" suffix="]" delimiter=" ">
+          <text term="cited" text-case="lowercase"/>
+          <date variable="accessed" suffix="">
+            <date-part name="year"/>
+            <date-part name="month" prefix=" " form="short" strip-periods="true"/>
+            <date-part name="day" prefix=" "/>
+          </date>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-title">
+    <choose>
+      <if type="article-journal article-magazine chapter paper-conference article-newspaper" match="any">
+        <group suffix="." delimiter=" ">
+          <text variable="container-title" form="short"/>
+          <choose>
+            <if variable="URL">
+              <text term="internet" prefix="[" suffix="]" text-case="capitalize-first"/>
+            </if>
+          </choose>
+        </group>
+        <text macro="edition" prefix=" "/>
+      </if>
+      <!--add event-name and event-place once they become available-->
+      <else-if type="bill legislation" match="any">
+        <group delimiter=", ">
+          <group delimiter=". ">
+            <text variable="container-title" form="short"/>
+            <group delimiter=" ">
+              <text term="section" form="short" text-case="capitalize-first"/>
+              <text variable="section"/>
+            </group>
+          </group>
+          <text variable="number"/>
+        </group>
+      </else-if>
+      <else>
+        <text variable="container-title" suffix="." form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title">
+    <text variable="title"/>
+    <choose>
+      <if type="article-journal article-magazine chapter paper-conference article-newspaper" match="none">
+        <choose>
+          <if variable="URL">
+            <text term="internet" prefix=" [" suffix="]" text-case="capitalize-first"/>
+          </if>
+        </choose>
+        <text macro="edition" prefix=". "/>
+      </if>
+    </choose>
+    <choose>
+      <if type="thesis">
+        <text variable="genre" prefix=" [" suffix="]"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition" suffix="."/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date">
+    <choose>
+      <if type="article-journal article-magazine article-newspaper" match="any">
+        <group suffix=";" delimiter=" ">
+          <date variable="issued" delimiter=" ">
+            <date-part name="year"/>
+            <date-part name="month" form="short" strip-periods="true"/>
+            <date-part name="day"/>
+          </date>
+          <text macro="accessed-date"/>
+        </group>
+      </if>
+      <else-if type="bill legislation" match="any">
+        <group delimiter=", ">
+          <date variable="issued" delimiter=" ">
+            <date-part name="month" form="short" strip-periods="true"/>
+            <date-part name="day"/>
+          </date>
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </group>
+      </else-if>
+      <else-if type="report">
+        <date variable="issued" delimiter=" ">
+          <date-part name="year"/>
+          <date-part name="month" form="short" strip-periods="true"/>
+        </date>
+      </else-if>
+      <else>
+        <group suffix=".">
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+          <text macro="accessed-date" prefix=" "/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="pages">
+    <choose>
+      <if type="article-journal article-magazine article-newspaper" match="any">
+        <text variable="page" prefix=":"/>
+      </if>
+      <else>
+        <text variable="page" prefix=" p. "/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="journal-location">
+    <choose>
+      <if type="article-journal article-magazine" match="any">
+        <text variable="volume"/>
+        <text variable="issue" prefix="(" suffix=")"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="report-details">
+    <choose>
+      <if type="report">
+        <text variable="number" prefix="Report No.: "/>
+      </if>
+    </choose>
+  </macro>
+  <citation collapse="citation-number">
+    <sort>
+      <key variable="citation-number"/>
+    </sort>
+    <layout prefix="[" suffix="]" delimiter=",">
+      <text variable="citation-number"/>
+    </layout>
+  </citation>
+  <bibliography et-al-min="7" et-al-use-first="6" second-field-align="flush">
+    <layout>
+      <text variable="citation-number" suffix=". "/>
+      <group delimiter=". " suffix=". ">
+        <text macro="author"/>
+        <text macro="title"/>
+      </group>
+      <group delimiter=" " suffix=". ">
+        <text macro="editor"/>
+        <text macro="container-title"/>
+        <text macro="publisher"/>
+        <group>
+          <text macro="date"/>
+          <text macro="journal-location"/>
+          <text macro="pages"/>
+        </group>
+      </group>
+      <text macro="report-details" suffix=". "/>
+      <text macro="access"/>
+      <text prefix=" " variable="note"/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/nature.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only" default-locale="en-GB">
+  <info>
+    <title>Nature</title>
+    <id>http://www.zotero.org/styles/nature</id>
+    <link href="http://www.zotero.org/styles/nature" rel="self"/>
+    <link href="http://www.nature.com/nature/authors/gta/index.html#a5.4" rel="documentation"/>
+    <author>
+      <name>Michael Berkowitz</name>
+      <email>mberkowi@gmu.edu</email>
+    </author>
+    <category citation-format="numeric"/>
+    <category field="science"/>
+    <category field="generic-base"/>
+    <issn>0028-0836</issn>
+    <issn>1476-4687</issn>
+    <updated>2012-09-27T22:06:38+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <terms>
+      <term name="editor" form="short">
+        <single>ed.</single>
+        <multiple>eds</multiple>
+      </term>
+    </terms>
+  </locale>
+  <macro name="title">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song" match="any">
+        <text variable="title" font-style="italic"/>
+      </if>
+      <else-if type="chapter" match="any"/>
+      <else>
+        <text variable="title"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="author">
+    <names variable="author">
+      <name sort-separator=", " delimiter=", " and="symbol" initialize-with=". " delimiter-precedes-last="never" name-as-sort-order="all"/>
+      <label form="short" prefix=", "/>
+      <et-al font-style="italic"/>
+    </names>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if variable="volume"/>
+      <else-if variable="DOI">
+        <text variable="DOI" prefix="doi:"/>
+      </else-if>
+      <else-if variable="URL">
+        <text term="at"/>
+        <text variable="URL" prefix=" &lt;" suffix="&gt;"/>
+      </else-if>
+    </choose>
+  </macro>
+  <macro name="issuance">
+    <choose>
+      <if type="bill book graphic legal_case legislation motion_picture report song chapter paper-conference" match="any">
+        <group delimiter=", " prefix="(" suffix=").">
+          <text variable="publisher" form="long"/>
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </group>
+      </if>
+      <else>
+        <date prefix="(" suffix=")." variable="issued">
+          <date-part name="year"/>
+        </date>
+      </else>
+    </choose>
+  </macro>
+  <macro name="editor">
+    <choose>
+      <if type="chapter paper-conference" match="any">
+        <names variable="editor" prefix="(" suffix=")">
+          <name and="symbol" delimiter-precedes-last="never" initialize-with=". " name-as-sort-order="all"/>
+        </names>
+      </if>
+    </choose>
+  </macro>
+  <citation collapse="citation-number">
+    <sort>
+      <key variable="citation-number"/>
+    </sort>
+    <layout vertical-align="sup" delimiter=",">
+      <text variable="citation-number"/>
+    </layout>
+  </citation>
+  <bibliography et-al-min="6" et-al-use-first="1" second-field-align="flush" entry-spacing="0">
+    <layout>
+      <text variable="citation-number" suffix="."/>
+      <group delimiter=" ">
+        <text macro="author" suffix="."/>
+        <text macro="title" suffix="."/>
+        <choose>
+          <if type="chapter paper-conference" match="any">
+            <text term="in" form="long" plural="false"/>
+          </if>
+        </choose>
+        <text variable="container-title" font-style="italic" form="short"/>
+        <text macro="editor"/>
+        <group font-weight="bold">
+          <text variable="volume" suffix=","/>
+        </group>
+        <text variable="page"/>
+        <text macro="issuance"/>
+        <text macro="access"/>
+      </group>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/CiteProc/style/vancouver.csl	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,267 @@
+<?xml version="1.0" encoding="utf-8"?>
+<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="sort-only" page-range-format="minimal">
+  <info>
+    <title>Vancouver</title>
+    <id>http://www.zotero.org/styles/vancouver</id>
+    <link href="http://www.zotero.org/styles/vancouver" rel="self"/>
+    <link href="http://www.nlm.nih.gov/bsd/uniform_requirements.html" rel="documentation"/>
+    <author>
+      <name>Michael Berkowitz</name>
+      <email>mberkowi@gmu.edu</email>
+    </author>
+    <contributor>
+      <name>Sean Takats</name>
+      <email>stakats@gmu.edu</email>
+    </contributor>
+    <contributor>
+      <name>Sebastian Karcher</name>
+    </contributor>
+    <category citation-format="numeric"/>
+    <category field="medicine"/>
+    <summary>
+      Vancouver style as outlined by International Committee of Medical Journal Editors Uniform Requirements for Manuscripts Submitted to Biomedical Journals: Sample References
+    </summary>
+    <updated>2012-09-27T22:06:38+00:00</updated>
+    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
+  </info>
+  <locale xml:lang="en">
+    <date form="text" delimiter=" ">
+      <date-part name="year"/>
+      <date-part name="month" form="short" strip-periods="true"/>
+      <date-part name="day"/>
+    </date>
+    <terms>
+      <term name="retrieved">available</term>
+      <term name="section" form="short">sect.</term>
+    </terms>
+  </locale>
+  <locale xml:lang="fr">
+    <date form="text" delimiter=" ">
+      <date-part name="day"/>
+      <date-part name="month" form="short" strip-periods="true"/>
+      <date-part name="year"/>
+    </date>
+    <terms>
+      <term name="retrieved">disponible</term>
+      <term name="from">sur</term>
+    </terms>
+  </locale>
+  <locale xml:lang="de">
+    <terms>
+      <term name="retrieved">verfügbar</term>
+      <term name="from">unter</term>
+    </terms>
+  </locale>
+  <macro name="author">
+    <names variable="author">
+      <name sort-separator=" " initialize-with="" name-as-sort-order="all" delimiter=", " delimiter-precedes-last="always"/>
+      <label form="long" prefix=", "/>
+      <substitute>
+        <names variable="editor"/>
+      </substitute>
+    </names>
+  </macro>
+  <macro name="editor">
+    <group delimiter=": ">
+      <choose>
+        <if type="chapter paper-conference" match="any">
+          <text term="in" text-case="capitalize-first"/>
+        </if>
+      </choose>
+      <names variable="editor" suffix=".">
+        <name sort-separator=" " initialize-with="" name-as-sort-order="all" delimiter=", " delimiter-precedes-last="always"/>
+        <label form="long" prefix=", "/>
+      </names>
+    </group>
+  </macro>
+  <macro name="publisher">
+    <group delimiter=": " suffix=";">
+      <choose>
+        <if type="thesis">
+          <text variable="publisher-place" prefix="[" suffix="]"/>
+        </if>
+        <else>
+          <text variable="publisher-place"/>
+        </else>
+      </choose>
+      <text variable="publisher"/>
+    </group>
+  </macro>
+  <macro name="access">
+    <choose>
+      <if variable="URL">
+        <group delimiter=": ">
+          <group delimiter=" ">
+            <text term="retrieved" text-case="capitalize-first"/>
+            <text term="from"/>
+          </group>
+          <text variable="URL"/>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="accessed-date">
+    <choose>
+      <if variable="URL">
+        <group prefix="[" suffix="]" delimiter=" ">
+          <text term="cited" text-case="lowercase"/>
+          <date variable="accessed" form="text"/>
+        </group>
+      </if>
+    </choose>
+  </macro>
+  <macro name="container-title">
+    <choose>
+      <if type="article-journal article-magazine chapter paper-conference article-newspaper" match="any">
+        <group suffix="." delimiter=" ">
+          <text variable="container-title" form="short"/>
+          <choose>
+            <if variable="URL">
+              <text term="internet" prefix="[" suffix="]" text-case="capitalize-first"/>
+            </if>
+          </choose>
+        </group>
+        <text macro="edition" prefix=" "/>
+      </if>
+      <!--add event-name and event-place once they become available-->
+      <else-if type="bill legislation" match="any">
+        <group delimiter=", ">
+          <group delimiter=". ">
+            <text variable="container-title" form="short"/>
+            <group delimiter=" ">
+              <text term="section" form="short" text-case="capitalize-first"/>
+              <text variable="section"/>
+            </group>
+          </group>
+          <text variable="number"/>
+        </group>
+      </else-if>
+      <else>
+        <text variable="container-title" suffix="." form="short"/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="title">
+    <text variable="title"/>
+    <choose>
+      <if type="article-journal article-magazine chapter paper-conference article-newspaper" match="none">
+        <choose>
+          <if variable="URL">
+            <text term="internet" prefix=" [" suffix="]" text-case="capitalize-first"/>
+          </if>
+        </choose>
+        <text macro="edition" prefix=". "/>
+      </if>
+    </choose>
+    <choose>
+      <if type="thesis">
+        <text variable="genre" prefix=" [" suffix="]"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="edition">
+    <choose>
+      <if is-numeric="edition">
+        <group delimiter=" ">
+          <number variable="edition" form="ordinal"/>
+          <text term="edition" form="short"/>
+        </group>
+      </if>
+      <else>
+        <text variable="edition" suffix="."/>
+      </else>
+    </choose>
+  </macro>
+  <macro name="date">
+    <choose>
+      <if type="article-journal article-magazine article-newspaper" match="any">
+        <group suffix=";" delimiter=" ">
+          <date variable="issued" form="text"/>
+          <text macro="accessed-date"/>
+        </group>
+      </if>
+      <else-if type="bill legislation" match="any">
+        <group delimiter=", ">
+          <date variable="issued" delimiter=" ">
+            <date-part name="month" form="short" strip-periods="true"/>
+            <date-part name="day"/>
+          </date>
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+        </group>
+      </else-if>
+      <else-if type="report">
+        <date variable="issued" delimiter=" ">
+          <date-part name="year"/>
+          <date-part name="month" form="short" strip-periods="true"/>
+        </date>
+      </else-if>
+      <else>
+        <group suffix=".">
+          <date variable="issued">
+            <date-part name="year"/>
+          </date>
+          <text macro="accessed-date" prefix=" "/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="pages">
+    <choose>
+      <if type="article-journal article-magazine article-newspaper" match="any">
+        <text variable="page" prefix=":"/>
+      </if>
+      <else>
+        <group prefix=" " delimiter=" ">
+          <label variable="page" form="short" plural="never"/>
+          <text variable="page"/>
+        </group>
+      </else>
+    </choose>
+  </macro>
+  <macro name="journal-location">
+    <choose>
+      <if type="article-journal article-magazine" match="any">
+        <text variable="volume"/>
+        <text variable="issue" prefix="(" suffix=")"/>
+      </if>
+    </choose>
+  </macro>
+  <macro name="report-details">
+    <choose>
+      <if type="report">
+        <text variable="number" prefix="Report No.: "/>
+      </if>
+    </choose>
+  </macro>
+  <citation collapse="citation-number">
+    <sort>
+      <key variable="citation-number"/>
+    </sort>
+    <layout prefix="(" suffix=")" delimiter=",">
+      <text variable="citation-number"/>
+    </layout>
+  </citation>
+  <bibliography et-al-min="7" et-al-use-first="6" second-field-align="flush">
+    <layout>
+      <text variable="citation-number" suffix=". "/>
+      <group delimiter=". " suffix=". ">
+        <text macro="author"/>
+        <text macro="title"/>
+      </group>
+      <group delimiter=" " suffix=". ">
+        <text macro="editor"/>
+        <text macro="container-title"/>
+        <text macro="publisher"/>
+        <group>
+          <text macro="date"/>
+          <text macro="journal-location"/>
+          <text macro="pages"/>
+        </group>
+      </group>
+      <text macro="report-details" suffix=". "/>
+      <text macro="access"/>
+    </layout>
+  </bibliography>
+</style>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/RIS/biblio_ris.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Biblio - RIS
+description = Provides RIS file import and export to the Biblio module.
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = views/biblio_handler_field_export_link_ris.inc
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/RIS/biblio_ris.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,218 @@
+<?php
+/**
+ * @file
+ * Database table creation for biblio_ris module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function biblio_ris_install() {
+  _save_ris_maps();
+}
+
+function biblio_ris_uninstall() {
+  if (db_table_exists('biblio_type_maps')) {
+    db_delete('biblio_type_maps')
+      ->condition('format', 'ris')
+      ->execute();
+  }
+}
+
+function biblio_ris_enable() {
+  biblio_ris_set_system_weight();
+}
+
+function biblio_ris_set_system_weight() {
+  db_update('system')
+    ->fields(array('weight' => 27))
+    ->condition('name', 'biblio_ris')
+    ->execute();
+}
+
+function _save_ris_maps() {
+
+  $typemap = _get_ris_type_map();
+  $typenames = _get_ris_type_names();
+  $fieldmap = _get_ris_field_map();
+  $maps = array_merge($typemap, $typenames, $fieldmap);
+  biblio_save_map($maps);
+
+}
+function _reset_ris_map($type) {
+  $count = db_query("SELECT COUNT(*) FROM {biblio_type_maps} WHERE format='ris'")->fetchField();
+  if ($count && $type) { //update
+    $function = '_get_ris_' . $type;
+    if (!function_exists($function)) return;
+    $map = $function();
+
+    db_update('biblio_type_maps')
+      ->fields($map)
+      ->condition('format', 'ris')
+      ->execute();
+  }
+  else { // install
+    db_delete('biblio_type_maps')
+      ->condition('format', 'ris')
+      ->execute();
+    _save_ris_maps();
+  }
+}
+  function _get_ris_type_map() {
+  $map['type_map'] = serialize(
+        array(
+                'ABST' => 129,
+                'ADVS' => 114,
+                'ART'  => 112,
+                'BILL' => 117,
+                'BOOK' => 100,
+                'CASE' => 116,
+                'CHAP' => 101,
+                'COMP' => 113,
+                'CONF' => 103,
+                'CTLG' => 129,
+                'DATA' => 125,
+                'ELEC' => 129,
+                'GEN'  => 129,
+                'HEAR' => 115,
+                'ICOMM' => 107,
+                'INPR'  => 129,
+                'JFULL' => 129,
+                'JOUR'  => 102,
+                'MAP'   => 122,
+                'MGZN'  => 106,
+                'MPCT'  => 110,
+                'MUSIC' => 129,
+                'NEWS'  => 105,
+                'PAMP'  => 129,
+                'PAT'   => 119,
+                'PCOMM' => 120,
+                'RPRT'  => 109,
+                'SER'   => 100,
+                'SLIDE' => 129,
+                'SOUND' => 129,
+                'STAT'  => 125,
+                'THES'  => 108,
+                'UNBILl' => 129,
+                'UNPB'  => 124,
+                'VIDEO' => 129,
+        )
+    );
+  $map['format'] = 'ris';
+  return $map;
+}
+
+function _get_ris_type_names() {
+  $map['type_names'] =  serialize(
+        array(
+                'ABST'   => 'Abstract',
+                'ADVS'   => 'Audiovisual material',
+                'ART'    => 'Art Work',
+                'BILL'   => 'Bill/Resolution',
+                'BOOK'   => 'Book, Whole',
+                'CASE'   => 'Case',
+                'CHAP'   => 'Book chapter',
+                'COMP'   => 'Computer program',
+                'CONF'   => 'Conference proceeding',
+                'CTLG'   => 'Catalog',
+                'DATA'   => 'Data file',
+                'ELEC'   => 'Electronic Citation',
+                'GEN'    => 'Generic',
+                'HEAR'   => 'Hearing',
+                'ICOMM'  => 'Internet Communication',
+                'INPR'   => 'In Press',
+                'JFULL'  => 'Journal (full)',
+                'JOUR'   => 'Journal',
+                'MAP'    => 'Map',
+                'MGZN'   => 'Magazine article',
+                'MPCT'   => 'Motion picture',
+                'MUSIC'  => 'Music score',
+                'NEWS'   => 'Newspaper',
+                'PAMP'   => 'Pamphlet',
+                'PAT'    => 'Patent',
+                'PCOMM'  => 'Personal communication',
+                'RPRT'   => 'Report',
+                'SER'    => 'Serial (Book, Monograph)',
+                'SLIDE'  => 'Slide',
+                'SOUND'  => 'Sound recording',
+                'STAT'   => 'Statute',
+                'THES'   => 'Thesis/Dissertation',
+                'UNBILl' => 'Unenacted bill/resolution',
+                'UNPB'   => 'Unpublished work',
+                'VIDEO'  => 'Video recording',
+        )
+  );
+  $map['format'] = 'ris';
+  return $map;
+}
+function _get_ris_field_map() {
+  $map['field_map'] =  serialize(
+        array(
+                'ID'  =>  '',                     //- Reference ID (not imported to reference software)
+                'T1'  =>  'title',                     //- Primary title
+                'TI'  =>  'title',                     //- Book title
+                'BT'  =>  'title',                     //- Book title
+                'CT'  =>  'title',                     //- Title of unpublished reference
+                'A1'  =>  '',                     //- Primary author
+                'A2'  =>  '',                     //- Secondary author (each name on separate line)
+                'AU'  =>  '',                     //- Author (syntax. Last name, First name, Suffix)
+                'Y1'  =>  'biblio_year',                     //- Primary date
+                'PY'  =>  '',                     //- Publication year (YYYY/MM/DD)
+                'N1'  => 'biblio_notes',          //- Notes
+                'KW'  =>  '',                     //- Keywords (each keyword must be on separate line preceded KW -)
+                'RP'  =>  '',                     //- Reprint status (IN FILE, NOT IN FILE, ON REQUEST (MM/DD/YY))
+                'SP'  =>  '',                     //- Start page number
+                'EP'  =>  '',                     //- Ending page number
+                'JF'  => 'biblio_secondary_title',//- Periodical full name
+                'JO'  => 'biblio_short_title',    //- Periodical standard abbreviation
+                'JA'  => 'biblio_secondary_title',//- Periodical in which article was published
+                'J1'  => 'biblio_short_title',    //- Periodical name //- User abbreviation 1
+                'J2'  => 'biblio_short_title',    //- Periodical name - User abbreviation 2
+                'VL'  => 'biblio_volume',         //- Volume number
+                'IS'  => 'biblio_issue',          //- Issue number
+                'CP'  => 'biblio_issue',          //- Issue number
+                'T2'  => 'biblio_secondary_title',//- Title secondary
+                'CY'  => 'biblio_place_published',//- City of Publication
+                'PB'  => 'biblio_publisher',      //- Publisher
+                'U1'  => 'biblio_custom1',        //- User definable 1
+                'U2'  => 'biblio_custom2',        //- User definable 2
+                'U3'  => 'biblio_custom3',        //- User definable 3
+                'U4'  => 'biblio_custom4',        //- User definable 4
+                'U5'  => 'biblio_custom5',        //- User definable 5
+                'T3'  => 'biblio_tertiary_title', //- Title series
+                'AB'  => 'biblio_abst_e',         //- Abstract
+                'N2'  => 'biblio_abst_e',         //- Abstract
+                'SN'  => 'biblio_isbn',           //- ISSN/ISBN (e.g. ISSN XXXX-XXXX)
+                'AV'  =>  '',                     //- Availability
+                'M1'  =>  '',                     //- Misc. 1
+                'M3'  =>  '',                     //- Misc. 3
+                'AD'  =>  '',                     //- Address
+                'UR'  => 'biblio_url',            //- Web/URL
+                'L1'  =>  '',                     //- Link to PDF
+                'L2'  =>  '',                     //- Link to Full-text
+                'L3'  =>  '',                     //- Related records
+                'L4'  =>  '',                     //- Images
+                'ER'  =>  '',                     //- End of Reference (must be the last tag)
+                )
+  );
+
+  $map['format'] = 'ris';
+  return $map;
+}
+/**
+ * Implementation of hook_schema().
+ *
+ * Note:  Pro Drupal Development models use of t() to translate 'description'
+ * for field definitions, but Drupal core does not use them.  We follow core.
+ */
+function biblio_ris_schema() {
+  $schema = array();
+  $schema['biblio_ris'] = array(
+    'fields' => array(
+      'nid'       => array('type' => 'int', 'not null' => TRUE),
+      'biblio_ris_md5' => array('type' => 'char', 'length' => 32, 'not null' => TRUE),
+      ),
+  'primary key' => array('nid'),
+  );
+  return $schema;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/RIS/biblio_ris.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,490 @@
+<?php
+/*
+ * @file biblio_ris.module
+ *
+ */
+function biblio_ris_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'biblio_ris') . '/views',
+  );
+}
+/*
+ *   add the ris option to the option list of the biblio_import_form
+ *   the key is the module name use by module_invoke to call hook_biblio_import
+ *   module_invoke('biblio_ris', 'biblio_import',...)
+ */
+function biblio_ris_biblio_import_options() {
+  return array('biblio_ris' => t('RIS'));
+}
+function biblio_ris_biblio_mapper_options() {
+  return  array(
+    'ris' => array(
+      'title' => t('RIS'),
+      'export' => TRUE,
+      )
+    );
+}
+
+function biblio_ris_biblio_export_options() {
+  return array('ris' => t('RIS'));
+}
+function biblio_ris_form_biblio_node_form_alter(&$form, &$form_state) {
+  global $user;
+  if (!$form_state['submitted'] && !isset($form_state['values']) && !isset($form['#node']->nid)) {
+      if (!$form_state['submitted']) {
+      $form['biblio_ris_paste'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Paste RIS Record'),
+        '#weight' => -20,
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+      );
+      $form['biblio_ris_paste']['paste_data_ris'] = array(
+        '#type' => 'textarea',
+        '#title' => t('RIS'),
+        '#required' => FALSE,
+        '#default_value' => isset($form_state['values']['paste_data_ris']) ? $form_state['values']['paste_data_ris'] : '',
+        '#description' => t('Paste a RIS entry here'),
+        '#size' => 60,
+        '#weight' => -4
+      );
+      $form['biblio_ris_paste']['paste_submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Populate using RIS'),
+        '#submit' => array('biblio_ris_form_biblio_node_form_submit')
+      );
+    }
+  }
+  $biblio_ris_id = (isset($form_state['values']['biblio_ris_id'])) ? $form_state['values']['biblio_ris_id'] : '';
+  $biblio_ris_md5 = (isset($form_state['values']['biblio_ris_md5'])) ? $form_state['values']['biblio_ris_md5'] : '';
+  $form['biblio_ris_id'] = array('#type' => 'value', '#value'  => $biblio_ris_id);
+  $form['biblio_ris_md5'] = array('#type' => 'value', '#value' => $biblio_ris_md5);
+}
+
+function biblio_ris_form_biblio_node_form_submit($form, &$form_state) {
+  global $user;
+  $node_data = array();
+  $dups = array();
+
+  if (strlen($form_state['values']['paste_data_ris'])) {
+    $node_data = _biblio_ris_import_string($form_state['values']['paste_data_ris']);
+  }
+  if (!empty($node_data) && is_object($node_data)) {
+    $form_state['values'] = array_merge($form_state['values'], (array)$node_data);
+    $form_state['input']['biblio_type'] = $form_state['biblio_type'] = $node_data->biblio_type;
+  }
+  $form_state['rebuild'] = TRUE;
+  return;
+}
+
+/**
+ * Creates a link to export a node (or view) in ris format
+ *
+ * @param $base this is the base url (defaults to /biblio)
+ * @param $nid  the node id, if NULL then the current view is exported
+ * @return  a link (<a href=...>ris</a>)
+ */
+function biblio_ris_biblio_export_link($nid = NULL, $filter = array()) {
+  $show_link = variable_get('biblio_export_links', array('ris' => TRUE));
+  if (!isset($show_link['ris']) || empty($show_link['ris']) || !biblio_access('export') ) {
+    return array();
+  }
+  $base = variable_get('biblio_base', 'biblio');
+
+  if (module_exists('popups') && !empty($nid)) {
+    $link = array(
+        'attributes' => array(
+          'class' => 'popups',
+          'title' => t("Click to get the RIS output")));
+  }
+  else {
+    $link = array(
+        'attributes' => array(
+          'title' => t("Click to download the RIS formatted file")));
+  }
+
+  $link['attributes'] += array('rel' => 'nofollow');
+
+  $link['href']  = "$base/export/ris/$nid";
+  $link['title'] = t('RIS');
+
+  if (empty($nid) && !empty($filter)) { // add any filters which may be on the current page
+    $link['query'] = $filter;
+  }
+
+  return array('biblio_ris' => $link);
+}
+
+function biblio_ris_node_delete($node) {
+  if ($node->type != 'biblio') {
+    return;
+  }
+  db_delete('biblio_ris')
+    ->condition('nid', $node->nid)
+    ->execute();
+}
+
+function biblio_ris_node_insert($node) {
+  if (isset($node->biblio_ris_md5)) {
+    drupal_write_record('biblio_ris', $node);
+  }
+}
+
+function biblio_ris_node_view($node, $view_mode) {
+  if ( $node->type == 'biblio') {
+    switch ($view_mode) {
+      case 'full':
+      case 'teaser':
+        $links = biblio_ris_biblio_export_link($node->nid);
+        $node->content['links']['biblio_ris'] = array(
+          '#links' => $links,
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
+    }
+  }
+}
+
+function biblio_ris_biblio_import($file, $terms = array(), $batch = FALSE, $session_id = NULL, $save = TRUE, $string = FALSE) {
+  $nids = array();
+  $dups = array();
+  list($nids, $dups) = _biblio_ris_import($file, $terms, $batch, $session_id);
+
+  return array($nids, $dups);
+}
+
+function biblio_ris_biblio_export($nids) {
+
+  if (module_exists('popups') && $nid) {
+    $popup = TRUE;
+  }
+  else {
+    $popup = FALSE;
+    drupal_add_http_header('Content-type', 'application/x-endnote-refer');
+    drupal_add_http_header('Content-Disposition', 'attachment; filename="Drupal-Biblio.ris"');
+  }
+
+  $nodes = node_load_multiple($nids, array(), TRUE);
+  foreach ($nodes as $node) {
+    if (variable_get('biblio_hide_bibtex_braces', 0) ) {
+      $node->title = biblio_remove_brace($node->title);
+    }
+
+    if (!$popup) {
+      print _biblio_ris_export($node);
+    }
+    else{
+      $popup_data .=  _biblio_ris_export($node);
+    }
+  }
+  if ($popup && !empty($popup_data)) return '<pre>' . $popup_data . '</pre>';
+
+}
+
+function _biblio_ris_import_string($string) {
+  $tag = '';
+  $node = new stdClass();
+  $unmapped = array();
+
+  $lines = preg_split('/[\r\n]/', $string, -1, PREG_SPLIT_NO_EMPTY);
+  foreach ($lines as $line) {
+    $line_len = strlen($line);
+    if ($line_len > 3) {
+      $start = strpos($line, '  -'); // There could be some unprintables at the beginning of the line so fine the location of the %
+      if ($start !== FALSE) {
+        $tag = drupal_substr($line, $start -2, 2);
+        $data = trim(drupal_substr($line, $start +3));
+      }
+      else {
+        $data = $line;
+      }
+    }
+    if ($line_len > 3 && !empty($tag)) { // if this is not a blank line
+      if ($tag == 'ER') {
+        if (!empty($node)) {
+          $node->biblio_ris_md5 = md5(serialize($node));
+          if (empty ($node->title )) $node->title = t("Untitled");
+          if (! ($dup = biblio_ris_check_md5($node->biblio_ris_md5))) {
+            return $node;
+          }
+          else {
+            $message = t('The RIS node that you are trying to paste into the form already exists in the database, see !url', array('!url' => l('node/' . $dup, 'node/' . $dup)));
+            form_set_error('paste_data_ris', $message);
+            return;
+          }
+        }
+      }
+      else {
+        _biblio_ris_parse_line($tag, $data, $node, $unmapped);
+      }
+    }
+  } // end while
+  if (!empty($unmapped)) {
+    $ignored_tags = array_unique($unmapped);
+    $message = t("The following elements were ignored because they do not map to any biblio fields:") . ' ';
+    $message .= implode(', ', $ignored_tags);
+    if (user_access('administer biblio')) {
+      $message .= '. ' . t('Click !url if you wish to check the field mapping', array('!url' => l(t('here'), 'admin/config/content/biblio/iomap/edit/ris')));
+    }
+    drupal_set_message($message, 'warning');
+  }
+}
+
+function _biblio_ris_import($file, $terms = array(), $batch = FALSE, $session_id = NULL) {
+  ini_set('auto_detect_line_endings', TRUE);
+  if (!($fp = fopen($file->uri, "r"))) {
+    drupal_set_message(t("Could not open RIS input file for reading."), 'error');
+    return;
+  }
+
+  $tag = '';
+  $nids = array();
+  $dups = array();
+  $unmapped = array();
+  $node = new stdClass();
+
+  while (!feof($fp)) {
+    $line = fgets($fp);
+    // Remove any character other than: carriage return, line feed, tab, or ANSI/ASCII character codes 32-255
+    $line = preg_replace('/[^\r\n\t\x20-\xFF]/', '', $line);
+    $line_len = strlen($line);
+    if ($line_len > 3) {
+      $start = strpos($line, '  -'); // There could be some unprintables at the beginning of the line so fine the location of the %
+      if ($start !== FALSE) {
+        $tag = drupal_substr($line, $start -2, 2);
+        $data = trim(drupal_substr($line, $start +3));
+      }
+      else {
+        $data = $line;
+      }
+    }
+    if ($line_len > 3 && !empty($tag)) { // if this is not a blank line
+      if ($tag == 'ER') {
+        if (!empty($node)) {
+          $node->biblio_ris_md5 = md5(serialize($node));
+          if (empty ($node->title )) $node->title = t("Untitled");
+          if (! ($dup = biblio_ris_check_md5($node->biblio_ris_md5))) {
+            biblio_save_node($node, $terms, $batch, $session_id);
+            if (!empty($node->nid)) $nids[] = $node->nid;
+          }
+          else {
+            $dups[] = $dup;
+          }
+        }
+
+        $node = new stdClass();
+        $node->biblio_contributors = array();
+      }
+      else {
+        _biblio_ris_parse_line($tag, $data, $node, $unmapped);
+      }
+
+    }
+  } // end while
+
+  fclose($fp);
+
+  if (!empty($unmapped)) {
+    $ignored_tags = array_unique($unmapped);
+    $message = t('The following elements were ignored because they do not map to any biblio fields:') . ' ';
+    $message .= implode(', ', $ignored_tags);
+    if (user_access('administer biblio')) {
+      $message .= '. ' . t('Click !url if you wish to check the field mapping', array('!url' => l(t('here'), 'admin/config/content/biblio/iomap/edit/ris')));
+    }
+    drupal_set_message($message, 'warning');
+  }
+
+  return array($nids, $dups);
+}
+
+function _biblio_ris_parse_line($tag, $data, $node, &$unmapped) {
+  switch ($tag) {
+    case 'TY' :
+      $node->biblio_type = _biblio_ris_type_map($data);
+      break;
+    case 'A1' :
+    case 'AU' :
+      $node->biblio_contributors[] = array(
+                'name' => $data,
+                'auth_category' => 1,
+                'auth_type' => _biblio_get_auth_type(1, $node->biblio_type));
+      break;
+    case 'DA' :
+      if (!isset($node->biblio_year) || empty($node->biblio_year)) {
+        $node->biblio_year = ($end = strpos($data, "/")) ? substr($data, 0, $end) : $data;
+      }
+      $node->biblio_date = $data;
+      break;
+    case 'Y1' :
+    case 'PY' :
+      if (!isset($node->biblio_year) || empty($node->biblio_year)) {
+        $node->biblio_year = ($end = strpos($data, "/")) ? substr($data, 0, $end) : $data;
+      }
+      if (!isset($node->biblio_date) || empty($node->biblio_date)) {
+        $node->biblio_date = $data;
+      }
+      break;
+    case 'A2' :
+    case 'ED' :
+      $node->biblio_contributors[] = array(
+                'name' => $data,
+                'auth_category' => 2,
+                'auth_type' => _biblio_get_auth_type(2, $node->biblio_type));
+      break;
+    case 'KW' :
+      $node->biblio_keywords[] = $data;
+      break;
+    case 'SP' :
+    case 'EP' :
+      $node->biblio_pages .= ($tag == "SP") ? $data : " - " . $data;
+      break;
+    case 'A3' :
+      $node->biblio_contributors[] = array(
+                'name' => $data,
+                'auth_category' => 5,
+                'auth_type' => _biblio_get_auth_type(5, $node->biblio_type));
+      break;
+    case 'BT' :
+      if ($node->biblio_type == 100) {
+        $node->title = $data;
+      }
+      else {
+        $node->biblio_secondary_title = $data;
+      }
+      break;
+    default :
+      if ($field = _biblio_ris_field_map($tag)) {
+        $node->$field .= $data;
+      }
+      else {
+        if (!in_array($tag, $unmapped)) {
+          $unmapped[] = $tag;
+        }
+      }
+  }
+}
+
+function _biblio_ris_export($node) {
+  $reverse = TRUE;
+  $ris = "";
+  $ris .= "TY  - " . _biblio_ris_type_map($node->biblio_type, $reverse) . "\r\n";
+  if (!empty($node->title))  $ris .= "T1  - " . trim($node->title) . "\r\n";
+  switch ($node->biblio_type) {
+    case 100 :
+    case 101 :
+    case 103 :
+    case 104 :
+    case 105 :
+    case 108 :
+    case 119 :
+      if (!empty($node->biblio_secondary_title))
+      $ris .= "T2  - " . trim($node->biblio_secondary_title) . "\r\n";
+      break;
+    case 102 :
+      if (!empty($node->biblio_secondary_title))
+      $ris .= "JF  - " . trim($node->biblio_secondary_title) . "\r\n";
+      unset($node->biblio_secondary_title);
+      break; // journal
+  }
+  if (isset($node->biblio_year) && $node->biblio_year < 9998) {
+      $ris .= "Y1  - " . trim($node->biblio_year) . "\r\n";
+  }
+
+  foreach (biblio_get_contributor_category($node->biblio_contributors, 1) as $auth) {
+    $ris .= "A1  - " . trim($auth['name']) . "\r\n";
+  }
+  foreach (biblio_get_contributor_category($node->biblio_contributors, 2) as $auth) {
+    $ris .= "ED  - " . trim($auth['name']) . "\r\n";
+  }
+
+  $kw_array = array();
+  if (!empty($node->terms)) {
+    foreach ($node->terms as $term) {
+      $kw_array[] = $term->name;
+    }
+  }
+  if (!empty($node->biblio_keywords)) {
+    foreach ($node->biblio_keywords as $term) {
+      $kw_array[] = $term;
+    }
+  }
+  if (!empty($kw_array)) {
+    $kw_array = array_unique($kw_array);
+    foreach ($kw_array as $term) {
+      $ris .= "KW  - " . trim($term) . "\r\n";
+    }
+  }
+  $abst = "";
+  if (!empty($node->biblio_abst_e))  $abst .= trim($node->biblio_abst_e);
+  if ($abst) {
+    $search = array("/\r/", "/\n/");
+    $replace = " ";
+    $abst = preg_replace($search, $replace, $abst);
+    $ris .= "AB  - " . $abst . "\r\n";
+  }
+  $skip_fields = array('biblio_year',  'biblio_abst_e', 'biblio_abst_f', 'biblio_type' );
+  $fields = drupal_schema_fields_sql('biblio');
+  $fields = array_diff($fields, $skip_fields);
+  foreach ($fields as $field) {
+    if (!empty($node->$field)) {
+      $ris .= _biblio_ris_format_entry($field, $node->$field);
+    }
+  }
+  $ris .= "ER  - \r\n\r\n";
+  return $ris;
+}
+
+function _biblio_ris_format_entry($key, $value) {
+  $reverse = TRUE;
+  $tag = _biblio_ris_field_map($key, $reverse);
+  if (!empty($tag)) {
+    return "$tag  - " . trim($value) . "\r\n";
+  }
+
+}
+
+function _biblio_ris_type_map($type, $reverse = FALSE) {
+  static $map = array();
+  if (empty($map)) {
+    $map = biblio_get_map('type_map', 'ris');
+  }
+
+  if ($reverse) {
+    return ($tag = array_search($type, $map)) ? $tag : 'Generic'; //return the biblio type or 129 (Misc) if type not found
+  }
+  return (isset($map[$type]))?$map[$type]:129; //return the biblio type or 129 (Misc) if type not found
+}
+
+function _biblio_ris_field_map($field, $reverse = FALSE) {
+  static $fmap = array();
+  if (empty($fmap)) {
+    $fmap = biblio_get_map('field_map', 'ris');
+  }
+  if ($reverse) {
+    return ($tag = array_search($field, $fmap)) ? $tag : '';
+
+  }
+  return (!empty($fmap[$field])) ? $fmap[$field] : '';
+
+}
+function biblio_ris_ris_map_reset($type = NULL) {
+  module_load_include('install', 'biblio_ris', 'biblio_ris');
+ _reset_ris_map($type);
+}
+
+function biblio_ris_check_md5($md5) {
+  static $ris_md5s = array();
+  if (empty($ris_md5s)) {
+    $result = db_query("SELECT * FROM {biblio_ris} ");
+    foreach ($result as $row) {
+      $ris_md5s[$row->biblio_ris_md5] = $row->nid;
+    }
+  }
+  if (isset($ris_md5s[$md5])) {
+    return $ris_md5s[$md5];
+  }
+  else {
+    $ris_md5s[$md5] = TRUE; // gaurd against duplicates in the same import
+    return;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/CHANGELOG	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,83 @@
+CHANGELOG
+
+Released through http://bibliophile.sourceforge.net under the GPL licence.
+Do whatever you like with this -- some credit to the author(s) would be appreciated.
+
+A collection of PHP classes to manipulate bibtex files.
+
+If you make improvements, please consider contacting the administrators at bibliophile.sourceforge.net so that your improvements can be added to the release package.
+
+Mark Grimshaw 2004/2005/2006
+http://bibliophile.sourceforge.net
+
+################################################
+v2.2
+24/April/2006 - Esteban Zimanyi and Mark Grimshaw
+1/ A 4th array, $this->undefinedStrings, is now returned that holds field values that are judged to be undefined strings. i.e. they are a non-numeric value that is not defined in a @string{...} entry and not enclosed by braces or double-quotes. This array will be empty unless the following condition is met:
+($this->removeDelimit || $this->expandMacro && $this->fieldExtract)
+2/ When an undefined string is found in function removeDelimiters return the empty string. Return $this->undefinedStrings in the last position to allow compatibility with previous versions.
+3/ Fix management of preamble in function returnArrays.
+
+v2.1
+7/February/2006 - Esteban Zimanyi and Mark Grimshaw
+Minor debugging to catch more unusually formatted entries.
+
+
+v2.0
+3/February/2006 - Esteban Zimanyi and Mark Grimshaw
+Substantial work on PARSEENTRES.php (mainly by Esteban) to:
+1/  handle @strings concatenated from other @strings.
+2/  handle all different types of comments possible.
+3/  clean-up the code.
+4/  handles more unusual formatting of white space between and inside entries.
+
+v1.5.4
+17/June/2005 - Mark Grimshaw
+month fields that have multiple dates (e.g. dec # " 5--9," or nov # " 29" # "--" # dec # " 2") are correctly parsed. (list($startMonth, $startDay, $endMonth, $endDay) = $parseMonth->init($monthField);)
+
+v1.5.3
+10/June/2005 - Mark Grimshaw
+Fixed excessive expansion of @strings in bibtex imports.
+
+v1.5.2
+5/May/2005 - Mark Grimshaw and Guillaume Gardey.
+1/  Corrections to PARSEENTRIES when handling concatenations using '#'
+2/  Corrections to the example commandline code for PARSECREATORS.
+
+v1.5.1
+30th April 2005 - Mark Grimshaw
+1/  Ensure entries such as journal = {{Journal of } # JRNL23} are properly parsed and expanded with a hanging '}' removed.
+
+v1.5
+28th April 2005 - Mark Grimshaw
+1/  Fixed a bug when parsing @preamble in PARSEENTRIES.php
+2/  Made efficiency and accuracy improvements in PARSECREATORS.php
+3/  Added class PARSEMONTH to split a bibtex month field into day and month components.
+  list($month, $day) = $parseMonth->init($monthField);
+4/  Added class PARSEPAGE to split a bibtex pages field into page start and page end components.
+  list($start, $end) = $parsePage->init($pagesField);
+
+v1.4
+25th August 2004
+1/  Expand macros added by Guillaume Gardey.
+2/  Discard comments on same line as @string.
+3/  A few bug fixes.
+4/  PARSEENTRIES can parse PHP strings. (loadBibTeXString)
+5/  Supports user defined BibTeX macro. (loadStringMacro)
+
+v1.3
+20th August 2004
+1/  @string<spaces>{...} now correctly parsed.
+2/  Any final "," left on the end of the last field in an entry is now removed.
+
+v1.2
+15th August 2004
+Corrected bug in extraction of values from @string.
+v1.1
+15th August 2004
+1/  Added another flag to PARSEENTRIES to decide whether to remove enclosing "..." or {...} from string and entry fields.
+2/  Some debugging and simplification.  Both flags now have a default value of TRUE.
+
+v1.0
+14th August 2004
+Initial release: PARSEENTRIES.php, PARSECREATORS.php
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/LICENSE	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,251 @@
+The GNU General Public License (GPL)
+
+Version 2, June 1991
+
+
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+Everyone is permitted to copy and distribute verbatim copies
+
+of this license document, but changing it is not allowed.
+
+
+
+Preamble
+
+
+
+The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
+
+
+
+When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.
+
+
+
+To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.
+
+
+
+For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
+
+
+
+We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.
+
+
+
+Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.
+
+
+
+Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
+
+
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+
+
+0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
+
+
+
+Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
+
+
+
+1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
+
+
+
+You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.
+
+
+
+2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
+
+
+
+    a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+
+
+
+    b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
+
+
+
+    c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
+
+
+
+These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
+
+
+
+Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
+
+
+
+In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
+
+
+
+3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
+
+
+
+    a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+
+
+    b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
+
+
+
+    c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
+
+
+
+The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
+
+
+
+If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
+
+
+
+4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
+
+
+
+5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
+
+
+
+6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
+
+
+
+7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
+
+
+
+If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
+
+
+
+It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
+
+
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+
+
+8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
+
+
+
+9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.
+
+
+
+Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.
+
+
+
+10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.
+
+
+
+NO WARRANTY
+
+
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+
+
+END OF TERMS AND CONDITIONS
+
+
+
+How to Apply These Terms to Your New Programs
+
+
+
+If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
+
+
+
+To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
+
+
+
+    one line to give the program's name and a brief idea of what it does.
+
+    Copyright (C)
+
+
+
+    This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
+
+
+
+    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+
+
+    You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+
+
+If the program is interactive, make it output a short notice like this when it starts in an interactive mode:
+
+
+
+    Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
+
+
+
+The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program.
+
+
+
+You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:
+
+
+
+    Yoyodyne, Inc., hereby disclaims all copyright interest
+
+    in the program `Gnomovision' (which makes passes at compilers)
+
+    written by James Hacker.
+
+
+
+    signature of Ty Coon, 1 April 1989
+
+    Ty Coon, President of Vice
+
+
+
+This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/PARSECREATORS.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,319 @@
+<?php
+class Creators extends PARSECREATORS
+{
+  protected   $authors            = array();
+  private   $existing_authors   = array();
+    protected    $typeMap            = array();
+    private   $md5                = array();
+
+  function Creators($init = NULL)
+  {
+    $this->buildTypeMap();
+    if (is_array($init))
+    {
+      $this->setCreators($init);
+    }elseif (is_numeric($init))
+    {
+      $this->loadCreators($init);
+    }
+
+  }
+
+    function buildTypeMap()
+    {
+      $result = db_query("SELECT * FROM {biblio_contributor_type} ;");
+      while ($type = db_fetch_object($result))
+      {
+        $this->typeMap[$type->type] = $type->ctid;
+      }
+    }
+  function getCreatorByName($name)
+  {
+    $result = db_query('SELECT *
+                    FROM {biblio_contributor_data}
+                    WHERE lastname RLIKE "[[:<:]]%s[[:>:]]" ', $name);
+  }
+
+  function getCreatorCount()
+  {
+    return count($this->authors);
+  }
+
+  function getCreatorString()
+  {
+    foreach ($this->authors as $key => $author)
+    {
+      $author_array[$author['rank']] =  $author['firstname'] .' '. $author['initials'].' '.$author['lastname'];
+    }
+    ksort($author_array);
+
+    return implode(',  ' , $author_array);
+  }
+
+
+    private
+    function loadMD5()
+    {
+      $result = db_query('SELECT md5,cid  FROM {biblio_contributor_data} ');
+      while ($row = db_fetch_array($result))
+      {
+        $this->md5[$row['cid']] = $row['md5'];
+      }
+    }
+
+    public
+  function loadCreators($vid)
+  {
+    $query = 'SELECT bcd.lastname, bcd.firstname, bcd.initials,
+             bcd.affiliation, bct.type, bc.rank
+          FROM    {biblio_contributor} bc,
+           {biblio_contributor_data} bcd,
+           {biblio_contributor_type} bct
+          WHERE bc.vid = %d
+             AND bc.cid = bcd.cid
+             AND  bc.ctid = bct.ctid
+          ORDER BY bc.ctid ASC, bc.rank ASC;';
+
+    $result = db_query($query, array($vid));
+    while($creator = db_fetch_array($result))
+    {
+      $this->authors[] = $creator;
+    }
+
+  }
+
+  public
+  function saveCreators($nid, $vid)
+  {
+    if (!empty($this->authors))
+    {
+      $this->loadMD5();
+      db_query('DELETE FROM {biblio_contributor} WHERE nid = %d AND vid = %d', $nid, $vid);
+      foreach ($this->authors as $rank => $author)
+      {
+        if (empty($author['cid']) && !empty($this->md5)) $author['cid'] = array_search($author['md5'], $this->md5);
+      if (empty($author['cid']) )
+      {
+        drupal_write_record('biblio_contributor_data', $author);
+        $cid = db_last_insert_id('biblio_contributor_data', 'cid');
+      }else
+      {
+        $cid = $author['cid'];
+      }
+
+      $link_array = array('nid' => $nid, 'vid' => $vid,
+                        'cid' => $cid, 'rank' => $rank,
+                        'ctid' => $author['type']);
+
+      drupal_write_record('biblio_contributor', $link_array );
+
+      }
+    }
+  }
+
+
+  function getAuthorArray()
+  {
+    return $this->authors;
+  }
+
+  function getAuthor($rank)
+  {
+    return $this->authors[$rank];
+  }
+
+/**
+ * update object with an array of authors
+ *
+ * @param $authors
+ *   an array containing two keys "name" and "type"
+ *   the name is the full name of the contributor which will be parsed into
+ *   component pieces, and type contains a string indicating the author type
+ */
+  function setCreators($authors)
+  {
+    foreach ($authors as $author) {
+      if (strlen(trim($author['name'])))
+      {
+        $this->authors[] = $this->parseAuthor($author['name'], $author['type']);
+      }
+    }
+  }
+
+  function setCreator($author, $type = 'author')
+  {
+    $this->authors[] = $this->parseAuthor($author, $type);
+  }
+
+
+
+}
+
+/*
+Released through http://bibliophile.sourceforge.net under the GPL licence.
+Do whatever you like with this -- some credit to the author(s) would be appreciated.
+
+A collection of PHP classes to manipulate bibtex files.
+
+If you make improvements, please consider contacting the administrators at bibliophile.sourceforge.net so that your improvements can be added to the release package.
+
+Mark Grimshaw 2004/2005
+http://bibliophile.sourceforge.net
+
+28/04/2005 - Mark Grimshaw.
+  Efficiency improvements.
+
+11/02/2006 - Daniel Reidsma.
+  Changes to preg_matching to account for Latex characters in names such as {\"{o}}
+*/
+// For a quick command-line test (php -f PARSECREATORS.php) after installation, uncomment these lines:
+
+/***********************
+  $authors = "Mark \~N. Grimshaw and Bush III, G.W. & M. C. H{\\'a}mmer Jr. and von Frankenstein, Ferdinand Cecil, P.H. & Charles Louis Xavier Joseph de la Vallee P{\\\"{o}}ussin";
+  $creator = new PARSECREATORS();
+  $creatorArray = $creator->parse($authors);
+  print_r($creatorArray);
+***********************/
+
+class PARSECREATORS
+{
+  function PARSECREATORS()
+  {
+  }
+
+  function parse($input, $type = 'author')
+  {
+    $input = trim($input);
+      // split on ' and '
+    $authorArray = preg_split("/\s(and|&)\s/i", $input);
+    return $this->parseArray($authorArray, $type);
+  }
+
+  function parseArray($authorArray, $type = 'author')
+  {
+    foreach ($authorArray as $author)
+    {
+      $this->authors[]  = $this->parseAuthor($author, $type);
+    }
+  }
+/* Create writer arrays from bibtex input.
+'author field can be (delimiters between authors are 'and' or '&'):
+1. <first-tokens> <von-tokens> <last-tokens>
+2. <von-tokens> <last-tokens>, <first-tokens>
+3. <von-tokens> <last-tokens>, <jr-tokens>, <first-tokens>
+*/
+  function parseAuthor($value, $type = 'author')
+  {
+    $appellation = $prefix = $surname = $firstname = $initials = '';
+    $this->prefix = array();
+    $author = explode(",", preg_replace("/\s{2,}/", ' ', trim($value)));
+    $size = sizeof($author);
+// No commas therefore something like Mark Grimshaw, Mark Nicholas Grimshaw, M N Grimshaw, Mark N. Grimshaw
+    if ($size == 1)
+    {
+// Is complete surname enclosed in {...}, unless the string starts with a backslash (\) because then it is
+// probably a special latex-sign..
+// 2006.02.11 DR: in the last case, any NESTED curly braces should also be taken into account! so second
+// clause rules out things such as author="a{\"{o}}"
+//
+            if (preg_match("/(.*) {([^\\\].*)}/", $value, $matches) &&
+         !(preg_match("/(.*) {\\\.{.*}.*}/", $value, $matches2)))
+      {
+        $author = split(" ", $matches[1]);
+        $surname = $matches[2];
+      }
+      else
+      {
+        $author = split(" ", $value);
+// last of array is surname (no prefix if entered correctly)
+        $surname = array_pop($author);
+      }
+    }
+// Something like Grimshaw, Mark or Grimshaw, Mark Nicholas  or Grimshaw, M N or Grimshaw, Mark N.
+    else if ($size == 2)
+    {
+// first of array is surname (perhaps with prefix)
+      list($surname, $prefix) = $this->grabSurname(array_shift($author));
+    }
+// If $size is 3, we're looking at something like Bush, Jr. III, George W
+    else
+    {
+// middle of array is 'Jr.', 'IV' etc.
+      $appellation = join(' ', array_splice($author, 1, 1));
+// first of array is surname (perhaps with prefix)
+      list($surname, $prefix) = $this->grabSurname(array_shift($author));
+    }
+    $remainder = join(" ", $author);
+    list($firstname, $initials) = $this->grabFirstnameInitials($remainder);
+    if (!empty($this->prefix))
+      $prefix = join(' ', $this->prefix);
+    $surname = $surname . ' ' . $appellation;
+    $creator = array('firstname' => utf8_encode(trim($firstname)), 'initials' => utf8_encode(trim($initials)), 'lastname' => utf8_encode(trim($surname)), 'prefix' => trim($prefix));
+    if (isset($creator))
+    {
+      $creator['type'] = $this->typeMap[$type];
+      $creator['md5']  = $this->md5sum($creator);
+      return $creator;
+    }
+    return FALSE;
+  }
+
+    function md5sum($creator)
+    {
+      $string = $creator['firstname'].$creator['initials'].$creator['lastname'];
+    $string = str_replace(' ', '', drupal_strtolower($string));
+
+       return  md5($string);
+    }
+// grab firstname and initials which may be of form "A.B.C." or "A. B. C. " or " A B C " etc.
+  function grabFirstnameInitials($remainder)
+  {
+    $firstname = $initials = '';
+    $array = split(" ", $remainder);
+    foreach ($array as $value)
+    {
+      $firstChar = substr($value, 0, 1);
+      if ((ord($firstChar) >= 97) && (ord($firstChar) <= 122))
+        $this->prefix[] = $value;
+      else if (preg_match("/[a-zA-Z]{2,}/", trim($value)))
+        $firstnameArray[] = trim($value);
+      else
+        $initialsArray[] = str_replace(".", " ", trim($value));
+    }
+    if (isset($initialsArray))
+    {
+      foreach ($initialsArray as $initial)
+        $initials .= ' ' . trim($initial);
+    }
+    if (isset($firstnameArray))
+      $firstname = join(" ", $firstnameArray);
+    return array($firstname, $initials);
+  }
+// surname may have title such as 'den', 'von', 'de la' etc. - characterised by first character lowercased.  Any
+// uppercased part means lowercased parts following are part of the surname (e.g. Van den Bussche)
+  function grabSurname($input)
+  {
+    $surnameArray = split(" ", $input);
+    $noPrefix = $surname = FALSE;
+    foreach ($surnameArray as $value)
+    {
+      $firstChar = substr($value, 0, 1);
+      if (!$noPrefix && (ord($firstChar) >= 97) && (ord($firstChar) <= 122))
+        $prefix[] = $value;
+      else
+      {
+        $surname[] = $value;
+        $noPrefix = TRUE;
+      }
+    }
+    if ($surname)
+      $surname = join(" ", $surname);
+    if (isset($prefix))
+    {
+      $prefix = join(" ", $prefix);
+      return array($surname, $prefix);
+    }
+    return array($surname, FALSE);
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/PARSEENTRIES.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,561 @@
+<?php
+/*
+ v21
+
+ Inspired by an awk BibTeX parser written by Nelson H. F. Beebe over 20 years ago although
+ little of that remains.
+
+ Released through http://bibliophile.sourceforge.net under the GPL licence.
+ Do whatever you like with this -- some credit to the author(s) would be appreciated.
+
+ A collection of PHP classes to manipulate bibtex files.
+
+ If you make improvements, please consider contacting the administrators at bibliophile.sourceforge.net
+ so that your improvements can be added to the release package.
+
+ Mark Grimshaw 2006
+ http://bibliophile.sourceforge.net
+
+ (Amendments to file reading Daniel Pozzi for v1.1)
+
+ 11/June/2005 - v1.53 Mark Grimshaw:  Stopped expansion of @string when entry is enclosed in {...} or "..."
+ 21/08/2004 v1.4 Guillaume Gardey, Added PHP string parsing and expand macro features.
+ Fix bug with comments, strings macro.
+ expandMacro = FALSE/TRUE to expand string macros.
+ loadStringMacro($bibtex_string) to load a string. (array of lines)
+ 22/08/2004 v1.4 Mark Grimshaw - a few adjustments to Guillaume's code.
+ 28/04/2005 v1.5 Mark Grimshaw - a little debugging for @preamble
+
+ 02/05/2005 G. Gardey - Add support for @string macro defined by curly brackets:
+ @string{M12 = {December}}
+ - Don't expand macro for bibtexCitation and bibtexEntryType
+ - Better support for fields like journal = {Journal of } # JRNL23
+ 03/05/2005 G. Gardey - Fix wrong field value parsing when an entry ends by
+ someField = {value}}
+
+ v2 ****************************************** v2
+
+ 30/01/2006 v2.0 Esteban Zimanyi
+ - Add support for @string defined by other strings as in @string( AA = BB # " xx " # C }
+ - Add support for comments as defined in Bibtex, i.e., ignores everything that is outside
+ entries delimited by '@' and the closing delimiter. In particular, comments in Bibtex do not
+ necessarily have a % at the begining of the line !
+ This required a complete rewrite of many functions as well as writing new ones !
+
+ 31/01/2006 Mark Grimshaw
+ - Ensured that @comment{...} is ignored in parseEntry().
+ - Modified extractEntries() to ensure that entries where the start brace/parenthesis is on a
+ new line are properly parsed.
+
+ 10/02/2006 Mark Grimshaw
+ - A 4th array, $this->undefinedStrings, is now returned that holds field values that are judged to be undefined strings.
+ i.e. they are a non-numeric value that is not defined in a @string{...} entry and not enclosed by braces or double-quotes.
+ This array will be empty unless the following condition is met:
+ ($this->removeDelimit || $this->expandMacro && $this->fieldExtract)
+
+ 24/04/2006 Esteban Zimanyi
+ - When an undefined string is found in function removeDelimiters return the empty string
+ - Return $this->undefinedStrings in the last position to allow compatibility with previous versions
+ - Fix management of preamble in function returnArrays
+ */
+
+// For a quick command-line test (php -f PARSEENTRIES.php) after installation, uncomment these lines:
+require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.contributors.inc');
+
+/*************************
+ // Parse a file
+ $parse = NEW PARSEENTRIES();
+ $parse->expandMacro = TRUE;
+ //  $array = array("RMP" =>"Rev., Mod. Phys.");
+ //  $parse->loadStringMacro($array);
+ //  $parse->removeDelimit = FALSE;
+ //  $parse->fieldExtract = FALSE;
+ $parse->openBib("bib.bib");
+ $parse->extractEntries();
+ $parse->closeBib();
+ list($preamble, $strings, $entries, $undefinedStrings) = $parse->returnArrays();
+ print_r($preamble);
+ print "\n";
+ print_r($strings);
+ print "\n";
+ print_r($entries);
+ print "\n\n";
+ *************************/
+
+/************************
+ // Parse a bibtex PHP string
+ $bibtex_data = <<< END
+
+ @STRING{three = "THREE"}
+ @STRING{two = "TWO"}
+ @string{JRNL23 = {NatLA 23 } # " " # two # " " # three}
+
+ @article{klitzing.1,
+ author = "v. Klitzing and Dorda and Pepper",
+ title = "New method for high mark@sirfragalot.com accuracy determination of fine structure constant based on quantized hall resistance",
+ volume = "45",
+ journal = {Journal of } # JRNL23,
+ pages = "494",
+ citeulike-article-id = {12222
+ }
+ ,
+ ignoreMe = {blah}, }
+
+ @article
+ {
+ klitzing.2,
+ author = "Klaus von Klitzing",
+ title = "The Quantized Hall Effect",
+ volume = "58",
+ journal = two,
+ pages = "519",
+ }
+
+ END;
+
+ $parse = NEW PARSEENTRIES();
+ $parse->expandMacro = TRUE;
+ //  $parse->removeDelimit = FALSE;
+ //  $parse->fieldExtract = FALSE;
+ $array = array("RMP" =>"Rev., Mod. Phys.");
+ $parse->loadStringMacro($array);
+ $parse->loadBibtexString($bibtex_data);
+ $parse->extractEntries();
+ list($preamble, $strings, $entries, $undefinedStrings) = $parse->returnArrays();
+ print_r($preamble);
+ print "\n";
+ print_r($strings);
+ print "\n";
+ print_r($entries);
+ print "\n\n";
+
+ **********************/
+
+class PARSEENTRIES
+{
+  /**
+   * @return unknown_type
+   */
+  function PARSEENTRIES()
+  {
+    require_once(drupal_get_path('module', 'biblio_bibtex') . '/transtab_latex_unicode.inc.php');
+    $this->transtab_latex_unicode = get_transtab_latex_unicode();
+    $this->preamble = $this->strings = $this->undefinedStrings = $this->entries = array();
+    $this->count = 0;
+    $this->fieldExtract = TRUE;
+    $this->removeDelimit = TRUE;
+    $this->expandMacro = FALSE;
+    $this->parseFile = TRUE;
+    $this->outsideEntry = TRUE;
+    $this->translate_latex = TRUE;
+  }
+  // Open bib file
+  /**
+   * @param $file
+   * @return none
+   */
+  function openBib($file)
+  {
+    if (!is_file($file))
+    die;
+    ini_set('auto_detect_line_endings', true);
+    $this->fid = fopen ($file,'r');
+    $this->parseFile = TRUE;
+  }
+  // Load a bibtex string to parse it
+  function loadBibtexString($bibtex_string)
+  {
+    if (is_string($bibtex_string)) {
+      //$bibtex_string = $this->searchReplaceText($this->transtab_latex_unicode, $bibtex_string, FALSE);
+      $this->bibtexString = explode("\n",$bibtex_string);
+    } else {
+      $this->bibtexString = $bibtex_string;
+    }
+    $this->parseFile = FALSE;
+    $this->currentLine = 0;
+  }
+  function searchReplaceText($searchReplaceActionsArray, $sourceString, $includesSearchPatternDelimiters=FALSE)
+  {
+    $searchStrings = array_keys($searchReplaceActionsArray);
+    if (!$includesSearchPatternDelimiters) {
+      foreach ($searchStrings as $key => $value) {
+        $searchStrings[$key] = "/" . $value . "/"; // add search pattern delimiters
+      }
+    }
+
+    $replaceStrings= array_values($searchReplaceActionsArray);
+
+    // apply the search & replace actions defined in '$searchReplaceActionsArray' to the text passed in '$sourceString':
+    return preg_replace($searchStrings, $replaceStrings, $sourceString);
+  }
+
+  // Set strings macro
+  function loadStringMacro($macro_array)
+  {
+    $this->userStrings = $macro_array;
+  }
+  // Close bib file
+  function closeBib()
+  {
+    fclose($this->fid);
+  }
+  // Get a non-empty line from the bib file or from the bibtexString
+  function getLine()
+  {
+    if ($this->parseFile) {
+      if (!feof($this->fid)) {
+        do  {
+          $line = trim(fgets($this->fid));
+        }
+        while(!feof($this->fid) && !$line);
+        return $line;
+      }
+      return FALSE;
+    }
+    else {
+      do {
+        $line = array_shift($this->bibtexString);
+        $line = trim($line);
+        $this->currentLine++;
+      }
+      while($this->bibtexString && !$line);
+      return $line;
+    }
+  }  // Extract value part of @string field enclosed by double-quotes or braces.
+  // The string may be expanded with previously-defined strings
+  function extractStringValue($string)
+  {
+    // $string contains a end delimiter, remove it
+    $string = trim(substr($string,0,strlen($string)-1));
+    // remove delimiters and expand
+    $string = $this->removeDelimitersAndExpand($string);
+    return $string;
+  }
+  // Extract a field
+  function fieldSplit($seg)
+  {
+    // echo "**** ";print_r($seg);echo "<BR>";
+    // handle fields like another-field = {}
+    $array = preg_split("/,\s*([-_.:,a-zA-Z0-9]+)\s*={1}\s*/U", $seg, PREG_SPLIT_DELIM_CAPTURE);
+    // echo "**** ";print_r($array);echo "<BR>";
+    //$array = preg_split("/,\s*(\w+)\s*={1}\s*/U", $seg, PREG_SPLIT_DELIM_CAPTURE);
+    if (!array_key_exists(1, $array))
+    return array($array[0], FALSE);
+    return array($array[0], $array[1]);
+  }
+  // Extract and format fields
+  function reduceFields($oldString)
+  {
+    // 03/05/2005 G. Gardey. Do not remove all occurences, juste one
+    // * correctly parse an entry ended by: somefield = {aValue}}
+    $lg = strlen($oldString);
+    if ($oldString[$lg-1] == "}" || $oldString[$lg-1] == ")" || $oldString[$lg-1] == ",")
+    $oldString = substr($oldString,0,$lg-1);
+    // $oldString = rtrim($oldString, "}),");
+    $split = preg_split("/=/", $oldString, 2);
+    $string = $split[1];
+    while($string)
+    {
+      list($entry, $string) = $this->fieldSplit($string);
+      $values[] = $entry;
+    }
+    foreach ($values as $value)
+    {
+      $pos = strpos($oldString, $value);
+      $oldString = substr_replace($oldString, '', $pos, strlen($value));
+    }
+    $rev = strrev(trim($oldString));
+    if ($rev{0} != ',')
+    $oldString .= ',';
+    $keys = preg_split("/=,/", $oldString);
+    // 22/08/2004 - Mark Grimshaw
+    // I have absolutely no idea why this array_pop is required but it is.  Seems to always be
+    // an empty key at the end after the split which causes problems if not removed.
+    array_pop($keys);
+    foreach ($keys as $key)
+    {
+      $value = trim(array_shift($values));
+      $rev = strrev($value);
+      // remove any dangling ',' left on final field of entry
+      if ($rev{0} == ',')
+      $value = rtrim($value, ",");
+      if (!$value)
+      continue;
+      // 21/08/2004 G.Gardey -> expand macro
+      // Don't remove delimiters now needs to know if the value is a string macro
+      // $this->entries[$this->count][strtolower(trim($key))] = trim($this->removeDelimiters(trim($value)));
+      $key = strtolower(trim($key));
+      $value = trim($value);
+      $this->entries[$this->count][$key] = $value;
+    }
+    // echo "**** ";print_r($this->entries[$this->count]);echo "<BR>";
+  }
+  // Start splitting a bibtex entry into component fields.
+  // Store the entry type and citation.
+  function fullSplit($entry)
+  {
+    $matches = preg_split("/@(.*)[{(](.*),/U", $entry, 2, PREG_SPLIT_DELIM_CAPTURE);
+    $this->entries[$this->count]['bibtexEntryType'] = strtolower(trim($matches[1]));
+    // sometimes a bibtex entry will have no citation key
+    if (preg_match("/=/", $matches[2])) // this is a field
+    $matches = preg_split("/@(.*)\s*[{(](.*)/U", $entry, 2, PREG_SPLIT_DELIM_CAPTURE);
+    // print_r($matches); print "<P>";
+    $this->entries[$this->count]['bibtexCitation'] = $matches[2];
+    $this->reduceFields($matches[3]);
+  }
+
+  // Grab a complete bibtex entry
+  function parseEntry($entry)
+  {
+    set_time_limit(30); // reset the script timer to avoid timeouts
+    $entry = $this->translate_latex ? $this->searchReplaceText($this->transtab_latex_unicode, $entry, FALSE) : $entry;
+    $count = 0;
+    $lastLine = FALSE;
+    if (preg_match("/@(.*)([{(])/U", preg_quote($entry), $matches))
+    {
+      if (!array_key_exists(1, $matches))
+      return $lastLine;
+      if (preg_match("/string/i", trim($matches[1])))
+      $this->strings[] = $entry;
+      else if (preg_match("/preamble/i", trim($matches[1])))
+      $this->preamble[] = $entry;
+      else if (preg_match("/comment/i", $matches[1])); // MG (31/Jan/2006) -- ignore @comment
+      else
+      {
+        if ($this->fieldExtract)
+        $this->fullSplit($entry);
+        else
+        $this->entries[$this->count] = $entry;
+        $this->count++;
+      }
+      return $lastLine;
+    }
+  }
+
+  // Remove delimiters from a string
+  function removeDelimiters($string)
+  {
+    if ($string  && ($string{0} == "\""))
+    {
+      $string = substr($string, 1);
+      $string = substr($string, 0, -1);
+    }
+    else if ($string && ($string{0} == "{"))
+    {
+      if (strlen($string) > 0 && $string[strlen($string)-1] == "}")
+      {
+        $string = substr($string, 1);
+        $string = substr($string, 0, -1);
+      }
+    }
+    else if (!is_numeric($string) && !array_key_exists($string, $this->strings)
+    && (array_search($string, $this->undefinedStrings) === FALSE))
+    {
+      $this->undefinedStrings[] = $string; // Undefined string that is not a year etc.
+      return '';
+    }
+    return $string;
+  }
+
+  // This function works like explode('#',$val) but has to take into account whether
+  // the character # is part of a string (i.e., is enclosed into "..." or {...} )
+  // or defines a string concatenation as in @string{ "x # x" # ss # {xx{x}x} }
+  function explodeString($val)
+  {
+    $openquote = $bracelevel = $i = $j = 0;
+    while ($i < strlen($val))
+    {
+      if ($val[$i] == '"')
+      $openquote = !$openquote;
+      elseif ($val[$i] == '{')
+      $bracelevel++;
+      elseif ($val[$i] == '}')
+      $bracelevel--;
+      elseif ( $val[$i] == '#' && !$openquote && !$bracelevel )
+      {
+        $strings[] = substr($val,$j,$i-$j);
+        $j=$i+1;
+      }
+      $i++;
+    }
+    $strings[] = substr($val,$j);
+    return $strings;
+  }
+
+  // This function receives a string and a closing delimiter '}' or ')'
+  // and looks for the position of the closing delimiter taking into
+  // account the following Bibtex rules:
+  //  * Inside the braces, there can arbitrarily nested pairs of braces,
+  //    but braces must also be balanced inside quotes!
+  //  * Inside quotes, to place the " character it is not sufficient
+  //    to simply escape with \": Quotes must be placed inside braces.
+  function closingDelimiter($val,$delimitEnd)
+  {
+    //  echo "####>$delimitEnd $val<BR>";
+    $openquote = $bracelevel = $i = $j = 0;
+    while ($i < strlen($val))
+    {
+      // a '"' found at brace level 0 defines a value such as "ss{\"o}ss"
+      if ($val[$i] == '"' && !$bracelevel)
+      $openquote = !$openquote;
+      elseif ($val[$i] == '{')
+      $bracelevel++;
+      elseif ($val[$i] == '}')
+      $bracelevel--;
+      if ( $val[$i] == $delimitEnd && !$openquote && !$bracelevel )
+      return $i;
+      $i++;
+    }
+    // echo "--> $bracelevel, $openquote";
+    return 0;
+  }
+
+  // Remove enclosures around entry field values.  Additionally, expand macros if flag set.
+  function removeDelimitersAndExpand($string, $inpreamble = FALSE)
+  {
+    // only expand the macro if flag set, if strings defined and not in preamble
+    if (!$this->expandMacro || empty($this->strings) || $inpreamble)
+    $string = $this->removeDelimiters($string);
+    else
+    {
+      $stringlist = $this->explodeString($string);
+      $string = "";
+      foreach ($stringlist as $str)
+      {
+        // trim the string since usually # is enclosed by spaces
+        $str = trim($str);
+        // replace the string if macro is already defined
+        // strtolower is used since macros are case insensitive
+        if (isset($this->strings[strtolower($str)]))
+        $string .= $this->strings[strtolower($str)];
+        else
+        $string .= $this->removeDelimiters(trim($str));
+      }
+    }
+    return $string;
+  }
+
+  // This function extract entries taking into account how comments are defined in BibTeX.
+  // BibTeX splits the file in two areas: inside an entry and outside an entry, the delimitation
+  // being indicated by the presence of a @ sign. When this character is met, BibTex expects to
+  // find an entry. Before that sign, and after an entry, everything is considered a comment!
+  function extractEntries()
+  {
+    $inside = $possibleEntryStart = FALSE;
+    $entry="";
+    while($line=$this->getLine())
+    {
+      if ($possibleEntryStart)
+      $line = $possibleEntryStart . $line;
+      if (!$inside && strchr($line,"@"))
+      {
+        // throw all characters before the '@'
+        $line=strstr($line,'@');
+        if (!strchr($line, "{") && !strchr($line, "("))
+        $possibleEntryStart = $line;
+        elseif (preg_match("/@.*([{(])/U", preg_quote($line), $matches))
+        {
+          $inside = TRUE;
+          if ($matches[1] == '{')
+          $delimitEnd = '}';
+          else
+          $delimitEnd = ')';
+          $possibleEntryStart = FALSE;
+        }
+      }
+      if ($inside)
+      {
+        $entry .= " ".$line;
+        if ($j=$this->closingDelimiter($entry,$delimitEnd))
+        {
+          // all characters after the delimiter are thrown but the remaining
+          // characters must be kept since they may start the next entry !!!
+          $lastLine = substr($entry,$j+1);
+          $entry = substr($entry,0,$j+1);
+          // Strip excess whitespaces from the entry
+          $entry = preg_replace('/\s\s+/', ' ', $entry);
+          $this->parseEntry($entry);
+          $entry = strchr($lastLine,"@");
+          if ($entry)
+          $inside = TRUE;
+          else
+          $inside = FALSE;
+        }
+      }
+    }
+  }
+
+  // Return arrays of entries etc. to the calling process.
+  function returnArrays()
+  {
+ //   global $transtab_latex_unicode; // defined in 'transtab_latex_unicode.inc.php'
+    foreach ($this->preamble as $value)
+    {
+      preg_match("/.*?[{(](.*)/", $value, $matches);
+      $preamble = substr($matches[1], 0, -1);
+      $preambles['bibtexPreamble'] = trim($this->removeDelimitersAndExpand(trim($preamble), TRUE));
+    }
+    if (isset($preambles))
+    $this->preamble = $preambles;
+    if ($this->fieldExtract)
+    {
+      // Next lines must take into account strings defined by previously-defined strings
+      $strings = $this->strings;
+      // $this->strings is initialized with strings provided by user if they exists
+      // it is supposed that there are no substitutions to be made in the user strings, i.e., no #
+      $this->strings = isset($this->userStrings) ? $this->userStrings : array() ;
+      foreach ($strings as $value)
+      {
+        // changed 21/08/2004 G. Gardey
+        // 23/08/2004 Mark G. account for comments on same line as @string - count delimiters in string value
+        $value = trim($value);
+        $matches = preg_split("/@\s*string\s*([{(])/i", $value, 2, PREG_SPLIT_DELIM_CAPTURE);
+        $delimit = $matches[1];
+        $matches = preg_split("/=/", $matches[2], 2, PREG_SPLIT_DELIM_CAPTURE);
+        // macros are case insensitive
+        $this->strings[strtolower(trim($matches[0]))] = $this->extractStringValue($matches[1]);
+      }
+    }
+    // changed 21/08/2004 G. Gardey
+    // 22/08/2004 Mark Grimshaw - stopped useless looping.
+    // removeDelimit and expandMacro have NO effect if !$this->fieldExtract
+    if ($this->removeDelimit || $this->expandMacro && $this->fieldExtract)
+    {
+      for($i = 0; $i < count($this->entries); $i++)
+      {
+        foreach ($this->entries[$i] as $key => $value)
+        // 02/05/2005 G. Gardey don't expand macro for bibtexCitation
+        // and bibtexEntryType
+        if ($key != 'bibtexCitation' && $key != 'bibtexEntryType')
+        $this->entries[$i][$key] = trim($this->removeDelimitersAndExpand($this->entries[$i][$key]));
+      }
+    }
+    // EZ: Remove this to be able to use the same instance for parsing several files,
+    // e.g., parsing a entry file with its associated abbreviation file
+    //    if (empty($this->preamble))
+    //      $this->preamble = FALSE;
+    //    if (empty($this->strings))
+    //      $this->strings = FALSE;
+    //    if (empty($this->entries))
+    //      $this->entries = FALSE;
+    return array($this->preamble, $this->strings, $this->entries, $this->undefinedStrings);
+  }
+
+  function &getEntries() {
+    if ($this->removeDelimit || $this->expandMacro && $this->fieldExtract)
+    {
+      for($i = 0; $i < count($this->entries); $i++)
+      {
+        foreach ($this->entries[$i] as $key => $value)
+        // 02/05/2005 G. Gardey don't expand macro for bibtexCitation
+        // and bibtexEntryType
+        if ($key != 'bibtexCitation' && $key != 'bibtexEntryType')
+        $this->entries[$i][$key] = trim($this->removeDelimitersAndExpand($this->entries[$i][$key]));
+      }
+    }
+    return $this->entries;
+  }
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/PARSEMONTH.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,117 @@
+<?php
+/*
+Released through http://bibliophile.sourceforge.net under the GPL licence.
+Do whatever you like with this -- some credit to the author(s) would be appreciated.
+
+A collection of PHP classes to manipulate bibtex files.
+
+If you make improvements, please consider contacting the administrators at bibliophile.sourceforge.net so 
+that your improvements can be added to the release package.
+
+Mark Grimshaw 2005
+http://bibliophile.sourceforge.net
+*/
+/*****
+*  PARSEMONTH: BibTeX MONTH import class
+*
+* BibTeX month field can come in as:
+* jan
+* "8~" # jan
+* jan#"~8"
+* etc.
+* where # is concatenation and '~' can be any non-numeric character.
+*****/
+
+// 17/June/2005 - Mark Grimshaw:  month fields that have multiple dates (e.g. dec # " 5--9," or nov # " 29" # "--" # dec # " 2") are correctly parsed.
+class PARSEMONTH
+{
+// Constructor
+  function PARSEMONTH()
+  {
+  }
+  function init($monthField)
+  {
+    $startMonth = $this->startDay = $endMonth = $this->endDay = FALSE;
+    $date = split("#", $monthField);
+    foreach ($date as $field)
+    {
+      $field = ucfirst(strtolower(trim($field)));
+      if ($month = array_search($field, $this->monthToLongName()))
+      {
+        if (!$startMonth)
+          $startMonth = $month;
+        else
+          $endMonth = $month;
+        continue;
+      }
+      else if ($month = array_search($field, $this->monthToShortName()))
+      {
+        if (!$startMonth)
+          $startMonth = $month;
+        else
+          $endMonth = $month;
+        continue;
+      }
+      $this->parseDay($field);
+    }
+    if ($this->endDay && !$endMonth)
+      $endMonth = $startMonth;
+    return array($startMonth, $this->startDay, $endMonth, $this->endDay);
+  }
+// extract day of month from field
+  function parseDay($dayField)
+  {
+    preg_match("/([0-9]+).*([0-9]+)|([0-9]+)/", $dayField, $array);
+    if (array_key_exists(3, $array))
+    {
+      if (!$this->startDay)
+        $this->startDay = $array[3];
+      else if (!$this->endDay)
+        $this->endDay = $array[3];
+    }
+    else
+    {
+      if (array_key_exists(1, $array))
+        $this->startDay = $array[1];
+      if (array_key_exists(2, $array))
+        $this->endDay = $array[2];
+    }
+  }
+// Convert month to long name
+  function monthToLongName()
+  {
+    return array(
+        1  =>  'January',
+        2  =>  'February',
+        3  =>  'March',
+        4  =>  'April',
+        5  =>  'May',
+        6  =>  'June',
+        7  =>  'July',
+        8  =>  'August',
+        9  =>  'September',
+        10  =>  'October',
+        11  =>  'November',
+        12  =>  'December',
+      );
+  }
+// Convert month to short name
+  function monthToShortName()
+  {
+    return array(
+        1  =>  'Jan',
+        2  =>  'Feb',
+        3  =>  'Mar',
+        4  =>  'Apr',
+        5  =>  'May',
+        6  =>  'Jun',
+        7  =>  'Jul',
+        8  =>  'Aug',
+        9  =>  'Sep',
+        10  =>  'Oct',
+        11  =>  'Nov',
+        12  =>  'Dec',
+      );
+  }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/PARSEPAGE.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+/*
+Released through http://bibliophile.sourceforge.net under the GPL licence.
+Do whatever you like with this -- some credit to the author(s) would be appreciated.
+
+A collection of PHP classes to manipulate bibtex files.
+
+If you make improvements, please consider contacting the administrators at bibliophile.sourceforge.net 
+so that your improvements can be added to the release package.
+
+Mark Grimshaw 2005
+http://bibliophile.sourceforge.net*/
+/*****
+*  PARSEPAGE: BibTeX PAGES import class
+*****/
+class PARSEPAGE
+{
+// Constructor
+  function PARSEPAGE()
+  {
+  }
+// Create page arrays from bibtex input.
+// 'pages' field can be:
+//  "77--99"
+//  "3 - 5"
+//  "ix -- 101"
+//  "73+"
+//  73, 89,103"
+// Currently, PARSEPAGE will take 1/, 2/ and 3/ above as page_start and page_end and, in the other cases, will accept
+// the first valid number it finds from the left as page_start setting page_end to NULL
+  function init($item)
+  {
+    $item = trim($item);
+    if ($this->type1($item))
+      return $this->return;
+// else, return first number we can find
+    if (preg_match("/(\d+|[ivx]+)/i", $item, $array))
+      return array($array[1], FALSE);
+// No valid page numbers found
+    return array(FALSE, FALSE);;
+  }
+// "77--99" or '-'type?
+  function type1($item)
+  {
+    $start = $end = FALSE;
+    $array = preg_split("/--|-/", $item);
+    if (sizeof($array) > 1)
+    {
+      if (is_numeric(trim($array[0])))
+        $start = trim($array[0]);
+      else
+        $start = strtolower(trim($array[0]));
+      if (is_numeric(trim($array[1])))
+        $end = trim($array[1]);
+      else
+        $end = strtolower(trim($array[1]));
+      if ($end && !$start)
+        $this->return = array($end, $start);
+      else
+        $this->return = array($start, $end);
+      return TRUE;
+    }
+    return FALSE;
+  }
+}
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/README	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,96 @@
+Released through http://bibliophile.sourceforge.net under the GPL licence.
+Do whatever you like with this -- some credit to the author(s) would be appreciated.
+
+A collection of PHP classes to manipulate bibtex files.
+
+If you make improvements, please consider contacting the administrators at bibliophile.sourceforge.net so that your improvements can be added to the release package.
+
+Mark Grimshaw & Guillaume Gardey 2004 - 2006
+http://bibliophile.sourceforge.net
+
+################################################
+PARSEENTRIES
+############
+This reads the contents of a BibTeX .bib file or a PHP string and returns arrays of information representing @preamble, @string and valid BibTeX entries.
+
+Entries may be enclosed by {...} or (...).  Fields values may be enclosed by "...", {...} or without enclosure.
+
+FLAGS can be set:
+$parse->fieldExtract;
+$parse->removeDelimit;
+$parse->expandMacro = FALSE/TRUE to expand macros within BibTeX entries ('#' and @string values).
+
+If $parse->fieldExtract == TRUE (default), the $entries array using the supplied example bib.bib file will be:
+Array
+(
+    [0] => Array
+        (
+            [bibtexEntryType] => article
+            [bibtexCitation] => klitzing:qhe
+            [author] => K. v. Klitzing and G. Dorda = "and M. Pepper
+            [title] => New method for h{\i}gh mark@sirfragalot.com accuracy determination of fine structure constant based on quantized hall resistance
+            [journal] => PRL
+            [volume] => 45
+            [pages] => 494
+            [blah] => bl"ah
+            [year] => 1980
+        )
+
+    [1] => Array
+        (
+            [bibtexEntryType] => article
+            [bibtexCitation] => klitzing:nobel
+            [author] => Klaus von Klitzing
+            [title] => The Quantized Hall Effect
+            [journal] => RMP
+            [volume] => 58
+            [pages] => 519
+            [year] => 1986
+        )
+)
+
+In other words, an array of separate BibTeX entries each one an array comprising the fields, entry type and given citation. @strings will be similarly formatted.
+
+If $parse->fieldExtract == FALSE, the $entries array using the supplied example bib.bib file will be:
+Array
+(
+    [0] =>  @ARTICLE{klitzing:qhe, AUTHOR="K. v. Klitzing and G. Dorda = "and M. Pepper",   TITLE="New method for h{\i}gh mark@sirfragalot.com accuracy determination of fine structure constant based on quantized hall resistance", JOURNAL=PRL,  VOLUME=  45,  PAGES=494, blah="  bl"ah   ", YEAR=1980 },
+    [1] =>  @ARTICLE(klitzing:nobel, AUTHOR={Klaus von Klitzing}, TITLE="The Quantized Hall Effect",JOURNAL=RMP, VOLUME=58, PAGES=519, YEAR=1986 )
+)
+
+In other words, an array of separate BibTeX entries with no further processing. @strings will be similarly formatted.
+NB - IF fieldExtract == FALSE, SETTINGS FOR expandMacro AND removeDelimit WILL HAVE NO EFFECT.
+
+If $parse->removeDelimit == TRUE (default), all double-quotes or braces that enclose field values of BibTeX entries/strings will be removed.  Otherwise, they will be left in place.  Setting this to TRUE only has an effect if $parse->fieldExtract is TRUE.
+
+In all cases, @preamble (from the given example bib.bib file) will be returned as:
+Array
+(
+    [bibtexPreamble] => Blah blah blah some preamble or other r
+)
+
+Additional BibTeX macro can be supplied to the parser:
+$more_macro = array("RMP" => "Rev., Mod. Phys.", "LNCS" => "Lecture Notes in Computer Science");
+$parse->loadStringMacro($more_macro);
+
+$parse->returnArrays() will then return $entries with all BibTeX macros (BibTeX file + $more_macro) expanded.
+
+
+################################################
+PARSECREATORS
+#############
+This takes a BibTeX author or editor field and splits it into the component writers returning a multidimensional array consisting of  writer arrays comprised of array(firstname(s), initials, surname).  It attempts to recognise 'et. al' or 'et. al.' and returns either FALSE or TRUE if that exists.  If the input is 'Anon', 'anon', 'Anonymous' or 'anonymous' FALSE is returned.
+################################################
+
+
+################################################
+PARSEMONTH
+#############
+Split a bibtex month field into day and month components including date ranges.
+  list($startMonth, $startDay, $endMonth, $endDay) = $parseMonth->init($monthField);
+
+################################################
+PARSEPAGE
+#############
+Split a bibtex pages field into page start and page end components.
+  list($start, $end) = $parsePage->init($pagesField);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/bib.bib	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,44 @@
+
+
+
+@STrinG{PRL="Phys. Rev. 
+Lett."}
+
+@preAmbLE {"Blah blah blah some preamble or other
+r"}
+
+%%some comments
+
+
+     @ARTICLE{klitzing:qhe,
+                      AUTHOR="K. v. Klitzing and G. Dorda = "and M. 
+Pepper",
+
+
+  TITLE="New method for h{\i}gh mark@sirfragalot.com accuracy determination of fine structure 
+constant based on quantized hall resistance",
+JOURNAL=PRL, 
+%%some comments
+
+            VOLUME=
+
+45,
+
+PAGES=494,
+blah="  bl"ah   ",
+YEAR=1980 # Aug
+}
+
+%% @stRING(
+%%RMP="Rev., Mod. 
+%%Phys.") 
+         @ARTICLE
+(klitzing:nobel,
+AUTHOR={Klaus von Klitzing},
+TITLE="The Quantized Hall Effect",JOURNAL=RMP,
+VOLUME=58,
+PAGES=519,
+YEAR=1986
+)
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/biblio_bibtex.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Biblio - BibTex
+description = Provides BibTex import and export to the Biblio module.
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = PARSEENTRIES.php
+files[] = views/biblio_handler_field_export_link_bibtex.inc
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/biblio_bibtex.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,165 @@
+<?php
+/**
+ * @file
+ * Database table creation for biblio_bibtex module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function biblio_bibtex_install() {
+  _save_bibtex_maps();
+}
+
+function biblio_bibtex_uninstall() {
+  if (db_table_exists('biblio_type_maps')) {
+    db_delete('biblio_type_maps')
+      ->condition('format', 'bibtex')
+      ->execute();
+  }
+}
+
+function biblio_bibtex_enable() {
+  biblio_bibtex_set_system_weight();
+}
+
+function biblio_bibtex_set_system_weight() {
+  db_update('system')
+    ->fields(array('weight' => 22))
+    ->condition('name', 'biblio_bibtex')
+    ->execute();
+}
+
+
+function _get_bibtex_type_map() {
+  $map['type_map'] = serialize(
+        array(
+                'article'       => 102,
+                'book'          => 100,
+                'booklet'       => 129,
+                'conference'    => 103,
+                'inbook'        => 101,
+                'incollection'  => 101,
+                'inproceedings' => 103,
+                'manual'        => 129,
+                'mastersthesis' => 108,
+                'misc'          => 129,
+                'phdthesis'     => 108,
+                'proceedings'   => 104,
+                'techreport'    => 129,
+                'unpublished'   => 124,
+        )
+  );
+  $map['format'] = 'bibtex';
+  return $map;
+
+}
+
+function _get_bibtex_type_names() {
+  $map['type_names'] =  serialize(
+        array(
+                'article'       => 'An article from a journal',
+                'book'          => 'A book with an explicit publisher',
+                'booklet'       => 'A work that is printed and bound, but without a named publisher or sponsoring institution',
+                'conference'    => 'An article in a conference proceedings',
+                'inbook'        => 'A part of a book, usually untitled. May be a chapter (or section or whatever) and/or a range of pages',
+                'incollection'  => 'A part of a book having its own title',
+                'inproceedings' => 'An article in a conference proceedings',
+                'manual'        => 'Technical documentation',
+                'mastersthesis' => 'A Master\'s thesis',
+                'misc'          => 'For use when nothing else fits',
+                'phdthesis'     => 'A Ph.D. thesis',
+                'proceedings'   => 'The proceedings of a conference',
+                'techreport'    => 'A report published by a school or other institution, usually numbered within a series',
+                'unpublished'   => 'A document having an author and title, but not formally published',
+        )
+  );
+  $map['format'] = 'bibtex';
+  return $map;
+
+}
+function _get_bibtex_field_map() {
+
+  $map['field_map'] =  serialize(
+        array(
+                'journal'      => 'biblio_secondary_title',
+                'booktitle'    => 'biblio_secondary_title',
+                'series'       => 'biblio_secondary_title',
+                'volume'       => 'biblio_volume',
+                'number'       => 'biblio_number',
+                'year'         => 'biblio_year',
+                'note'         => 'biblio_notes',
+                'month'        => 'biblio_date',
+                'pages'        => 'biblio_pages',
+                'publisher'    => 'biblio_publisher',
+                'school'       => 'biblio_publisher',
+                'organization' => 'biblio_publisher',
+                'institution'  => 'biblio_publisher',
+                'type'         => 'biblio_type_of_work',
+                'edition'      => 'biblio_edition',
+                'chapter'      => 'biblio_section',
+                'address'      => 'biblio_place_published',
+                'abstract'     => 'biblio_abst_e',
+                'keywords'     => 'biblio_keywords',
+                'isbn'         => 'biblio_isbn',
+                'issn'         => 'biblio_issn',
+                'doi'          => 'biblio_doi',
+                'url'          => 'biblio_url',
+
+        )
+  );
+
+  $map['format'] = 'bibtex';
+  return $map;
+
+}
+
+function _save_bibtex_maps() {
+  $typemap = _get_bibtex_type_map();
+  $typenames = _get_bibtex_type_names();
+  $fieldmap = _get_bibtex_field_map();
+  $maps = array_merge($typemap, $typenames, $fieldmap);
+  biblio_save_map($maps);
+}
+
+function _reset_bibtex_map($type) {
+  $count = db_query("SELECT COUNT(*)  FROM {biblio_type_maps} WHERE format='bibtex'")->fetchField();
+  if ($count && $type) { //update
+    $function = '_get_bibtex_' . $type;
+    if (!function_exists($function)) return;
+    $map = $function();
+    db_update('biblio_type_maps')
+      ->fields($map)
+      ->condition('format', 'bibtex')
+      ->execute();
+  }
+  else { // install
+    db_delete('biblio_type_maps')
+      ->condition('format', 'bibtex')
+      ->execute();
+    _save_bibtex_maps();
+  }
+}
+
+function biblio_bibtex_schema() {
+  $schema = array();
+  $schema['biblio_bibtex'] = array(
+    'fields' => array(
+      'nid'       => array('type' => 'int', 'not null' => TRUE),
+      'biblio_bibtex_md5' => array('type' => 'char', 'length' => 32, 'not null' => TRUE),
+      'biblio_bibtex_id' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE),
+  ),
+  'primary key' => array('nid'),
+  );
+  return $schema;
+}
+
+function biblio_bibtex_update_7001() {
+  if (!db_field_exists('biblio_bibtex', 'biblio_bibtex_id')) {
+    $spec = array('type' => 'varchar', 'length' => 255, 'not null' => FALSE);
+    db_add_field('biblio_bibtex', 'biblio_bibtex_id', $spec);
+  }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/biblio_bibtex.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,455 @@
+<?php
+/*
+ * @file biblio_bibtex.module
+ *
+ */
+function biblio_bibtex_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'biblio_bibtex') . '/views',
+  );
+}
+/*
+ *   add the BibTex option to the option list of the biblio_import_form
+ *   the key is the module name use by module_invoke to call hook_biblio_import
+ *   module_invoke('biblio_bibtex', 'biblio_import',...)
+ */
+function biblio_bibtex_biblio_import_options() {
+  return array('biblio_bibtex' => t('BibTex'));
+}
+function biblio_bibtex_biblio_mapper_options() {
+  return  array(
+    'bibtex' => array(
+      'title' => t('BibTex'),
+      'export' => TRUE,
+      )
+    );
+}
+
+function biblio_bibtex_form_biblio_node_form_alter(&$form, &$form_state) {
+  global $user;
+  if (!$form_state['submitted'] && !isset($form_state['values']) && !isset($form['#node']->nid)) {
+      if (!$form_state['submitted']) {
+      $form['biblio_cut_paste'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('Paste BibTex Record'),
+        '#weight' => -20,
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+      );
+      $form['biblio_cut_paste']['paste_data_bibtex'] = array(
+        '#type' => 'textarea',
+        '#title' => t('BibTex'),
+        '#required' => FALSE,
+        '#default_value' => isset($form_state['values']['paste_data_bibtex']) ? $form_state['values']['paste_data_bibtex'] : '',
+        '#description' => t('Paste a BibTex entry here'),
+        '#size' => 60,
+        '#weight' => -4
+      );
+      $form['biblio_cut_paste']['paste_submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Populate using BibTex'),
+        '#submit' => array('biblio_bibtex_form_biblio_node_form_submit')
+      );
+    }
+  }
+  $biblio_bibtex_id = (isset($form_state['values']['biblio_bibtex_id'])) ? $form_state['values']['biblio_bibtex_id'] : '';
+  $biblio_bibtex_md5 = (isset($form_state['values']['biblio_bibtex_md5'])) ? $form_state['values']['biblio_bibtex_md5'] : '';
+  $form['biblio_bibtex_id'] = array('#type' => 'value', '#value'  => $biblio_bibtex_id);
+  $form['biblio_bibtex_md5'] = array('#type' => 'value', '#value' => $biblio_bibtex_md5);
+}
+
+function biblio_bibtex_form_biblio_node_form_submit($form, &$form_state) {
+  global $user;
+  $node_data = array();
+  $dups = array();
+
+  if (strlen($form_state['values']['paste_data_bibtex'])) {
+    list($node_data, $dups) = biblio_bibtex_biblio_import($form_state['values']['paste_data_bibtex'], array(), FALSE, NULL, FALSE, TRUE);
+  }
+  if (!empty($node_data) && is_object($node_data[0])) {
+    $form_state['values'] = array_merge($form_state['values'], (array)$node_data[0]);
+    $form_state['input']['biblio_type'] = $form_state['biblio_type'] =  $node_data[0]->biblio_type;
+
+//    $form_state['storage']['biblio_type']  = $node_data[0]->biblio_type;
+  }
+  elseif (!empty($dups)) {
+    $message = t('The bibtex node that you are trying to paste into the form already exists in the database, see !url', array('!url' => l('node/' . $dups[0], 'node/' . $dups[0])));
+    form_set_error('paste_data_bibtex', $message);
+  }
+  $form_state['rebuild'] = TRUE;
+
+  return;
+}
+
+function biblio_bibtex_biblio_export_options() {
+  return array('bibtex'  => t('BibTex'));
+}
+
+function biblio_bibtex_node_view($node, $view_mode) {
+  if ($node->type == 'biblio') {
+    switch ($view_mode) {
+      case 'full':
+      case 'teaser':
+        $links = biblio_bibtex_biblio_export_link($node->nid);
+        $node->content['links']['biblio_bibtex'] = array(
+          '#links' => $links,
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
+    }
+  }
+}
+
+/**
+ * Creates a link to export a node (or view) in BibTEX format
+ *
+ * @param $base this is the base url (defaults to /biblio)
+ * @param $nid  the node id, if NULL then the current view is exported
+ * @return  a link (<a href=...>BibTEX</a>)
+ */
+function biblio_bibtex_biblio_export_link($nid = NULL, $filter = array()) {
+  $show_link = variable_get('biblio_export_links', array('bibtex' => TRUE));
+  if (!isset($show_link['bibtex']) || !biblio_access('export')) return array();
+  $base = variable_get('biblio_base', 'biblio');
+
+  if (module_exists('popups') && !empty($nid)) {
+    $link = array(
+        'attributes' => array(
+          'class' => 'popups',
+          'title' => t("Click to get the BibTEX output")));
+  }
+  else {
+    $link = array(
+        'attributes' => array(
+          'title' => t("Click to download the BibTEX formatted file")));
+  }
+  $link['attributes'] += array('rel' => 'nofollow');
+
+  $link['href']  = "$base/export/bibtex" ;
+  if (!empty($nid)) {
+    $link['href'] .= '/' . $nid;
+  }
+  $link['title'] = t('BibTex');
+
+  if (empty($nid) && !empty($filter)) { // add any filters which may be on the current page
+    $link['query'] = $filter;
+  }
+
+  return array('biblio_bibtex' => $link);
+}
+
+function biblio_bibtex_node_delete($node) {
+  if ($node->type != 'biblio') {
+    return;
+  }
+  db_delete('biblio_bibtex')
+    ->condition('nid', $node->nid)
+    ->execute();
+}
+
+function biblio_bibtex_node_insert($node) {
+  if ($node->type != 'biblio') {
+    return;
+  }
+  if (!isset($node->biblio_bibtex_md5)) {
+    return;
+  }
+  drupal_write_record('biblio_bibtex', $node);
+}
+
+function biblio_bibtex_biblio_import($file, $terms = array(), $batch = FALSE, $session_id = NULL, $save = TRUE, $string = FALSE) {
+  $nids = array();
+  $dups = array();
+
+  module_load_include('php', 'biblio_bibtex', 'PARSEENTRIES');
+  $bibtex = new PARSEENTRIES();
+
+  if ($string) {
+    $bibtex->loadBibtexString($file);
+  }
+  else {
+    $bibtex->openBib($file->uri);
+  }
+
+  $bibtex->extractEntries();
+
+  if ($bibtex->count) {
+    $entries =& $bibtex->getEntries();
+    list($nids, $dups) = _biblio_bibtex_import($entries, $terms, $batch, $session_id, $save);
+  }
+  return array($nids, $dups);
+}
+function biblio_bibtex_biblio_export($nids) {
+  if (module_exists('popups') && $nid) {
+    $popup = TRUE;
+  }
+  else {
+    $popup = FALSE;
+    drupal_add_http_header('Content-type', 'application/text; charset=utf-8');
+    drupal_add_http_header('Content-Disposition', 'attachment; filename="Biblio-Bibtex.bib"');
+  }
+
+  $nodes = node_load_multiple($nids, array(), TRUE);
+  foreach ($nodes as $node) {
+    if (!$popup) {
+      print _biblio_bibtex_export($node);
+    }
+    else{
+      $popup_data .=  _biblio_bibtex_export($node);
+    }
+  }
+  if ($popup && !empty($popup_data)) return '<pre>' . $popup_data . '</pre>';
+}
+
+function _biblio_bibtex_import($entries, $terms = array(), $batch = FALSE, $session_id = NULL, $save = TRUE) {
+  $nids = array();
+  $dups = array();
+
+  foreach ($entries as $entry) {
+    $node = new stdClass();
+    $node->biblio_contributors = array();
+    $node->biblio_type = _biblio_bibtex_type_map($entry['bibtexEntryType'], 'import');
+    switch ($entry['bibtexEntryType']) {
+      case 'mastersthesis':
+        $node->biblio_type_of_work = 'masters';
+        break;
+      case 'phdthesis':
+        $node->biblio_type_of_work = 'phd';
+        break;
+    }
+    if (!empty($entry['author'])) {
+      // split on ' and '
+      $author_array = preg_split("/\s(and|&)\s/i", trim($entry['author']));
+      foreach ($author_array as $key => $author) {
+        // discard braces as biblio uses its own heuristic to split up human names,
+        // and the braces get in the way
+        $author = str_replace(array('{', '}'), array('', ''), $author);
+        $node->biblio_contributors[]= array('name' => $author, 'auth_category' => 1, 'auth_type' => _biblio_get_auth_type(1, $node->biblio_type));
+      }
+    }
+
+    $node->biblio_citekey = (!empty($entry['bibtexCitation'])) ? $entry['bibtexCitation'] : NULL;
+    if (!empty($entry['editor'])) {
+      $author_array = preg_split("/\s(and|&)\s/i", trim($entry['editor']));
+      foreach ($author_array as $key => $author) {
+        // discard braces as biblio uses its own heuristic to split up human names,
+        // and the braces get in the way
+        $author = str_replace(array('{', '}'), array('', ''), $author);
+        $node->biblio_contributors[]= array('name' => $author, 'auth_category' => 2, 'auth_type' => _biblio_get_auth_type(2, $node->biblio_type));
+      }
+    }
+
+    $node->biblio_secondary_title = (!empty($entry['journal'])) ? $entry['journal'] : NULL;
+    if (!empty($entry['booktitle'])) $node->biblio_secondary_title =  $entry['booktitle'];
+    if (!empty($entry['series'])) {
+      if (!empty($entry['booktitle'])) {
+        $node->biblio_tertiary_title =  $entry['series'];
+      }
+      else {
+        $node->biblio_secondary_title =  $entry['series'];
+      }
+    }
+    $node->biblio_volume          = (!empty($entry['volume'])) ? $entry['volume'] : NULL;
+    $node->biblio_number          = (!empty($entry['number'])) ? $entry['number'] : NULL;
+    $node->biblio_year            = (!empty($entry['year'])) ? $entry['year'] : NULL;
+    $node->biblio_notes           = (!empty($entry['note'])) ? $entry['note'] : NULL;
+    $node->biblio_date            = (!empty($entry['month'])) ? $entry['month'] : NULL;
+    $node->biblio_pages           = (!empty($entry['pages'])) ? $entry['pages'] : NULL;
+    $node->biblio_publisher       = (!empty($entry['publisher'])) ? $entry['publisher'] : NULL;
+    if (!empty($entry['organization'])) $node->biblio_publisher = $entry['organization'];
+    if (!empty($entry['school']))       $node->biblio_publisher       = $entry['school'];
+    if (!empty($entry['institution']))  $node->biblio_publisher       = $entry['institution'];
+    $node->title                   = (!empty($entry['title'])) ? $entry['title'] : NULL;
+    $node->biblio_type_of_work    .= (!empty($entry['type'])) ? $entry['type'] : NULL;
+    $node->biblio_edition         = (!empty($entry['edition'])) ? $entry['edition'] : NULL;
+    $node->biblio_section         = (!empty($entry['chapter'])) ? $entry['chapter'] : NULL;
+    $node->biblio_place_published = (!empty($entry['address'])) ? $entry['address'] : NULL;
+    $node->biblio_abst_e          = (!empty($entry['abstract'])) ? $entry['abstract'] : NULL;
+    if (!empty($entry['keywords'])) {
+      if (strpos($entry['keywords'], ';')) {
+        $entry['keywords'] = str_replace(';', ',', $entry['keywords']);
+      }
+      $node->biblio_keywords = explode(',', $entry['keywords']);
+    }
+    $node->biblio_isbn            = (!empty($entry['isbn'])) ? $entry['isbn'] : NULL;
+    $node->biblio_issn            = (!empty($entry['issn'])) ? $entry['issn'] : NULL;
+    $node->biblio_url             = (!empty($entry['url'])) ? $entry['url'] : NULL;
+    $node->biblio_doi             = (!empty($entry['doi'])) ? $entry['doi'] : NULL;
+    if (module_exists('biblio_pm')) {
+      $node->biblio_pubmed_id     = (!empty($entry['pmid'])) ? $entry['pmid'] : NULL;
+      $node->biblio_pubmed_md5 = '';
+    }
+
+    $node->biblio_bibtex_md5      = md5(serialize($node));
+    $node->biblio_import_type     = 'bibtex';
+
+    if (!($dup = biblio_bibtex_check_md5($node->biblio_bibtex_md5))) {
+      if ($save) {
+        biblio_save_node($node, $terms, $batch, $session_id, $save);
+        $nids[] = (!empty($node->nid))? $node->nid : NULL;
+      }
+      else { // return the whole node if we are not saveing to the DB (used for the paste function on the input form)
+        $nids[] = $node;
+      }
+    }
+    else {
+      $dups[] = $dup;
+    }
+  }
+  return array($nids, $dups);
+}
+/**
+ * Export data in bibtex format.
+ *
+ * @param $result
+ *   a database result set pointer
+ * @return
+ *   none
+ */
+function _biblio_bibtex_export($node) {
+  static $converter = NULL;
+
+  $bibtex = '';
+  $type = "article";
+  $journal = $series = $booktitle = $school = $organization = $institution = NULL;
+  $type = _biblio_bibtex_type_map($node->biblio_type);
+  switch ($node->biblio_type) {
+    case 100 :
+      $series = $node->biblio_secondary_title;
+      $organization = $node->biblio_publisher;
+      break;
+    case 101 :
+    case 103 :
+      $booktitle = $node->biblio_secondary_title;
+      $organization = $node->biblio_publisher;
+      $series = $node->biblio_tertiary_title;
+      break;
+    case 108 :
+      $school = $node->biblio_publisher;
+      $node->biblio_publisher = NULL;
+      if (stripos($node->biblio_type_of_work, 'masters')) {
+        $type = "mastersthesis";
+      }
+      break;
+    case 109 :
+      $institution  = $node->biblio_publisher;
+      $node->biblio_publisher = NULL;
+      break;
+    case 102 :
+    default:
+      $journal = $node->biblio_secondary_title;
+      break;
+  }
+
+  $bibtex .= '@' . $type . ' {';
+  $bibtex .= ($node->biblio_citekey) ? $node->biblio_citekey  : "";
+  $bibtex .= _biblio_bibtex_format_entry('title', $node->title);
+  $bibtex .= _biblio_bibtex_format_entry('journal', $journal);
+  $bibtex .= _biblio_bibtex_format_entry('booktitle', $booktitle);
+  $bibtex .= _biblio_bibtex_format_entry('series', $series);
+  $bibtex .= _biblio_bibtex_format_entry('volume', $node->biblio_volume);
+  $bibtex .= _biblio_bibtex_format_entry('number', $node->biblio_number);
+  $bibtex .= _biblio_bibtex_format_entry('year', $node->biblio_year);
+  $bibtex .= _biblio_bibtex_format_entry('note', $node->biblio_notes);
+  $bibtex .= _biblio_bibtex_format_entry('month', $node->biblio_date);
+  $bibtex .= _biblio_bibtex_format_entry('pages', $node->biblio_pages);
+  $bibtex .= _biblio_bibtex_format_entry('publisher', $node->biblio_publisher);
+  $bibtex .= _biblio_bibtex_format_entry('school', $school);
+  $bibtex .= _biblio_bibtex_format_entry('organization', $organization);
+  $bibtex .= _biblio_bibtex_format_entry('institution', $institution);
+  $bibtex .= _biblio_bibtex_format_entry('type', $node->biblio_type_of_work);
+  $bibtex .= _biblio_bibtex_format_entry('edition', $node->biblio_edition);
+  $bibtex .= _biblio_bibtex_format_entry('chapter', $node->biblio_section);
+  $bibtex .= _biblio_bibtex_format_entry('address', $node->biblio_place_published);
+  $bibtex .= _biblio_bibtex_format_entry('abstract', $node->biblio_abst_e);
+
+  $kw_array = array();
+  if (!empty($node->terms)) {
+    foreach ($node->terms as $term) {
+      $kw_array[] = $term->name;
+    }
+  }
+  if (!empty($node->biblio_keywords)) {
+    foreach ($node->biblio_keywords as $term) {
+      $kw_array[] = $term;
+    }
+  }
+  if (!empty($kw_array)) {
+    $kw_array = array_unique($kw_array);
+    $bibtex .= _biblio_bibtex_format_entry('keywords', implode(', ', $kw_array));
+  }
+
+  $bibtex .= _biblio_bibtex_format_entry('isbn', $node->biblio_isbn);
+  $bibtex .= _biblio_bibtex_format_entry('issn', $node->biblio_issn);
+  $bibtex .= _biblio_bibtex_format_entry('doi', $node->biblio_doi);
+  $bibtex .= _biblio_bibtex_format_entry('url', $node->biblio_url);
+
+  if (!empty ($node->upload) && count($node->upload['und']) && user_access('view uploaded files')) {
+      foreach ($node->upload['und'] as $file) {
+      $attachments[] = file_create_url($file['uri']);
+    }
+    $bibtex .= _biblio_bibtex_format_entry('attachments', implode(' , ', $attachments));
+  }
+
+  $a = $e = $authors = array();
+  if ($authors = biblio_get_contributor_category($node->biblio_contributors, 1)) {
+    foreach ($authors as $auth) $a[] = trim($auth['name']);
+  }
+  if ($authors = biblio_get_contributor_category($node->biblio_contributors, 2)) {
+    foreach ($authors as $auth) $e[] = trim($auth['name']);
+  }
+  $a = implode(' and ', $a);
+  $e = implode(' and ', $e);
+  if (!empty ($a)) $bibtex .= _biblio_bibtex_format_entry('author', $a);
+  if (!empty ($e)) $bibtex .= _biblio_bibtex_format_entry('editor', $e);
+  $bibtex .= "\n}\n";
+
+
+  //now convert any special characters to the latex equivelents...
+  if (!isset($converter)) {
+    module_load_include('php', 'biblio_bibtex', 'PARSEENTRIES');
+    include_once(drupal_get_path('module', 'biblio_bibtex') . '/transtab_unicode_bibtex.inc.php');
+    $converter = new PARSEENTRIES();
+  }
+  $bibtex = $converter->searchReplaceText(_biblio_bibtex_get_transtab(), $bibtex, FALSE);
+
+  return $bibtex;
+}
+
+function _biblio_bibtex_format_entry($key, $value) {
+  return !empty($value) ? ",\n\t$key = {" . $value . "}" : '';
+}
+
+function _biblio_bibtex_type_map($type, $direction = 'export') {
+  static $map = array();
+  if (empty($map)) {
+    $map = biblio_get_map('type_map', 'bibtex');
+  }
+  if ($direction == 'export') {
+    return ($type = array_search($type, $map)) ? $type : 'article';
+  }
+  else {
+    return (isset($map[$type])) ? $map[$type] : 129; //return the biblio type or 129 (Misc) if type not found
+  }
+}
+function biblio_bibtex_bibtex_map_reset($type = NULL) {
+  module_load_include('install', 'biblio_bibtex', 'biblio_bibtex');
+ _reset_bibtex_map($type);
+}
+
+function biblio_bibtex_check_md5($md5) {
+  static $bibtex_md5s = array();
+  if (empty($bibtex_md5s)) {
+    $result = db_query("SELECT * FROM {biblio_bibtex} ");
+    foreach ($result as $row ) {
+      $bibtex_md5s[$row->biblio_bibtex_md5] = $row->nid;
+    }
+  }
+  if (isset($bibtex_md5s[$md5])) {
+    return $bibtex_md5s[$md5];
+  }
+  else {
+    $bibtex_md5s[$md5] = TRUE; // gaurd against duplicates in the same import
+    return;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/transtab_latex_unicode.inc.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,256 @@
+<?php
+// Copyright:  Matthias Steffens
+//             This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.
+//             Please see the GNU General Public License for more details.
+// File:       ./includes/transtab_latex_unicode.inc.php
+// Created:    10-Aug-06, 23:55
+// Modified:   13-Aug-06, 16:16
+// This is a translation table for best-effort conversion from LaTeX to Unicode entities. It contains a comprehensive list of substitution strings for LaTeX characters,
+// which are used with the 'T1' font encoding. Uses commands from the 'textcomp' package. Unicode characters that can't be matched uniquely are commented out.
+// Adopted from 'transtab' by Markus Kuhn
+// (transtab.utf v1.8 2000-10-12 11:01:28+01 mgk25 Exp); see <http://www.cl.cam.ac.uk/~mgk25/unicode.html> for more info about Unicode and transtab.
+function get_transtab_latex_unicode() {
+return array(
+  '\\$\\\\#\\$' => "#",
+  "\\\\%" => "%",
+  "\\\\&" => "&",
+  "(?<!\\\\)~" => " ",
+  "\\{\\\\textexclamdown\\}" => "¡",
+  "\\{\\\\textcent\\}" => "¢",
+  "\\{\\\\textsterling\\}" => "£",
+  "\\{\\\\textyen\\}" => "Â¥",
+  "\\{\\\\textbrokenbar\\}" => "¦",
+  "\\{\\\\textsection\\}" => "§",
+  "\\{\\\\textasciidieresis\\}" => "¨",
+  "\\{\\\\textcopyright\\}" => "©",
+  "\\{\\\\textordfeminine\\}" => "ª",
+  "\\{\\\\guillemotleft\\}" => "«",
+  "\\{\\\\textlnot\\}" => "¬",
+  "\\{\\\\textregistered\\}" => "®",
+  "\\{\\\\textasciimacron\\}" => "¯",
+  "\\{\\\\textdegree\\}" => "°",
+  "\\{\\\\textpm\\}" => "±",
+  "\\{\\\\texttwosuperior\\}" => "²",
+  "\\{\\\\textthreesuperior\\}" => "³",
+  "\\{\\\\textasciiacute\\}" => "´",
+  "\\{\\\\textmu\\}" => "µ",
+  "\\{\\\\textparagraph\\}" => "¶",
+  "\\{\\\\textperiodcentered\\}" => "·",
+  "\\{\\\\c\\\\ \\}" => "¸",
+  "\\{\\\\textonesuperior\\}" => "¹",
+  "\\{\\\\textordmasculine\\}" => "º",
+  "\\{\\\\guillemotright\\}" => "»",
+  "\\{\\\\textonequarter\\}" => "¼",
+  "\\{\\\\textonehalf\\}" => "½",
+  "\\{\\\\textthreequarters\\}" => "¾",
+  "\\{\\\\textquestiondown\\}" => "¿",
+  "\\{?\\\\`\\{?A\\}?\\}?" => "À",
+  "\\{?\\\\'\\{?A\\}?\\}?" => "Ã",
+  "\\{?\\\\\\^\\{?A\\}?\\}?" => "Â",
+  "\\{?\\\\~\\{?A\\}?\\}?" => "Ã",
+  "\\{?\\\\\"\\{?A\\}?\\}?" => "Ä",
+  "\\\\AA\\ +" => "Ã…",
+  "\\{?\\\\r\s\\{?A\\}?\\}?" => "Ã…",
+  "\\{?\\\\AE\\}?" => "Æ",
+  "\\{?\\\\c\sC\\}?" => "Ç",
+  "\\{?\\\\`\\{?E\\}?\\}?" => "È",
+  "\\{?\\\\'\\{?E\\}?\\}?" => "É",
+  "\\{?\\\\\\^\\{?E\\}?\\}?" => "Ê",
+  "\\{?\\\\\"\\{?E\\}?\\}?" => "Ë",
+  "\\{?\\\\`\\{?I\\}?\\}?" => "Ì",
+  "\\{?\\\\'\\{?I\\}?\\}?" => "Ã",
+  "\\{?\\\\\\^\\{?I\\}?\\}?" => "ÃŽ",
+  "\\{?\\\\\"\\{?I\\}?\\}?" => "Ã",
+  "\\{?\\\\DH\\}?" => "Ã",
+  "\\{?\\\\~\\{?N\\}?\\}?" => "Ñ",
+  "\\{?\\\\`\\{?O\\}?\\}?" => "Ã’",
+  "\\{?\\\\'\\{?O\\}?\\}?" => "Ó",
+  "\\{?\\\\\\^\\{?O\\}?\\}?" => "Ô",
+  "\\{?\\\\~\\{?O\\}?\\}?" => "Õ",
+  "\\{?\\\\\"\\{?O\\}?\\}?" => "Ö",
+  "\\{?\\\\texttimes\\}?" => "×",
+  "\\\\O\\ +" => "Ø",
+  "\\{?\\\\O\\}?" => "Ø",
+  "\\{?\\\\`\\{?U\\}?\\}?" => "Ù",
+  "\\{?\\\\'\\{?U\\}?\\}?" => "Ú",
+  "\\{?\\\\\\^\\{?U\\}?\\}?" => "Û",
+  "\\{?\\\\\"\\{?U\\}?\\}?" => "Ü",
+  "\\{?\\\\'\\{?Y\\}?\\}?" => "Ã",
+  "\\{?\\\\TH\\}?" => "Þ",
+  "\\{?\\\\ss\\{?\\}?\\}?" => "ß",
+  "\\{?\\\\`\\{?a\\}?\\}?" => "à",
+  "\\{?\\\\'\\{?a\\}?\\}?" => "á",
+  "\\{?\\\\\\^\\{?a\\}?\\}?" => "â",
+  "\\{?\\\\~\\{?a\\}?\\}?" => "ã",
+  "\\{?\\\\\"\\{?a\\}?\\}?" => "ä",
+  "\\\\aa\\ +" => "Ã¥",
+  "\\{?\\\\r\s\\{?a\\}?\\}?" => "Ã¥",
+  "\\{?\\\\ae\\}?" => "æ",
+  "\\{?\\\\c\\{?c\\}?\\}?" => "ç",
+  "\\{?\\\\`\\{?e\\}?\\}?" => "è",
+  "\\{?\\\\'\\{?e\\}?\\}?" => "é",
+  "\\{?\\\\\\^\\{?e\\}?\\}?" => "ê",
+  "\\{?\\\\\"\s?\\{?e\\}?\\}?" => "ë",
+  "\\{?\\\\`\\{?i\\}?\\}?" => "ì",
+  "\\{?\\\\'\\{?i\\}?\\}?" => "í",
+  "\\{?\\\\\\^\\{?i\\}?\\}?" => "î",
+  "\\{?\\\\\"\\{?i\\}?\\}?" => "ï",
+  "\\{?\\\\dh\\}?" => "ð",
+  "\\{?\\\\~\\{?n\\}?\\}?" => "ñ",
+  "\\{?\\\\`\\{?o\\}?\\}?" => "ò",
+  "\\{?\\\\'\\{?o\\}?\\}?" => "ó",
+  "\\{?\\\\\\^\\{?o\\}?\\}?" => "ô",
+  "\\{?\\\\~\\{?o\\}?\\}?" => "õ",
+  "\\{?\\\\\"\\{?o\\}?\\}?" => "ö",
+  "\\{?\\\\textdiv\\}?" => "÷",
+  "\\\\o\\ +" => "ø",
+  "\\{?\\\\o\\}?" => "ø",
+  "\\{?\\\\`\\{?u\\}?\\}?" => "ù",
+  "\\{?\\\\'\\{?u\\}?\\}?" => "ú",
+  "\\{?\\\\\\^\\{?u\\}?\\}?" => "û",
+  "\\{?\\\\\"\\{?u\\}?\\}?" => "ü",
+  "\\{?\\\\'\\{?y\\}?\\}?" => "ý",
+  "\\{?\\\\th\\}?" => "þ",
+  "\\{?\\\\\"\\{?y\\}?\\}?" => "ÿ",
+  "\\{?\\\\u\\{?A\\}?\\}?" => "Ä‚",
+  "\\{?\\\\u\\{?a\\}?\\}?" => "ă",
+//  "\\{?\\\\k\\{?A\\}?||}?" => "Ä„",
+  "\\{?\\\\k\\{?a\\}?\\}?" => "Ä…",
+  "\\{?\\\\'\\{?C\\}?\\}?" => "Ć",
+  "\\{?\\\\'\\{?c\\}?\\}?" => "ć",
+  "\\{?\\\\v\\{?C\\}?\\}?" => "Č",
+  "\\{?\\\\v\\{?c\\}?\\}?" => "Ä",
+  "\\{?\\\\v\\{?c\\}?\\}?" => "Ä",
+  "\\{?\\\\v\\{?D\\}?\\}?" => "ÄŽ",
+  "\\{?\\\\v\\{?d\\}?\\}?" => "Ä",
+  "\\{?\\\\DJ\\}?" => "Ä",
+  "\\{?\\\\dj\\}?" => "Ä‘",
+  "\\{?\\\\k\\{?E\\}?\\}?" => "Ę",
+  "\\{?\\\\k\\{?e\\}?\\}?" => "Ä™",
+  "\\{?\\\\v\\{?E\\}?\\}?" => "Äš",
+  "\\{?\\\\v\\{?e\\}?\\}?" => "Ä›",
+  "\\{?\\\\u\s?\\{?e\\}?\\}?" => "Ä•",
+  "\\{?\\\\u\\{?G\\}?\\}?" => "Äž",
+  "\\{?\\\\u\\{?g\\}?\\}?" => "ÄŸ",
+  "\\{?\\\\.\\{?g\\}?\\}?" => "Ä¡",
+  "\\{?\\\\.\\{?I\\}?\\}?" => "İ",
+  "\\\\'\\{?\\\\i\\}?" => "í",
+  "\\{?\\\\i\\}?" => "ı",
+  "\\{?\\\\'\\{?L\\}?\\}?" => "Ĺ",
+//  "\\{?\\\\'\\{?l\\}?||}?" => "ĺ",
+  "\\{?\\\\v\\{?L\\}?\\}?" => "Ľ",
+  "\\{?\\\\v\\{?l\\}?\\}?" => "ľ",
+  "\\{?\\\\L\\}?" => "Å",
+  "\\{?\\\\l\\}?" => "Å‚",
+  "\\{?\\\\'\\{?N\\}?\\}?" => "Ń",
+  "\\{?\\\\'\\{?n\\}?\\}?" => "Å„",
+  "\\{?\\\\v\\{?N\\}?\\}?" => "Ň",
+  "\\{?\\\\v\\{?n\\}?\\}?" => "ň",
+  "\\{?\\\\NG\\}?" => "ÅŠ",
+  "\\{?\\\\ng\\}?" => "Å‹",
+  "\\{?\\\\H\\{?O\\}?\\}?" => "Å",
+  "\\{?\\\\H\\{?o\\}?\\}?" => "Å‘",
+  "\\{?\\\\OE\\}?" => "Å’",
+  "\\{?\\\\oe\\}?" => "Å“",
+  "\\{?\\\\'\\{?R\\}?\\}?" => "Å”",
+  "\\{?\\\\'\\{?r\\}?\\}?" => "Å•",
+  "\\{?\\\\v\\{?R\\}?\\}?" => "Ř",
+  "\\{?\\\\v\\{?r\\}?\\}?" => "Å™",
+  "\\{?\\\\'\\{?S\\}?\\}?" => "Åš",
+  "\\{?\\\\'\\{?s\\}?\\}?" => "Å›",
+  "\\{?\\\\c\\{?S\\}?\\}?" => "Åž",
+  "\\{?\\\\c\\{?s\\}?\\}?" => "ÅŸ",
+  "\\{?\\\\v\\{?S\\}?\\}?" => "Å ",
+  "\\{?\\\\v\\{?s\\}?\\}?" => "Å¡",
+  "\\{?\\\\c\\{?T\\}?\\}?" => "Å¢",
+  "\\{?\\\\c\\{?t\\}?\\}?" => "Å£",
+  "\\{?\\\\v\\{?T\\}?\\}?" => "Ť",
+  "\\{?\\\\v\\{?t\\}?\\}?" => "Å¥",
+  "\\{?\\\\r\\{?U\\}?\\}?" => "Å®",
+  "\\{?\\\\r\\{?u\\}?\\}?" => "ů",
+  "\\{?\\\\H\\{?U\\}?\\}?" => "Ű",
+  "\\{?\\\\H\\{?u\\}?\\}?" => "ű",
+  "\\{?\\\\\"\\{?Y\\}?\\}?" => "Ÿ",
+  "\\{?\\\\'\\{?Z\\}?\\}?" => "Ź",
+  "\\{?\\\\'\\{?z\\}?\\}?" => "ź",
+  "\\{?\\\\.\\{?Z\\}?\\}?" => "Å»",
+  "\\{?\\\\.\\{?z\\}?\\}?" => "ż",
+  "\\{?\\\\v\\{?Z\\}?\\}?" => "Ž",
+  "\\{?\\\\v\\{?z\\}?\\}?" => "ž",
+  "\\{?\\\\textflorin\\}?" => "Æ’",
+  "\\{?\\\\textasciicircum\\}?" => "ˆ",
+  "\\{?\\\\textacutedbl\\}?" => "Ë",
+  "\\{?\\\\textendash\\}?|--" => "–",
+  "\\{?\\\\textemdash\\}?|---" => "—",
+  "\\{?\\\\textbardbl\\}?" => "‖",
+  "\\{?\\\\textunderscore\\}?" => "‗",
+  "\\{?\\\\textquoteleft\\}?" => "‘",
+  "\\{?\\\\textquoteright\\}?" => "’",
+  "\\{?\\\\quotesinglbase\\}?" => "‚",
+  "\\{?\\\\textquotedblleft\\}?" => "“",
+  "\\{?\\\\textquotedblright\\}?" => "â€",
+  "\\{?\\\\quotedblbase\\}?" => "„",
+  "\\{?\\\\textdagger\\}?" => "†",
+  "\\{?\\\\textdaggerdbl\\}?" => "‡",
+  "\\{?\\\\textbullet\\}?" => "•",
+  "\\{?\\\\textellipsis\\}?" => "…",
+  "\\{?\\\\textperthousand\\}?" => "‰",
+  "\\{?\\\\guilsinglleft\\}?" => "‹",
+  "\\{?\\\\guilsinglright\\}?" => "›",
+  "\\{?\\\\textfractionsolidus\\}?" => "â„",
+  '\\$\\^\\{0\\}\\$' => "â°",
+  '\\$\\^\\{4\\}\\$' => "â´",
+  '\\$\\^\\{5\\}\\$' => "âµ",
+  '\\$\\^\\{6\\}\\$' => "â¶",
+  '\\$\\^\\{7\\}\\$' => "â·",
+  '\\$\\^\\{8\\}\\$' => "â¸",
+  '\\$\\^\\{9\\}\\$' => "â¹",
+  '\\$\\^\\{+\\}\\$' => "âº",
+  '\\$\\^\\{-\\}\\$' => "â»",
+  '\\$\\^\\{=\\}\\$' => "â¼",
+  '\\$\\^\\{n\\}\\$' => "â¿",
+  '\\$_\\{0\\}\\$' => "â‚€",
+  '\\$_\\{1\\}\\$' => "â‚",
+  '\\$_\\{2\\}\\$' => "â‚‚",
+  '\\$_\\{3\\}\\$' => "₃",
+  '\\$_\\{4\\}\\$' => "â‚„",
+  '\\$_\\{5\\}\\$' => "â‚…",
+  '\\$_\\{6\\}\\$' => "₆",
+  '\\$_\\{7\\}\\$' => "₇",
+  '\\$_\\{8\\}\\$' => "₈",
+  '\\$_\\{9\\}\\$' => "₉",
+  '\\$_\\{+\\}\\$' => "₊",
+  '\\$_\\{-\\}\\$' => "â‚‹",
+  '\\$_\\{=\\}\\$' => "₌",
+  "\\{?\\\\texteuro\\}?" => "€",
+  "\\{?\\\\textcelsius\\}?" => "℃",
+  "\\{?\\\\textnumero\\}?" => "â„–",
+  "\\{?\\\\textcircledP\\}?" => "â„—",
+  "\\{?\\\\textservicemark\\}?" => "â„ ",
+  "\\{?\\\\texttrademark\\}?" => "â„¢",
+  "\\{?\\\\textohm\\}?" => "Ω",
+  "\\{?\\\\textestimated\\}?" => "â„®",
+  "\\{?\\\\textleftarrow\\}?" => "â†",
+  "\\{?\\\\textuparrow\\}?" => "↑",
+  "\\{?\\\\textrightarrow\\}?" => "→",
+  "\\{?\\\\textdownarrow\\}?" => "↓",
+  '\\$\\\\infty\\$' => "∞",
+  "\\{?\\\\textlangle\\}?" => "〈",
+  "\\{?\\\\textrangle\\}?" => "〉",
+  "\\{?\\\\textvisiblespace\\}?" => "â£",
+  "\\{?\\\\textopenbullet\\}?" => "â—¦",
+  "\\{?\\\\Delta\\}?" => "Δ",
+  "\\{?\\\\iota\\}?" => "ι",
+  "\\{?\\\\omicron\\}?" =>"ο",
+  "\\{?\\\\mu\\}?" => "μ",
+  "\\{?\\\\eta\\}?" => "η",
+  "\\{?\\\\delta\\}?" => "δ",
+  "\\{?\\\\varsigma\\}?" => "Ï‚",
+  "\\{?\\\\Sigma\\}?" => "Σ",
+  "\\{?\\\\pi\\}?" => "Ï€",
+  "\\{?\\\\nu\\}?" => "ν",
+  "\\{?\\\\epsilon\\}?" => "ε",
+  "\\{?\\\\lambda\\}?" => "λ",
+  "\\{?\\\\=\\{?o\\}?\\}?" => "Å",
+);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/bibtexParse/transtab_unicode_bibtex.inc.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,849 @@
+<?php
+// Copyright:  Matthias Steffens
+//             This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY.
+//             Please see the GNU General Public License for more details.
+// File:       ./includes/transtab_unicode_bibtex.inc.php
+// Created:    28-May-06, 12:39
+// Modified:   13-Aug-06, 13:55
+
+// This is a translation table for best-effort conversion from Unicode to LaTeX/BibTeX entities. It contains a comprehensive list of substitution strings for Unicode characters,
+// which can be used with the 'T1' font encoding. Uses commands from the 'textcomp' package. Characters that can't be matched are converted to ASCII equivalents.
+// Adopted from 'transtab' by Markus Kuhn
+// (transtab.utf v1.8 2000-10-12 11:01:28+01 mgk25 Exp); see <http://www.cl.cam.ac.uk/~mgk25/unicode.html> for more info about Unicode and transtab.
+
+function _biblio_bibtex_get_transtab() {
+
+  return array(
+  "(?<!\\\\)#" => '$\\#$',
+  "(?<!\\\\)%" => "\\%",
+  "(?<!\\\\)&" => "\\&",
+  "(?<!\\\\)'" => "{\\textquoteright}",
+  "(?<!\\\\)`" => "{\\textquoteleft}",
+  " " => "~",
+  "¡" => "{\\textexclamdown}",
+  "¢" => "{\\textcent}",
+  "£" => "{\\textsterling}",
+  "Â¥" => "{\\textyen}",
+  "¦" => "{\\textbrokenbar}",
+  "§" => "{\\textsection}",
+  "¨" => "{\\textasciidieresis}",
+  "©" => "{\\textcopyright}",
+  "ª" => "{\\textordfeminine}",
+  "«" => "{\\guillemotleft}",
+  "¬" => "{\\textlnot}",
+  "­" => "-",
+  "®" => "{\\textregistered}",
+  "¯" => "{\\textasciimacron}",
+  "°" => "{\\textdegree}",
+  "±" => "{\\textpm}",
+  "²" => "{\\texttwosuperior}",
+  "³" => "{\\textthreesuperior}",
+  "´" => "{\\textasciiacute}",
+  "µ" => "{\\textmu}",
+  "¶" => "{\\textparagraph}",
+  "·" => "{\\textperiodcentered}",
+  "¸" => "{\\c\\ }",
+  "¹" => "{\\textonesuperior}",
+  "º" => "{\\textordmasculine}",
+  "»" => "{\\guillemotright}",
+  "¼" => "{\\textonequarter}",
+  "½" => "{\\textonehalf}",
+  "¾" => "{\\textthreequarters}",
+  "¿" => "{\\textquestiondown}",
+  "À" => "{\\`A}",
+  "Ã" => "{\\'A}",
+  "Â" => "{\\^A}",
+  "Ã" => "{\\~A}",
+  "Ä" => "{\\\"A}",
+  "Ã…" => "{\\r A}",
+  "Æ" => "{\\AE}",
+  "Ç" => "{\\c C}",
+  "È" => "{\\`E}",
+  "É" => "{\\'E}",
+  "Ê" => "{\\^E}",
+  "Ë" => "{\\\"E}",
+  "Ì" => "{\\`I}",
+  "Ã" => "{\\'I}",
+  "ÃŽ" => "{\\^I}",
+  "Ã" => "{\\\"I}",
+  "Ã" => "{\\DH}",
+  "Ñ" => "{\\~N}",
+  "Ã’" => "{\\`O}",
+  "Ó" => "{\\'O}",
+  "Ô" => "{\\^O}",
+  "Õ" => "{\\~O}",
+  "Ö" => "{\\\"O}",
+  "×" => "{\\texttimes}",
+  "Ø" => "{\\O}",
+  "Ù" => "{\\`U}",
+  "Ú" => "{\\'U}",
+  "Û" => "{\\^U}",
+  "Ü" => "{\\\"U}",
+  "Ã" => "{\\'Y}",
+  "Þ" => "{\\TH}",
+  "ß" => "{\\ss}",
+  "à" => "{\\`a}",
+  "á" => "{\\'a}",
+  "â" => "{\\^a}",
+  "ã" => "{\\~a}",
+  "ä" => "{\\\"a}",
+  "Ã¥" => "{\\r a}",
+  "æ" => "{\\ae}",
+  "ç" => "{\\c c}",
+  "è" => "{\\`e}",
+  "é" => "{\\'e}",
+  "ê" => "{\\^e}",
+  "ë" => "{\\\"e}",
+  "ì" => "{\\`\\i}",
+  "í" => "{\\'\\i}",
+  "î" => "{\\^\\i}",
+  "ï" => "{\\\"\\i}",
+  "ð" => "{\\dh}",
+  "ñ" => "{\\~n}",
+  "ò" => "{\\`o}",
+  "ó" => "{\\'o}",
+  "ô" => "{\\^o}",
+  "õ" => "{\\~o}",
+  "ö" => "{\\\"o}",
+  "÷" => "{\\textdiv}",
+  "ø" => "{\\o}",
+  "ù" => "{\\`u}",
+  "ú" => "{\\'u}",
+  "û" => "{\\^u}",
+  "ü" => "{\\\"u}",
+  "ý" => "{\\'y}",
+  "þ" => "{\\th}",
+  "ÿ" => "{\\\"y}",
+  "Ä€" => "A",
+  "Ä" => "{\\={a}}",
+  "Ä‚" => "{\\u A}",
+  "ă" => "{\\u a}",
+  "Ä„" => "{\\k A}",
+  "Ä…" => "{\\k a}",
+  "Ć" => "{\\'C}",
+  "ć" => "{\\'c}",
+  "Ĉ" => "Ch",
+  "ĉ" => "ch",
+  "ÄŠ" => "C",
+  "Ä‹" => "c",
+  "Č" => "{\\v C}",
+  "Ä" => "{\\v c}",
+  "ÄŽ" => "{\\v D}",
+  "Ä" => "{\\v d}",
+  "Ä" => "{\\DJ}",
+  "Ä‘" => "{\\dj}",
+  "Ä’" => "E",
+  "Ä“" => "e",
+  "Ä”" => "E",
+  "Ä•" => "e",
+  "Ä–" => "E",
+  "Ä—" => "e",
+  "Ę" => "{\\k E}",
+  "Ä™" => "{\\k e}",
+  "Äš" => "{\\v E}",
+  "Ä›" => "{\\v e}",
+  "Ĝ" => "Gh",
+  "Ä" => "gh",
+  "Äž" => "{\\u G}",
+  "ÄŸ" => "{\\u g}",
+  "Ä " => "G",
+  "Ä¡" => "g",
+  "Ä¢" => "G",
+  "Ä£" => "g",
+  "Ĥ" => "Hh",
+  "Ä¥" => "hh",
+  "Ħ" => "H",
+  "ħ" => "h",
+  "Ĩ" => "I",
+  "Ä©" => "i",
+  "Ī" => "I",
+  "Ä«" => "i",
+  "Ĭ" => "I",
+  "Ä­" => "i",
+  "Ä®" => "I",
+  "į" => "i",
+  "İ" => "{\\.I}",
+  "ı" => "{\\i}",
+  "IJ" => "IJ",
+  "ij" => "ij",
+  "Ä´" => "Jh",
+  "ĵ" => "jh",
+  "Ķ" => "K",
+  "Ä·" => "k",
+  "ĸ" => "k",
+  "Ĺ" => "{\\'L}",
+  "ĺ" => "{\\'l}",
+  "Ä»" => "L",
+  "ļ" => "l",
+  "Ľ" => "{\\v L}",
+  "ľ" => "{\\v l}",
+  "Ŀ" => "L·",
+  "ŀ" => "l·",
+  "Å" => "{\\L}",
+  "Å‚" => "{\\l}",
+  "Ń" => "{\\'N}",
+  "Å„" => "{\\'n}",
+  "Å…" => "N",
+  "ņ" => "n",
+  "Ň" => "{\\v N}",
+  "ň" => "{\\v n}",
+  "ʼn" => "'n",
+  "ÅŠ" => "{\\NG}",
+  "Å‹" => "{\\ng}",
+  "Ō" => "O",
+  "Å" => "o",
+  "ÅŽ" => "O",
+  "Å" => "o",
+  "Å" => "{\\H O}",
+  "Å‘" => "{\\H o}",
+  "Å’" => "{\\OE}",
+  "Å“" => "{\\oe}",
+  "Å”" => "{\\'R}",
+  "Å•" => "{\\'r}",
+  "Å–" => "R",
+  "Å—" => "r",
+  "Ř" => "{\\v R}",
+  "Å™" => "{\\v r}",
+  "Åš" => "{\\'S}",
+  "Å›" => "{\\'s}",
+  "Ŝ" => "Sh",
+  "Å" => "sh",
+  "Åž" => "{\\c S}",
+  "ÅŸ" => "{\\c s}",
+  "Å " => "{\\v S}",
+  "Å¡" => "{\\v s}",
+  "Å¢" => "{\\c T}",
+  "Å£" => "{\\c t}",
+  "Ť" => "{\\v T}",
+  "Å¥" => "{\\v t}",
+  "Ŧ" => "T",
+  "ŧ" => "t",
+  "Ũ" => "U",
+  "Å©" => "u",
+  "Ū" => "U",
+  "Å«" => "u",
+  "Ŭ" => "U",
+  "Å­" => "u",
+  "Å®" => "{\\r U}",
+  "ů" => "{\\r u}",
+  "Ű" => "{\\H U}",
+  "ű" => "{\\H u}",
+  "Ų" => "U",
+  "ų" => "u",
+  "Å´" => "W",
+  "ŵ" => "w",
+  "Ŷ" => "Y",
+  "Å·" => "y",
+  "Ÿ" => "{\\\"Y}",
+  "Ź" => "{\\'Z}",
+  "ź" => "{\\'z}",
+  "Å»" => "{\\.Z}",
+  "ż" => "{\\.z}",
+  "Ž" => "{\\v Z}",
+  "ž" => "{\\v z}",
+  "Å¿" => "s",
+  "Æ’" => "{\\textflorin}",
+  "Ș" => "S",
+  "È™" => "s",
+  "Èš" => "T",
+  "È›" => "t",
+  "ʹ" => "'",
+  "Ê»" => "'",
+  "ʼ" => "'",
+  "ʽ" => "'",
+  "ˆ" => "{\\textasciicircum}",
+  "ˈ" => "'",
+  "ˉ" => "-",
+  "ˌ" => ",",
+  "Ë" => ":",
+  "Ëš" => "o",
+  "˜" => "\\~{}",
+  "Ë" => "{\\textacutedbl}",
+  "Í´" => "'",
+  "͵" => ",",
+  ";" => ";",
+  "Ḃ" => "B",
+  "ḃ" => "b",
+  "Ḋ" => "D",
+  "ḋ" => "d",
+  "Ḟ" => "F",
+  "ḟ" => "f",
+  "á¹€" => "M",
+  "á¹" => "m",
+  "á¹–" => "P",
+  "á¹—" => "p",
+  "á¹ " => "S",
+  "ṡ" => "s",
+  "Ṫ" => "T",
+  "ṫ" => "t",
+  "Ẁ" => "W",
+  "áº" => "w",
+  "Ẃ" => "W",
+  "ẃ" => "w",
+  "Ẅ" => "W",
+  "ẅ" => "w",
+  "Ỳ" => "Y",
+  "ỳ" => "y",
+  " " => " ",
+  "â€" => "  ",
+  " " => " ",
+  " " => "  ",
+  " " => " ",
+  " " => " ",
+  " " => " ",
+  " " => " ",
+  " " => " ",
+  " " => " ",
+  "â€" => "-",
+  "‑" => "-",
+  "‒" => "-",
+  "–" => "{\\textendash}",
+  "—" => "{\\textemdash}",
+  "―" => "--",
+  "‖" => "{\\textbardbl}",
+  "‗" => "{\\textunderscore}",
+  "‘" => "{\\textquoteleft}",
+  "’" => "{\\textquoteright}",
+  "‚" => "{\\quotesinglbase}",
+  "‛" => "'",
+  "“" => "{\\textquotedblleft}",
+  "â€" => "{\\textquotedblright}",
+  "„" => "{\\quotedblbase}",
+  "‟" => "\"",
+  "†" => "{\\textdagger}",
+  "‡" => "{\\textdaggerdbl}",
+  "•" => "{\\textbullet}",
+  "‣" => ">",
+  "․" => ".",
+  "‥" => "..",
+  "…" => "{\\textellipsis}",
+  "‧" => "-",
+  " " => " ",
+  "‰" => "{\\textperthousand}",
+  "′" => "'",
+  "″" => "\"",
+  "‴" => "'''",
+  "‵" => "`",
+  "‶" => "``",
+  "‷" => "```",
+  "‹" => "{\\guilsinglleft}",
+  "›" => "{\\guilsinglright}",
+  "‼" => "!!",
+  "‾" => "-",
+  "âƒ" => "-",
+  "â„" => "{\\textfractionsolidus}",
+  "âˆ" => "?!",
+  "â‰" => "!?",
+  "âŠ" => "7",
+  "â°" => '$^{0}$',
+  "â´" => '$^{4}$',
+  "âµ" => '$^{5}$',
+  "â¶" => '$^{6}$',
+  "â·" => '$^{7}$',
+  "â¸" => '$^{8}$',
+  "â¹" => '$^{9}$',
+  "âº" => '$^{+}$',
+  "â»" => '$^{-}$',
+  "â¼" => '$^{=}$',
+  "â½" => '$^{(}$',
+  "â¾" => '$^{)}$',
+  "â¿" => '$^{n}$',
+  "â‚€" => '$_{0}$',
+  "â‚" => '$_{1}$',
+  "â‚‚" => '$_{2}$',
+  "₃" => '$_{3}$',
+  "â‚„" => '$_{4}$',
+  "â‚…" => '$_{5}$',
+  "₆" => '$_{6}$',
+  "₇" => '$_{7}$',
+  "₈" => '$_{8}$',
+  "₉" => '$_{9}$',
+  "₊" => '$_{+}$',
+  "â‚‹" => '$_{-}$',
+  "₌" => '$_{=}$',
+  "â‚" => '$_{(}$',
+  "₎" => '$_{)}$',
+  "€" => "{\\texteuro}",
+  "â„€" => "a/c",
+  "â„" => "a/s",
+  "℃" => "{\\textcelsius}",
+  "â„…" => "c/o",
+  "℆" => "c/u",
+  "℉" => "F",
+  "â„“" => "l",
+  "â„–" => "{\\textnumero}",
+  "â„—" => "{\\textcircledP}",
+  "â„ " => "{\\textservicemark}",
+  "â„¡" => "TEL",
+  "â„¢" => "{\\texttrademark}",
+  "Ω" => "{\\textohm}",
+  "K" => "K",
+  "â„«" => "A",
+  "â„®" => "{\\textestimated}",
+  "â…“" => " 1/3",
+  "â…”" => " 2/3",
+  "â…•" => " 1/5",
+  "â…–" => " 2/5",
+  "â…—" => " 3/5",
+  "â…˜" => " 4/5",
+  "â…™" => " 1/6",
+  "â…š" => " 5/6",
+  "â…›" => " 1/8",
+  "⅜" => " 3/8",
+  "â…" => " 5/8",
+  "â…ž" => " 7/8",
+  "â…Ÿ" => " 1/",
+  "â… " => "I",
+  "â…¡" => "II",
+  "â…¢" => "III",
+  "â…£" => "IV",
+  "â…¤" => "V",
+  "â…¥" => "VI",
+  "â…¦" => "VII",
+  "â…§" => "VIII",
+  "â…¨" => "IX",
+  "â…©" => "X",
+  "â…ª" => "XI",
+  "â…«" => "XII",
+  "â…¬" => "L",
+  "â…­" => "C",
+  "â…®" => "D",
+  "â…¯" => "M",
+  "â…°" => "i",
+  "â…±" => "ii",
+  "â…²" => "iii",
+  "â…³" => "iv",
+  "â…´" => "v",
+  "â…µ" => "vi",
+  "â…¶" => "vii",
+  "â…·" => "viii",
+  "â…¸" => "ix",
+  "â…¹" => "x",
+  "â…º" => "xi",
+  "â…»" => "xii",
+  "â…¼" => "l",
+  "â…½" => "c",
+  "â…¾" => "d",
+  "â…¿" => "m",
+  "â†" => "{\\textleftarrow}",
+  "↑" => "{\\textuparrow}",
+  "→" => "{\\textrightarrow}",
+  "↓" => "{\\textdownarrow}",
+  "↔" => "<->",
+  "â‡" => "<=",
+  "⇒" => "=>",
+  "⇔" => "<=>",
+  "−" => "-",
+  "∕" => "/",
+  "∖" => "\\",
+  "∗" => "*",
+  "∘" => "o",
+  "∙" => ".",
+  "∞" => '$\\infty$',
+  "∣" => "|",
+  "∥" => "||",
+  "∶" => ":",
+  "∼" => "\\~{}",
+  "≠" => "/=",
+  "≡" => "=",
+  "≤" => "<=",
+  "≥" => ">=",
+  "≪" => "<<",
+  "≫" => ">>",
+  "⊕" => "(+)",
+  "⊖" => "(-)",
+  "⊗" => "(x)",
+  "⊘" => "(/)",
+  "⊢" => "|-",
+  "⊣" => "-|",
+  "⊦" => "|-",
+  "⊧" => "|=",
+  "⊨" => "|=",
+  "⊩" => "||-",
+  "â‹…" => ".",
+  "⋆" => "*",
+  "â‹•" => '$\\#$',
+  "⋘" => "<<<",
+  "â‹™" => ">>>",
+  "⋯" => "...",
+  "〈" => "{\\textlangle}",
+  "〉" => "{\\textrangle}",
+  "â€" => "NUL",
+  "â" => "SOH",
+  "â‚" => "STX",
+  "âƒ" => "ETX",
+  "â„" => "EOT",
+  "â…" => "ENQ",
+  "â†" => "ACK",
+  "â‡" => "BEL",
+  "âˆ" => "BS",
+  "â‰" => "HT",
+  "âŠ" => "LF",
+  "â‹" => "VT",
+  "âŒ" => "FF",
+  "â" => "CR",
+  "âŽ" => "SO",
+  "â" => "SI",
+  "â" => "DLE",
+  "â‘" => "DC1",
+  "â’" => "DC2",
+  "â“" => "DC3",
+  "â”" => "DC4",
+  "â•" => "NAK",
+  "â–" => "SYN",
+  "â—" => "ETB",
+  "â˜" => "CAN",
+  "â™" => "EM",
+  "âš" => "SUB",
+  "â›" => "ESC",
+  "âœ" => "FS",
+  "â" => "GS",
+  "âž" => "RS",
+  "âŸ" => "US",
+  "â " => "SP",
+  "â¡" => "DEL",
+  "â£" => "{\\textvisiblespace}",
+  "â¤" => "NL",
+  "â¥" => "///",
+  "â¦" => "?",
+  "â‘ " => "(1)",
+  "â‘¡" => "(2)",
+  "â‘¢" => "(3)",
+  "â‘£" => "(4)",
+  "⑤" => "(5)",
+  "â‘¥" => "(6)",
+  "⑦" => "(7)",
+  "â‘§" => "(8)",
+  "⑨" => "(9)",
+  "â‘©" => "(10)",
+  "⑪" => "(11)",
+  "â‘«" => "(12)",
+  "⑬" => "(13)",
+  "â‘­" => "(14)",
+  "â‘®" => "(15)",
+  "⑯" => "(16)",
+  "â‘°" => "(17)",
+  "⑱" => "(18)",
+  "⑲" => "(19)",
+  "⑳" => "(20)",
+  "â‘´" => "(1)",
+  "⑵" => "(2)",
+  "â‘¶" => "(3)",
+  "â‘·" => "(4)",
+  "⑸" => "(5)",
+  "⑹" => "(6)",
+  "⑺" => "(7)",
+  "â‘»" => "(8)",
+  "⑼" => "(9)",
+  "⑽" => "(10)",
+  "⑾" => "(11)",
+  "â‘¿" => "(12)",
+  "â’€" => "(13)",
+  "â’" => "(14)",
+  "â’‚" => "(15)",
+  "â’ƒ" => "(16)",
+  "â’„" => "(17)",
+  "â’…" => "(18)",
+  "â’†" => "(19)",
+  "â’‡" => "(20)",
+  "â’ˆ" => "1.",
+  "â’‰" => "2.",
+  "â’Š" => "3.",
+  "â’‹" => "4.",
+  "⒌" => "5.",
+  "â’" => "6.",
+  "â’Ž" => "7.",
+  "â’" => "8.",
+  "â’" => "9.",
+  "â’‘" => "10.",
+  "â’’" => "11.",
+  "â’“" => "12.",
+  "â’”" => "13.",
+  "â’•" => "14.",
+  "â’–" => "15.",
+  "â’—" => "16.",
+  "â’˜" => "17.",
+  "â’™" => "18.",
+  "â’š" => "19.",
+  "â’›" => "20.",
+  "⒜" => "(a)",
+  "â’" => "(b)",
+  "â’ž" => "(c)",
+  "â’Ÿ" => "(d)",
+  "â’ " => "(e)",
+  "â’¡" => "(f)",
+  "â’¢" => "(g)",
+  "â’£" => "(h)",
+  "â’¤" => "(i)",
+  "â’¥" => "(j)",
+  "â’¦" => "(k)",
+  "â’§" => "(l)",
+  "â’¨" => "(m)",
+  "â’©" => "(n)",
+  "â’ª" => "(o)",
+  "â’«" => "(p)",
+  "â’¬" => "(q)",
+  "â’­" => "(r)",
+  "â’®" => "(s)",
+  "â’¯" => "(t)",
+  "â’°" => "(u)",
+  "â’±" => "(v)",
+  "â’²" => "(w)",
+  "â’³" => "(x)",
+  "â’´" => "(y)",
+  "â’µ" => "(z)",
+  "â’¶" => "(A)",
+  "â’·" => "(B)",
+  "â’¸" => "(C)",
+  "â’¹" => "(D)",
+  "â’º" => "(E)",
+  "â’»" => "(F)",
+  "â’¼" => "(G)",
+  "â’½" => "(H)",
+  "â’¾" => "(I)",
+  "â’¿" => "(J)",
+  "â“€" => "(K)",
+  "â“" => "(L)",
+  "â“‚" => "(M)",
+  "Ⓝ" => "(N)",
+  "â“„" => "(O)",
+  "â“…" => "(P)",
+  "Ⓠ" => "(Q)",
+  "Ⓡ" => "(R)",
+  "Ⓢ" => "(S)",
+  "Ⓣ" => "(T)",
+  "Ⓤ" => "(U)",
+  "â“‹" => "(V)",
+  "Ⓦ" => "(W)",
+  "â“" => "(X)",
+  "Ⓨ" => "(Y)",
+  "â“" => "(Z)",
+  "â“" => "(a)",
+  "â“‘" => "(b)",
+  "â“’" => "(c)",
+  "â““" => "(d)",
+  "â“”" => "(e)",
+  "â“•" => "(f)",
+  "â“–" => "(g)",
+  "â“—" => "(h)",
+  "ⓘ" => "(i)",
+  "â“™" => "(j)",
+  "ⓚ" => "(k)",
+  "â“›" => "(l)",
+  "ⓜ" => "(m)",
+  "â“" => "(n)",
+  "ⓞ" => "(o)",
+  "ⓟ" => "(p)",
+  "â“ " => "(q)",
+  "â“¡" => "(r)",
+  "â“¢" => "(s)",
+  "â“£" => "(t)",
+  "ⓤ" => "(u)",
+  "â“¥" => "(v)",
+  "ⓦ" => "(w)",
+  "â“§" => "(x)",
+  "ⓨ" => "(y)",
+  "â“©" => "(z)",
+  "⓪" => "(0)",
+  "─" => "-",
+  "â”" => "=",
+  "│" => "|",
+  "┃" => "|",
+  "┄" => "-",
+  "â”…" => "=",
+  "┆" => "|",
+  "┇" => "|",
+  "┈" => "-",
+  "┉" => "=",
+  "┊" => "|",
+  "┋" => "|",
+  "┌" => "+",
+  "â”" => "+",
+  "┎" => "+",
+  "â”" => "+",
+  "â”" => "+",
+  "┑" => "+",
+  "â”’" => "+",
+  "┓" => "+",
+  "â””" => "+",
+  "┕" => "+",
+  "â”–" => "+",
+  "â”—" => "+",
+  "┘" => "+",
+  "â”™" => "+",
+  "┚" => "+",
+  "â”›" => "+",
+  "├" => "+",
+  "â”" => "+",
+  "┞" => "+",
+  "┟" => "+",
+  "â” " => "+",
+  "┡" => "+",
+  "┢" => "+",
+  "┣" => "+",
+  "┤" => "+",
+  "┥" => "+",
+  "┦" => "+",
+  "â”§" => "+",
+  "┨" => "+",
+  "┩" => "+",
+  "┪" => "+",
+  "┫" => "+",
+  "┬" => "+",
+  "â”­" => "+",
+  "â”®" => "+",
+  "┯" => "+",
+  "â”°" => "+",
+  "â”±" => "+",
+  "┲" => "+",
+  "┳" => "+",
+  "â”´" => "+",
+  "┵" => "+",
+  "â”¶" => "+",
+  "â”·" => "+",
+  "┸" => "+",
+  "┹" => "+",
+  "┺" => "+",
+  "â”»" => "+",
+  "┼" => "+",
+  "┽" => "+",
+  "┾" => "+",
+  "┿" => "+",
+  "â•€" => "+",
+  "â•" => "+",
+  "â•‚" => "+",
+  "╃" => "+",
+  "â•„" => "+",
+  "â•…" => "+",
+  "╆" => "+",
+  "╇" => "+",
+  "╈" => "+",
+  "╉" => "+",
+  "╊" => "+",
+  "â•‹" => "+",
+  "╌" => "-",
+  "â•" => "=",
+  "╎" => "|",
+  "â•" => "|",
+  "â•" => "=",
+  "â•‘" => "|",
+  "â•’" => "+",
+  "â•“" => "+",
+  "â•”" => "+",
+  "â••" => "+",
+  "â•–" => "+",
+  "â•—" => "+",
+  "╘" => "+",
+  "â•™" => "+",
+  "╚" => "+",
+  "â•›" => "+",
+  "╜" => "+",
+  "â•" => "+",
+  "╞" => "+",
+  "╟" => "+",
+  "â• " => "+",
+  "â•¡" => "+",
+  "â•¢" => "+",
+  "â•£" => "+",
+  "╤" => "+",
+  "â•¥" => "+",
+  "╦" => "+",
+  "â•§" => "+",
+  "╨" => "+",
+  "â•©" => "+",
+  "╪" => "+",
+  "â•«" => "+",
+  "╬" => "+",
+  "â•­" => "+",
+  "â•®" => "+",
+  "╯" => "+",
+  "â•°" => "+",
+  "╱" => "/",
+  "╲" => "\\",
+  "╳" => "X",
+  "╼" => "-",
+  "╽" => "|",
+  "╾" => "-",
+  "â•¿" => "|",
+  "â—‹" => "o",
+  "â—¦" => "{\\textopenbullet}",
+  "★" => "*",
+  "☆" => "*",
+  "☒" => "X",
+  "☓" => "X",
+  "☹" => ":-(",
+  "☺" => ":-)",
+  "☻" => "(-:",
+  "â™­" => "b",
+  "♯" => '$\\#$',
+  "âœ" => '$\\%<$',
+  "✂" => '$\\%<$',
+  "✃" => '$\\%<$',
+  "✄" => '$\\%<$',
+  "✌" => "V",
+  "✓" => "v",
+  "✔" => "V",
+  "✕" => "x",
+  "✖" => "x",
+  "✗" => "X",
+  "✘" => "X",
+  "✙" => "+",
+  "✚" => "+",
+  "✛" => "+",
+  "✜" => "+",
+  "âœ" => "+",
+  "✞" => "+",
+  "✟" => "+",
+  "✠" => "+",
+  "✡" => "*",
+  "✢" => "+",
+  "✣" => "+",
+  "✤" => "+",
+  "✥" => "+",
+  "✦" => "+",
+  "✧" => "+",
+  "✩" => "*",
+  "✪" => "*",
+  "✫" => "*",
+  "✬" => "*",
+  "✭" => "*",
+  "✮" => "*",
+  "✯" => "*",
+  "✰" => "*",
+  "✱" => "*",
+  "✲" => "*",
+  "✳" => "*",
+  "✴" => "*",
+  "✵" => "*",
+  "✶" => "*",
+  "✷" => "*",
+  "✸" => "*",
+  "✹" => "*",
+  "✺" => "*",
+  "✻" => "*",
+  "✼" => "*",
+  "✽" => "*",
+  "✾" => "*",
+  "✿" => "*",
+  "â€" => "*",
+  "â" => "*",
+  "â‚" => "*",
+  "âƒ" => "*",
+  "â„" => "*",
+  "â…" => "*",
+  "â†" => "*",
+  "â‡" => "*",
+  "âˆ" => "*",
+  "â‰" => "*",
+  "âŠ" => "*",
+  "â‹" => "*",
+  "ff" => "ff",
+  "ï¬" => "fi",
+  "fl" => "fl",
+  "ffi" => "ffi",
+  "ffl" => "ffl",
+  "ſt" => "st",
+  "st" => "st"
+  );
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/crossref/biblio.crossref.client.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,326 @@
+<?php
+class BiblioCrossRefClient
+{
+
+  const BASE_URL = 'http://www.crossref.org/openurl/';
+  private $pid;
+  private $doi;
+  private $query;
+  private $url;
+  private $nodes;
+  private $node;
+  private $parser;
+  private $element;
+  private $attribute;
+  private $auth_category;
+  private $contrib_count;
+  private $contribtors;
+  private $org_count;
+  private $field_map;
+  private $type_map;
+
+  public function __construct($doi = '', $id = '')
+  {
+    $this->setDOI($doi);
+    $this->setUserID($id);
+    $this->setURL(self::BASE_URL);
+    $this->field_map = array();
+    $this->type_map = array();
+  }
+
+  public function setURL($url) {
+    $this->url = $url;
+  }
+
+  public function setDOI($doi) {
+    $this->doi = $doi;
+  }
+
+  public function getDOI() {
+    return $this->doi;
+  }
+
+  public function setUserID($id) {
+    $this->pid = $id;
+  }
+
+  public function getUserID() {
+    return $this->pid;
+  }
+
+  public function getQuery() {
+    return $this->query;
+  }
+
+  public function fetch() {
+    $this->query = $this->url . '?pid=' . $this->pid . '&noredirect=true&format=unixref&id=doi%3A' . $this->doi;
+
+    $request_options = array('method' => 'POST');
+    $result = drupal_http_request($this->query, $request_options);
+
+    if ($result->code != 200) {
+      drupal_set_message(t('HTTP error: !error when trying to contact crossref.org for XML input', array('!error' => $result->code)),'error');
+      return;
+    }
+    if (empty($result->data)) {
+      drupal_set_message(t('Did not get any data from crossref.org'),'error');
+      return;
+    }
+    $sxml = @simplexml_load_string($result->data);
+    if (!isset($sxml->doi_record)) {
+    	drupal_set_message(t('Failed to retrieve data for doi ') . $this->doi, 'error');
+      return;
+    }
+
+    if ($error = (string)$sxml->doi_record->crossref->error) {
+      drupal_set_message($error,'error');
+      return;
+    }
+    $this->nodes = array();
+    $this->parser = drupal_xml_parser_create($result->data);
+    // use case-folding so we are sure to find the tag in
+    xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, FALSE);
+    xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, TRUE);
+
+    xml_set_object($this->parser, $this);
+    xml_set_element_handler($this->parser, 'unixref_startElement', 'unixref_endElement');
+    xml_set_character_data_handler($this->parser, 'unixref_characterData');
+
+    if(!xml_parse($this->parser, $result->data)){
+      drupal_set_message(sprintf("XML error: %s at line %d",
+      xml_error_string(xml_get_error_code($this->parser)),
+      xml_get_current_line_number($this->parser)),'error');
+    }
+
+    xml_parser_free($this->parser);
+
+    return $this->node;
+  }
+
+
+  function unixref_startElement($parser, $name, $attrs) {
+    switch ($name) {
+      case 'doi_record' :
+        $this->node = array();
+        $this->node['biblio_contributors'] = array();
+        $this->contributors = array();
+        $this->element = $name;
+        break;
+      case 'book':
+      case 'journal':
+      case 'standard':
+      case 'conference':
+      case 'report-paper':
+      case 'dissertation':
+      case 'database':
+      case 'sa_component':
+        $this->node['biblio_type'] = $this->_unixref_type_map($name);
+        $this->element = $name;
+        break;
+      case 'journal_article':
+      case 'conference_paper':
+      case 'content_item':
+      case 'report-paper_metadata':
+      case 'standard_metadata':
+      case 'database_date':
+      case 'component':
+        $this->node['year'] = '';
+        $this->node['doi']  = '';
+        $this->element = $name;
+        break;
+      case 'person_name' :
+        $this->auth_category = $this->_unixref_get_contributor_category($attrs['contributor_role']);
+        if (!isset($this->contrib_count)) $this->contrib_count = 0;
+        $this->element = $name;
+        break;
+      case 'organization':
+        if (!isset($this->org_count)) $this->org_count = 0;
+        $this->element = $name;
+        break;
+      case 'issn':
+        if (isset($attrs['media_type']) ) $this->attribute = $attrs['media_type'];
+        $this->element = $name;
+        break;
+      case 'isbn':
+        if (isset($attrs['media_type']) ) $this->attribute = $attrs['media_type'];
+        $this->element = $name;
+        break;
+      case 'i':  // HTML font style tags
+      case 'b':
+      case 'u':
+      case 'sub':
+      case 'sup':
+        $this->unixref_characterData(NULL, ' <' . $name . '>');
+        break;
+      case 'doi_data':
+        $this->doi_data = TRUE;
+        break;
+      default :
+        $this->element = $name;
+    }
+
+  }
+
+  function unixref_decode(&$item, $key) {
+    $item = html_entity_decode($item, NULL, 'UTF-8');
+  }
+
+  function unixref_endElement($parser, $name) {
+    switch ($name) {
+      case 'doi_record' :
+        $this->node['biblio_contributors'] += $this->contributors;
+        array_walk_recursive($this->node, array($this,'unixref_decode') );
+        $this->node['biblio_crossref_id']  = $this->getDOI();
+        $this->node['biblio_crossref_md5'] = md5(serialize($this->node));
+        $this->nodes[] = $this->node; //biblio_save_node($node, $batch, $session_id, $save_node);
+        break;
+      case 'person_name' :
+        $this->contributors[$this->contrib_count]['auth_type'] = _biblio_get_auth_type($this->auth_category, $this->node['biblio_type']);
+        $this->contributors[$this->contrib_count]['auth_category'] = $this->auth_category;
+        $this->contributors[$this->contrib_count]['name'] =
+        $this->contributors[$this->contrib_count]['lastname'];
+        if (isset($this->contributors[$this->contrib_count]['firstname'])) {
+          $this->contributors[$this->contrib_count]['name'] .=
+            ', ' . $this->contributors[$this->contrib_count]['firstname'];
+        }
+
+        $this->auth_category = '';
+        $this->contrib_count++;
+        break;
+      case 'organization' :
+        $this->contributors[$this->contrib_count]['auth_type'] = _biblio_get_auth_type(5, $this->node['biblio_type']);
+        $this->contributors[$this->contrib_count]['auth_category'] = 5;
+        $this->contrib_count++;
+        break;
+      case 'pages':
+        if (isset($this->node['biblio_first_page'])) $this->node['biblio_pages'] = $this->node['biblio_first_page'];
+        if (isset($this->node{'biblio_last_page'}))  $this->node['biblio_pages'] .= ' - ' . $this->node['biblio_last_page'];
+        break;
+      case 'publication_date':
+
+        break;
+      case 'journal_issue':
+      case 'journal_article':
+        if (!isset($this->node['biblio_date']) || empty($this->node['biblio_date'])) {
+          $day   = !empty($this->node['day'])   ? $this->node['day']   : 1;
+          $month = !empty($this->node['month']) ? $this->node['month'] : 1;
+          $year  = !empty($this->node['year'])  ? $this->node['year']  : 0;
+          if ($year) {
+            $this->node['biblio_date'] = date("M-d-Y", mktime(0, 0, 0, $day, $month, $year));
+          }
+        }
+        if ((!isset($this->node['biblio_year']) || empty($this->node['biblio_year'])) && isset($this->node['year'])) {
+          $this->node['biblio_year'] = $this->node['year'];
+        }
+        break;
+      case 'conference_paper':
+      case 'content_item':
+      case 'report-paper_metadata':
+      case 'standard_metadata':
+      case 'database_date':
+      case 'component':
+        if ((!isset($this->node['biblio_year']) || empty($this->node['biblio_year'])) && isset($this->node['year'])) {
+          $this->node['biblio_year'] = $this->node['year'];
+          unset($this->node['year']);
+        }
+//        $this->node['biblio_doi']  = $this->node['doi'];
+        break;
+      case 'issn':
+      case 'isbn':
+        $this->attribute = '';
+        break;
+      case 'i':  // HTML font style tags
+      case 'b':
+      case 'u':
+      case 'sub':
+      case 'sup':
+        $this->unixref_characterData(NULL, '</' . $name . '> ');
+        break;
+      case 'doi_data':
+        $this->doi_data = FALSE;
+        break;
+      default :
+    }
+  }
+
+  function unixref_characterData($parser, $data) {
+    $data = htmlspecialchars_decode($data);
+    if (trim($data)) {
+      switch ($this->element) {
+        case 'surname' :
+          $this->contributors[$this->contrib_count]['lastname'] = $data;
+          break;
+        case 'given_name' :
+          $this->contributors[$this->contrib_count]['firstname'] = $data;
+          break;
+        case 'suffix':
+          $this->contributors[$this->contrib_count]['suffix'] = $data;
+          break;
+        case 'affiliation' :
+          $this->contributors[$this->contrib_count]['affiliation'] = $data;
+          break;
+        case 'organization':
+          $this->contributors[$this->contrib_count]['name'] = $data;
+          break;
+        case 'year':
+        case 'month':
+        case 'day':
+         $this->node[$this->element] = $data;
+          break;
+        case 'issn':
+        case 'isbn':
+          if ($this->attribute == 'print') {
+            if ($field = $this->_unixref_field_map(trim($this->element))) {
+              $this->_set_data($field, $data);
+            }
+          }
+          break;
+        case 'doi':
+          if ($this->doi_data) {
+            if ($field = $this->_unixref_field_map(trim($this->element))) {
+              $this->_set_data($field, $data);
+            }
+          }
+          break;
+        case 'resource':
+          if ($this->doi_data) {
+              $this->_set_data('biblio_url', $data);
+          }
+          break;
+
+        default:
+          if ($field = $this->_unixref_field_map(trim($this->element))) {
+            $this->_set_data($field, $data);
+          }
+
+      }
+    }
+  }
+  function _set_data($field, $data) {
+    $this->node[$field] = (isset($this->node[$field]) ? $this->node[$field] . $data : $data);
+  }
+  /*
+   * map a unixref XML field to a biblio field
+   */
+  function _unixref_field_map($field) {
+    if (empty($this->field_map)) {
+      $this->field_map = unserialize(db_query("SELECT field_map FROM {biblio_type_maps} WHERE format='crossref'")->fetchField());
+    }
+    return (isset($this->field_map[$field])) ? $this->field_map[$field]: FALSE;
+  }
+
+  function _unixref_type_map($type) {
+    if (empty($this->type_map)) {
+      $this->type_map = unserialize(db_query("SELECT type_map FROM {biblio_type_maps} WHERE format='crossref'")->fetchField());
+    }
+    return (isset($this->type_map[$type]))?$this->type_map[$type]:129; //return the biblio type or 129 (Misc) if type not found
+  }
+
+  function _unixref_get_contributor_category($role) {
+    if ($role == 'author') return 1;
+    if ($role == 'editor') return 2;
+    if ($role == 'chair') return 3;
+    if ($role == 'translator') return 4;
+    return NULL;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/crossref/biblio_crossref.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Biblio - Crossref
+description = Provides DOI lookup and import to the Biblio module.
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = biblio.crossref.client.php
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/crossref/biblio_crossref.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,151 @@
+<?php
+/**
+ * @file
+ * Database table creation for biblio_crossref module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function biblio_crossref_install() {
+  _save_crossref_maps();
+}
+
+function biblio_crossref_uninstall() {
+  if (db_table_exists('biblio_type_maps')) {
+    db_delete('biblio_type_maps')
+      ->condition('format', 'crossref')
+      ->execute();
+  }
+}
+
+function biblio_crossref_enable() {
+  biblio_crossref_set_system_weight();
+}
+
+function biblio_crossref_set_system_weight() {
+  db_update('system')
+    ->fields(array('weight' => 20))
+    ->condition('name', 'biblio_crossref')
+    ->execute();
+}
+function _save_crossref_maps() {
+  $typemap = _get_crossref_type_map();
+  $typenames = _get_crossref_type_names();
+  $fieldmap = _get_crossref_field_map();
+  $maps = array_merge($typemap, $typenames, $fieldmap);
+  biblio_save_map($maps);
+}
+function _reset_crossref_map($type) {
+  $count = db_query("SELECT COUNT(*) FROM {biblio_type_maps} WHERE format='crossref'")->fetchField();
+  if ($count && $type) { //update
+    $function = '_get_crossref_' . $type;
+    if (!function_exists($function)) return;
+    $map = $function();
+    db_update('biblio_type_maps')
+      ->fields($map)
+      ->condition('format', 'crossref')
+      ->execute();
+  }
+  else { // install
+//    db_query("DELETE FROM {biblio_type_maps} WHERE format='crossref'");
+    db_delete('biblio_type_maps')
+      ->condition('format', 'crossref')
+      ->execute();
+      _save_crossref_maps();
+  }
+}
+
+function _get_crossref_type_map() {
+  $map['type_map'] = serialize(
+        array(
+                'error'        => 0,
+                'book'         => 100, // Book
+                'journal'      => 102, // Journal Article
+                'standard'     => 129, // Generic
+                'conference'   => 103, // conference_paper
+                'report-paper' => 109, // Report
+                'dissertation' => 108, // Thesis
+                'database'     => 125, // online database
+                'sa_component' => 129
+        )
+  );
+  $map['format'] = 'crossref';
+  return $map;
+}
+
+function _get_crossref_type_names() {
+  $map['type_names'] =  serialize(
+        array(
+                'error'        => 'Error',
+                'book'         => 'Book',
+                'journal'      => 'Journal Article',
+                'standard'     => 'Generic',
+                'conference'   => 'Conference Paper',
+                'report-paper' => 'Report',
+                'dissertation' => 'Thesis',
+                'database'     => 'Online database',
+                'sa_component' => 'SA Component',
+        )
+  );
+  $map['format'] = 'crossref';
+  return $map;
+}
+
+function _get_crossref_field_map() {
+  $map['field_map'] =  serialize(
+        array(
+                'publisher_place'     => 'biblio_place_published',
+                'publisher_name'      => 'biblio_publisher',
+                'volume'              => 'biblio_volume',
+                'number'              => 'biblio_number',
+                'issue'               => 'biblio_issue',
+                'edition_number'      => 'biblio_edition',
+                'section'             => 'biblio_section',
+                'doi'                 => 'biblio_doi',
+                'title'               => 'title',
+                'isbn'                => 'biblio_isbn',
+                'issn'                => 'biblio_issn',
+                'first_page'          => 'biblio_first_page',
+                'last_page'           => 'biblio_last_page',
+                // Journal metadata
+                'full_title'          => 'biblio_secondary_title',
+                'abbrev_title'        => 'biblio_short_title',
+                // Conference metadata
+                'conference_location' => 'biblio_place_published',
+                'conference_name'     => 'biblio_secondary_title',
+                'conference_acronym'  => 'biblio_short_title',
+                // Proceedings metadata
+                'proceedings_title'   => 'biblio_secondary_title',
+                'year'                => 'year',
+                'month'               => 'month',
+                'day'                 => 'day',
+                'degree'              => 'biblio_type_of_work',
+                'error'               => 'error',
+                'language'            => 'biblio_lang',
+        )
+  );
+
+  $map['format'] = 'crossref';
+  return $map;
+
+}
+
+/**
+ * Implementation of hook_schema().
+ *
+ * Note:  Pro Drupal Development models use of t() to translate 'description'
+ * for field definitions, but Drupal core does not use them.  We follow core.
+ */
+function biblio_crossref_schema() {
+  $schema = array();
+  $schema['biblio_crossref'] = array(
+    'fields' => array(
+      'nid'       => array('type' => 'int', 'not null' => TRUE),
+      'biblio_crossref_md5'       => array('type' => 'char', 'length' => 32, 'not null' => TRUE),
+      'biblio_crossref_id' => array('type' => 'char', 'length' => 255, 'not null' => TRUE),
+      ),
+  'primary key' => array('nid'),
+  );
+  return $schema;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/crossref/biblio_crossref.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,168 @@
+<?php
+/*
+ * @file biblio_crossref.module
+ *
+ */
+
+function biblio_crossref_form_biblio_node_form_alter(&$form, &$form_state) {
+  global $user;
+  if (phpversion() > 5 && !$form_state['submitted'] && !isset($form['#node']->nid)) {
+    $form['biblio_doi_lookup'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('DOI Lookup'),
+        '#weight' => -20,
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+    );
+    $have_pid = variable_get('biblio_crossref_pid', '');
+    $user_pid = (isset($user->data['biblio_crossref_pid']) && !empty($user->data['biblio_crossref_pid'])) ? $user->data['biblio_crossref_pid'] : '';
+    if (variable_get('biblio_show_crossref_profile_form', '1') && !empty($user_pid)) {
+      $have_pid = $user_pid;
+    }
+    if (empty($have_pid)) {
+      $form['biblio_doi_lookup']['doi_register'] = array(
+          '#prefix' => '<p><b>',
+          '#suffix' => '</b></p>',
+          '#markup' => t('!url1 and then enter your CrossRef UserID in the "<i>CrossRef Login Information</i>" section of your account profile !url2', array('!url1' => l(t('You need to register with CrossRef'), 'http://www.crossref.org/requestaccount/', array('attributes' => array('target' => '_blank'), 'absolue' => TRUE)), '!url2' => l(t('here...'), "user/$user->uid/edit"))),
+      );
+    }
+
+    $form['biblio_doi_lookup']['doi_data'] = array(
+        '#type' => 'textfield',
+        '#title' => t('DOI'),
+        '#required' => FALSE,
+        '#default_value' => (isset($form_state['values']['doi_data']) ? $form_state['values']['doi_data'] : ''),
+        '#description' => t('Enter a DOI name in the form: <b>10.1000/123456</b>'),
+        '#disabled' => empty($have_pid),
+        '#size' => 60,
+        '#maxlength' => 255,
+        '#weight' => -4
+    );
+    $form['biblio_doi_lookup']['doi_submit'] = array(
+        '#type' => 'submit',
+        '#disabled' => empty($have_pid),
+        '#value' => t('Populate using DOI'),
+        '#submit' => array('biblio_crossref_form_biblio_node_form_submit')
+    );
+  }
+  $biblio_crossref_id = (isset($form_state['values']['biblio_crossref_id'])) ? $form_state['values']['biblio_crossref_id'] : '';
+  $biblio_crossref_md5 = (isset($form_state['values']['biblio_crossref_md5'])) ? $form_state['values']['biblio_crossref_md5'] : '';
+  $form['biblio_crossref_id'] = array('#type' => 'value', '#value'  => $biblio_crossref_id);
+  $form['biblio_crossref_md5'] = array('#type' => 'value', '#value' => $biblio_crossref_md5);
+}
+
+function biblio_crossref_form_biblio_node_form_submit($form, &$form_state) {
+  global $user;
+  $node_data = array();
+  if (strlen($doi = $form_state['values']['doi_data'])) {
+    if (($doi_start = strpos($form_state['values']['doi_data'], '10.')) !== FALSE) {
+      if (!($dup = biblio_crossref_check_doi($doi))) {
+        $crossref_pid = variable_get('biblio_crossref_pid', '');
+        $user_pid = (isset($user->data['biblio_crossref_pid']) && !empty($user->data['biblio_crossref_pid'])) ? $user->data['biblio_crossref_pid'] : '';
+        if (variable_get('biblio_show_crossref_profile_form', '1') && !empty($user_pid)) {
+          $crossref_pid = $user_pid;
+        }
+
+        if (empty($crossref_pid)) {
+          form_set_error('doi_data', l(t('You need to register with CrossRef'), 'http://www.crossref.org/requestaccount/', array('attributes' => array('target' => '_blank'), 'absolue' => TRUE)) . ' ' . t('and then enter your CrossRef UserID in the "<i>CrossRef Login Information</i>" section of your account profile !url', array('!url' => l(t('here...'), "user/$user->uid/edit"))));
+          return;
+        }
+
+        module_load_include('php', 'biblio_crossref', 'biblio.crossref.client');
+        $client = new BiblioCrossRefClient($doi, $crossref_pid);
+        $node_data = $client->fetch();
+
+        if (!empty($node_data)) {
+          $form_state['values'] = array_merge($form_state['values'], $node_data);
+          $form_state['input']['biblio_type'] = $form_state['biblio_type'] = $node_data['biblio_type'];
+        }
+        else {
+          form_set_error('doi_data', '');
+        }
+      }
+      else {
+        $message = t('The DOI that you are trying to import already exists in the database, see !url', array('!url' => l('node/' . $dup, 'node/' . $dup)));
+        form_set_error('doi_data', $message);
+      }
+    }
+    else {
+      form_set_error('doi_data', t('This does not appear to be a valid DOI name, it should start with "10."'));
+    }
+  }
+  $form_state['rebuild'] = TRUE;
+  return;
+}
+
+function biblio_crossref_check_doi($doi) {
+    return db_query("SELECT nid FROM {biblio_crossref} WHERE biblio_crossref_id = :doi", array(':doi' => $doi))->fetchField();
+}
+
+function biblio_crossref_biblio_lookup_link_settings() {
+  return array('crossref'  => t('DOI'));
+}
+function biblio_crossref_biblio_mapper_options() {
+  return  array(
+    'crossref' => array(
+      'title' =>  t('CrossRef XML'),
+      'export' => FALSE,
+      ),
+  );
+}
+
+function biblio_crossref_biblio_lookup_link($node) {
+  $show_link = variable_get('biblio_lookup_links', array('crossref' => TRUE));
+  if (empty($show_link['crossref']) || !isset($node) || (!isset($node->biblio_crossref_id) && empty($node->biblio_doi))) {
+    return;
+  }
+  if ($node->type == 'biblio') {
+    $doi = isset($node->biblio_crossref_id) ? $node->biblio_crossref_id : $node->biblio_doi;
+    if ( ($doi_start = strpos($doi, '10.')) !== FALSE) {
+      $doi = substr($doi, $doi_start);
+    }
+    $link  = 'http://dx.doi.org/' . $doi;
+    return array('biblio_crossref' => array(
+        'title'      => t('DOI'),
+        'href'       => $link,
+        'attributes' => array('title' => t("Click to view the CrossRef listing for this node")),
+    ));
+  }
+  return ;
+  }
+
+
+function biblio_crossref_node_view($node, $view_mode, $langcode) {
+  if ($node->type == 'biblio' && (isset($node->biblio_crossref_id) || !empty($node->biblio_doi))) {
+    switch ($view_mode) {
+      case 'full':
+      case 'teaser':
+        $node->content['links']['biblio_crossref'] = array(
+          '#links' => biblio_crossref_biblio_lookup_link($node),
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
+    }
+  }
+}
+
+function biblio_crossref_node_delete($node) {
+  if ($node->type != 'biblio') return;
+  db_delete('biblio_crossref')
+    ->condition('nid', $node->nid)
+    ->execute();
+}
+
+function biblio_crossref_node_insert($node) {
+  if ($node->type != 'biblio') return;
+  if (empty($node->biblio_crossref_id)) return;
+  drupal_write_record('biblio_crossref', $node);
+}
+
+function biblio_crossref_node_load($nodes, $types) {
+  $result = db_query('SELECT  nid, biblio_crossref_id  FROM {biblio_crossref} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)));
+  foreach ($result as $record) {
+    $nodes[$record->nid]->biblio_crossref_id = $record->biblio_crossref_id;
+  }
+}
+function biblio_crossref_crossref_map_reset($type = NULL) {
+  module_load_include('install', 'biblio_crossref', 'biblio_crossref');
+ _reset_crossref_map($type);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/endnote/biblio_tagged.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Biblio - EndNote Tagged
+description = Provides EndNote tagged file import and export to the Biblio module.
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = views/biblio_handler_field_export_link_tagged.inc
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/endnote/biblio_tagged.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,196 @@
+<?php
+/**
+ * @file
+ * Database table creation for biblio_tagged module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function biblio_tagged_install() {
+  _save_tagged_maps();
+}
+
+function biblio_tagged_uninstall() {
+  if (db_table_exists('biblio_type_maps')) {
+    db_delete('biblio_type_maps')
+      ->condition('format', 'tagged')
+      ->execute();
+  }
+}
+
+function biblio_tagged_enable() {
+  biblio_tagged_set_system_weight();
+}
+
+function biblio_tagged_set_system_weight() {
+  db_update('system')
+    ->fields(array('weight' => 22))
+    ->condition('name', 'biblio_tagged')
+    ->execute();
+}
+
+function _get_tagged_type_map() {
+  $map['type_map'] = serialize(
+        array(
+                "Journal Article"         => 102,
+                "Conference Paper"        => 103,
+                "Conference Proceedings"  => 104,
+                "Report"                  => 109,
+                "Book"                    => 100,
+                "Edited Book"             => 100,
+                "Book Section"            => 101,
+                "Thesis"                  => 108,
+                "Patent"                  => 119,
+                "Generic"                 => 129,
+                "Newspaper Article"       => 105,
+                "Magazine Article"        => 106,
+                "Web Page"                => 107,
+                "Film or Broadcast"       => 110,
+                "Artwork"                 => 112,
+                "Audiovisual Material"    => 114,
+                "Hearing"                 => 115,
+                "Case"                    => 116,
+                "Bill"                    => 117,
+                "Statute"                 => 118,
+                "Personal Communication"  => 120,
+                "Manuscript"              => 121,
+                "Map"                     => 122,
+                "Chart or Table"          => 123,
+                "Unpublished Work"        => 124,
+                "Online Database"         => 125,
+                "Government Document"     => 126,
+                "Classical Work"          => 127,
+                "Legal Rule or Regulation" => 128,
+        )
+  );
+  $map['format'] = 'tagged';
+  return $map;
+}
+function _get_tagged_type_names() {
+  $map['type_names'] =  serialize(
+        array(
+                "Journal Article"         => "Journal Article",
+                "Conference Paper"        => "Conference Paper",
+                "Conference Proceedings"  => "Conference Proceedings",
+                "Report"                  => "Report",
+                "Book"                    => "Book",
+                "Edited Book"             => "Edited Book",
+                "Book Section"            => "Book Section",
+                "Thesis"                  => "Thesis",
+                "Patent"                  => "Patent",
+                "Generic"                 => "Generic",
+                "Newspaper Article"       => "Newspaper Article",
+                "Magazine Article"        => "Magazine Article",
+                "Web Page"                => "Web Page",
+                "Film or Broadcast"       => "Film or Broadcast",
+                "Artwork"                 => "Artwork",
+                "Audiovisual Material"    => "Audiovisual Material",
+                "Hearing"                 => "Hearing",
+                "Case"                    => "Case",
+                "Bill"                    => "Bill",
+                "Statute"                 => "Statute",
+                "Personal Communication"  => "Personal Communication",
+                "Manuscript"              => "Manuscript",
+                "Map"                     => "Map",
+                "Chart or Table"          => "Chart or Table",
+                "Unpublished Work"        => "Unpublished Work",
+                "Online Database"         => "Online Database",
+                "Government Document"     => "Government Document",
+                "Classical Work"          => "Classical Work",
+                "Legal Rule or Regulation" => "Legal Rule or Regulation",
+        )
+  );
+
+  $map['format'] = 'tagged';
+  return $map;
+}
+
+function _get_tagged_field_map() {
+  $map['field_map'] =  serialize(
+        array(
+                '%B' => 'biblio_secondary_title',
+                '%C' => 'biblio_place_published',
+                '%D' => 'biblio_year',
+                '%F' => 'biblio_label',
+                '%G' => 'biblio_lang',
+                '%I' => 'biblio_publisher',
+                '%J' => 'biblio_secondary_title',
+                '%K' => 'biblio_keywords',
+                '%L' => 'biblio_call_number',
+                '%M' => 'biblio_accession_number',
+                '%N' => 'biblio_issue',
+                '%P' => 'biblio_pages',
+                '%R' => 'biblio_doi',
+                '%S' => 'biblio_tertiary_title',
+                '%U' => 'biblio_url',
+                '%V' => 'biblio_volume',
+                '%1' => 'biblio_custom1',
+                '%2' => 'biblio_custom2',
+                '%3' => 'biblio_custom3',
+                '%4' => 'biblio_custom4',
+                '%#' => 'biblio_custom5',
+                '%$' => 'biblio_custom6',
+                '%]' => 'biblio_custom7',
+                '%6' => 'biblio_number_of_volumes',
+                '%7' => 'biblio_edition',
+                '%8' => 'biblio_date',
+                '%9' => 'biblio_type_of_work',
+                '%?' => '',
+                '%@' => 'biblio_isbn',
+                '%<' => 'biblio_research_notes',
+                '%!' => 'biblio_short_title',
+                '%&' => 'biblio_section',
+                '%(' => 'biblio_original_publication',
+                '%)' => 'biblio_reprint_edition',
+                '%*' => '',
+                '%+' => '',
+        )
+  );
+  $map['format'] = 'tagged';
+  return $map;
+}
+
+function _save_tagged_maps() {
+  $typemap = _get_tagged_type_map();
+  $typenames = _get_tagged_type_names();
+  $fieldmap = _get_tagged_field_map();
+  $maps = array_merge($typemap, $typenames, $fieldmap);
+  biblio_save_map($maps);
+}
+
+function _reset_tagged_map($type) {
+  $count = db_query("SELECT COUNT(*) FROM {biblio_type_maps} WHERE format='tagged'")->fetchField();
+  if ($count && $type) { //update
+    $function = '_get_tagged_' . $type;
+    if (!function_exists($function)) return;
+    $map = $function();
+    db_update('biblio_type_maps')
+      ->fields($map)
+      ->condition('format', 'tagged')
+      ->execute();
+  }
+  else { // install
+    db_delete('biblio_type_maps')
+      ->condition('format', 'tagged')
+      ->execute();
+    _save_tagged_maps();
+  }
+}
+/**
+ * Implementation of hook_schema().
+ *
+ * Note:  Pro Drupal Development models use of t() to translate 'description'
+ * for field definitions, but Drupal core does not use them.  We follow core.
+ */
+function biblio_tagged_schema() {
+  $schema = array();
+  $schema['biblio_tagged'] = array(
+    'fields' => array(
+      'nid'       => array('type' => 'int', 'not null' => TRUE),
+      'biblio_tagged_md5' => array('type' => 'char', 'length' => 32, 'not null' => TRUE),
+      ),
+  'primary key' => array('nid'),
+  );
+  return $schema;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/endnote/biblio_tagged.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,407 @@
+<?php
+/*
+ * @file biblio_tagged.module
+ *
+ */
+function biblio_tagged_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'biblio_tagged') . '/views',
+  );
+}
+/*
+ *   add the tagged option to the option list of the biblio_import_form
+ *   the key is the module name use by module_invoke to call hook_biblio_import
+ *   module_invoke('biblio_tagged', 'biblio_import',...)
+ */
+function biblio_tagged_biblio_import_options() {
+  return array('biblio_tagged' => t('EndNote Tagged'));
+}
+function biblio_tagged_biblio_mapper_options() {
+  return  array(
+    'tagged' => array(
+      'title' => t('EndNote Tagged'),
+      'export' => TRUE,
+      )
+    );
+}
+
+function biblio_tagged_biblio_export_options() {
+  return array('tagged' => t('EndNote Tagged'));
+}
+
+function biblio_tagged_node_view($node, $view_mode) {
+  if ($node->type == 'biblio') {
+    switch ($view_mode) {
+      case 'full':
+      case 'teaser':
+        $links = biblio_tagged_biblio_export_link($node->nid);
+        $node->content['links']['biblio_tagged'] = array(
+          '#links' => $links,
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
+    }
+  }
+}
+
+/**
+ * Creates a link to export a node (or view) in tagged format
+ *
+ * @param $base this is the base url (defaults to /biblio)
+ * @param $nid  the node id, if NULL then the current view is exported
+ * @return  a link (<a href=...>tagged</a>)
+ */
+function biblio_tagged_biblio_export_link($nid = NULL, $filter = array()) {
+  $show_link = variable_get('biblio_export_links', array('tagged' => TRUE));
+  if (!isset($show_link['tagged']) || empty($show_link['tagged']) || !biblio_access('export')) {
+    return array();
+  }
+  $base = variable_get('biblio_base', 'biblio');
+
+  if (module_exists('popups') && !empty($nid)) {
+    $link = array(
+        'attributes' => array(
+          'class' => 'popups',
+          'title' => t("Click to get the EndNote Tagged output")));
+  }
+  else {
+    $link = array(
+        'attributes' => array(
+          'title' => t("Click to download the EndNote Tagged formatted file")));
+  }
+
+  $link['attributes'] += array('rel' => 'nofollow');
+
+  $link['href']  = "$base/export/tagged";
+  if (!empty($nid)) {
+    $link['href'] .= '/' . $nid;
+  }
+  $link['title'] = t('Tagged');
+
+  if (empty($nid) && !empty($filter)) { // add any filters which may be on the current page
+    $link['query'] = $filter;
+  }
+
+  return array('biblio_tagged' => $link);
+}
+
+
+function biblio_tagged_node_delete($node) {
+  if ($node->type != 'biblio') {
+    return;
+  }
+  db_delete('biblio_tagged')
+    ->condition('nid', $node->nid)
+    ->execute();
+}
+
+function biblio_tagged_node_insert($node) {
+  if ($node->type != 'biblio' || !isset($node->biblio_tagged_md5)) {
+    return;
+  }
+  drupal_write_record('biblio_tagged', $node);
+}
+
+function biblio_tagged_biblio_import($file, $terms = array(), $batch = FALSE, $session_id = NULL, $save = TRUE, $string = FALSE) {
+  $nids = array();
+  $dups = array();
+  list($nids, $dups) = _biblio_tagged_import($file, $terms, $batch, $session_id);
+
+  return array($nids, $dups);
+}
+
+function biblio_tagged_biblio_export($nids) {
+  if (module_exists('popups') && count($nids)) {
+    $popup = TRUE;
+  }
+  else {
+    $popup = FALSE;
+    drupal_add_http_header('Content-type', 'application/x-endnote-refer');
+    drupal_add_http_header('Content-Disposition', 'attachment; filename="Drupal-Biblio.enw"');
+  }
+
+  $nodes = node_load_multiple($nids, array(), TRUE);
+  foreach ($nodes as $node) {
+    if (variable_get('biblio_hide_bibtex_braces', 0) ) {
+      $node->title = biblio_remove_brace($node->title);
+    }
+
+    if (!$popup) {
+      print _biblio_tagged_export($node);
+    }
+    else{
+      $popup_data .=  _biblio_tagged_export($node);
+    }
+  }
+  if ($popup && !empty($popup_data)) return '<pre>' . $popup_data . '</pre>';
+
+}
+
+/**
+ * Export data in tagged format.
+ *
+ * @param $result
+ *   a database result set pointer
+ * @return
+ *   none
+ */
+
+function _biblio_tagged_import($file, $terms = array(), $batch = FALSE, $session_id = NULL) {
+  ini_set('auto_detect_line_endings', TRUE);
+  if (!($fp = fopen($file->uri, "r"))) {
+    drupal_set_message(t("Could not open EndNote Tagged input"), 'error');
+    return;
+  }
+  $nids = array();
+  $dups = array();
+  $ignored_tags = array();
+  $node = NULL;
+  $incite = FALSE;
+  $node_id = NULL;
+  $contributors = NULL;
+  while (!feof($fp)) {
+    $line = trim(fgets($fp));
+    $line_len = strlen($line);
+    if ($line_len) {
+      $start = strpos($line, "%"); // There could be some unprintables at the beginning of the line so fine the location of the %
+      if ($start !== FALSE) {
+        $tag = drupal_substr($line, $start, 2);
+        $value = trim(drupal_substr($line, $start +3));
+      }
+      else {
+        $value = $line;
+      }
+    }
+    if ($line_len) { // if this is not a blank line
+      if (!$incite) {
+        $incite = TRUE;
+        $node = new stdClass();
+        //$node->biblio_contributors = array();
+
+      }
+      switch ($tag) {
+        case '%0' :
+          $node->biblio_type = _biblio_tagged_type_map($value);
+          break;
+        case '%A' :
+          $node->biblio_contributors[] = array(
+            'name' => $value,
+            'auth_category' => 1,
+            'auth_type' => _biblio_get_auth_type(1, $node->biblio_type));
+          break;
+        case '%E' :
+          $node->biblio_contributors[] = array(
+            'name' => $value,
+            'auth_category' => 2,
+            'auth_type' => _biblio_get_auth_type(2, $node->biblio_type));
+          break;
+        case '%T' :
+          $node->title = $value;
+          break;
+        case '%Y' :
+          $node->biblio_contributors[] = array(
+            'name' => $value,
+            'auth_category' => 3,
+            'auth_type' => _biblio_get_auth_type(3, $node->biblio_type));
+          break;
+        case '%?' :
+          $node->biblio_contributors[] = array(
+            'name' => $value,
+            'auth_category' => 4,
+            'auth_type' => _biblio_get_auth_type(4, $node->biblio_type));
+          break;
+        case '%X' :
+          $node->biblio_abst_e .= $value;
+          break;
+        case '%Z' :
+          $node->biblio_notes .= $value;
+          break;
+
+        default :
+          $field = _biblio_tagged_field_map($tag);
+          if (!empty($field)) {
+            $node->$field = $value;
+          }
+          else {
+            if (!in_array($tag, $ignored_tags)) {
+              $ignored_tags[] = $tag;
+            }
+          }
+          break;
+      } //end switch
+    }
+    else {
+      $incite = FALSE;
+      if (!empty($node)) {
+        _biblio_tagged_save($node, $terms, $batch, $session_id, $nids, $dups);
+        $node = NULL;
+      }
+
+    } // end if ($start !== FALSE)
+  } // end while
+
+  fclose($fp);
+
+  if ($incite && !empty($node)) {  // this catches the case where the file ends without a blank line at the end
+    _biblio_tagged_save($node, $terms, $batch, $session_id, $nids, $dups);
+  }
+
+  if (!empty($ignored_tags)) {
+    $ignored_tags = array_unique($ignored_tags);
+    $message = t("The following elements were ignored because they do not map to any biblio fields:") . ' ';
+    $message .= implode(', ', $ignored_tags);
+    if (user_access('administer biblio')) {
+      $message .= '. ' . t('Click !url if you wish to check the field mapping', array('!url' => l(t('here'), 'admin/config/content/biblio/iomap/edit/tagged')));
+    }
+    drupal_set_message($message, 'warning');
+  }
+
+  return array($nids, $dups);
+}
+
+function _biblio_tagged_save($node, $terms, $batch, $session_id, &$nids, &$dups) {
+  $node->biblio_tagged_md5 = md5(serialize($node));
+  if (! ($dup = biblio_tagged_check_md5($node->biblio_tagged_md5))) {
+    biblio_save_node($node, $terms, $batch, $session_id);
+    if (!empty($node->nid)) $nids[] = $node->nid;
+  }
+  else {
+    $dups[] = $dup;
+  }
+}
+
+function _biblio_tagged_export($node) {
+  $export = TRUE;
+  $tagged = "";
+  $tagged .= "%0 " . _biblio_tagged_type_map($node->biblio_type, $export) . "\r\n";
+  switch ($node->biblio_type) {
+    case 100 :
+    case 101 :
+    case 103 :
+    case 104 :
+    case 105 :
+    case 108 :
+    case 119 :
+      if (!empty($node->biblio_secondary_title))
+      $tagged .= "%B " . trim($node->biblio_secondary_title) . "\r\n";
+      break;
+    case 102 :
+      if (!empty($node->biblio_secondary_title))
+      $tagged .= "%J " . trim($node->biblio_secondary_title) . "\r\n";
+      break; // journal
+  }
+  if (isset($node->biblio_year) && $node->biblio_year < 9998)  $tagged .= "%D " . trim($node->biblio_year) . "\r\n";
+  if (!empty($node->title))  $tagged .= "%T " . trim($node->title) . "\r\n";
+
+  foreach (biblio_get_contributor_category($node->biblio_contributors, 1) as $auth) {
+    $tagged .= "%A " . trim($auth['name']) . "\r\n";
+  }
+  foreach (biblio_get_contributor_category($node->biblio_contributors, 2) as $auth) {
+    $tagged .= "%E " . trim($auth['name']) . "\r\n";
+  }
+  foreach (biblio_get_contributor_category($node->biblio_contributors, 3) as $auth) {
+    $tagged .= "%Y " . trim($auth['name']) . "\r\n";
+  }
+  foreach (biblio_get_contributor_category($node->biblio_contributors, 4) as $auth) {
+    $tagged .= "%? " . trim($auth['name']) . "\r\n";
+  }
+
+  $kw_array = array();
+  if (!empty($node->terms)) {
+    foreach ($node->terms as $term) {
+      $kw_array[] = $term->name;
+    }
+  }
+  if (!empty($node->biblio_keywords)) {
+    foreach ($node->biblio_keywords as $term) {
+      $kw_array[] = $term;
+    }
+  }
+  if (!empty($kw_array)) {
+    $kw_array = array_unique($kw_array);
+    foreach ($kw_array as $term) {
+      $tagged .= "%K " . trim($term) . "\r\n";
+    }
+  }
+  $abst = "";
+  if (!empty($node->biblio_abst_e))  $abst .= trim($node->biblio_abst_e);
+  if ($abst) {
+    $search = array("/\r/", "/\n/");
+    $replace = " ";
+    $abst = preg_replace($search, $replace, $abst);
+    $tagged .= "%X " . $abst . "\r\n";
+  }
+  $skip_fields = array('biblio_year',  'biblio_abst_e', 'biblio_abst_f', 'biblio_type' );
+  $fields = drupal_schema_fields_sql('biblio');
+  $fields = array_diff($fields, $skip_fields);
+  foreach ($fields as $field) {
+    if (!empty($node->$field)) {
+      $tagged .= _biblio_tagged_format_entry($field, $node->$field);
+    }
+  }
+  if (!empty ($node->upload) && count($node->upload['und']) && user_access('view uploaded files')) {
+      foreach ($node->upload['und'] as $file) {
+      $tagged .= "%> " . file_create_url($file['uri']) . "\r\n"; // insert file here.
+    }
+  }
+  $tagged .= "\r\n";
+  return $tagged;
+}
+
+function _biblio_tagged_format_entry($key, $value) {
+  $reverse = TRUE;
+  $tag = _biblio_tagged_field_map($key, $reverse);
+  if (!empty($tag)) {
+    return "$tag " . trim($value) . "\r\n";
+  }
+
+}
+
+function _biblio_tagged_type_map($type, $reverse = FALSE) {
+  static $map = array();
+
+  if (empty($map)) {
+    $map = biblio_get_map('type_map', 'tagged');
+  }
+
+  if ($reverse) {
+    return ($tag = array_search($type, $map)) ? $tag : 'Generic'; //return the biblio type or 129 (Misc) if type not found
+  }
+  return (isset($map[$type]))?$map[$type]:129; //return the biblio type or 129 (Misc) if type not found
+}
+
+function _biblio_tagged_field_map($field, $reverse = FALSE) {
+  static $fmap = array();
+
+  if (empty($fmap)) {
+    $fmap =  biblio_get_map('field_map', 'tagged' );
+  }
+
+  if ($reverse) {
+    return ($tag = array_search($field, $fmap)) ? $tag : '';
+  }
+  return (!empty($fmap[$field])) ? $fmap[$field] : '';
+
+}
+
+function biblio_tagged_tagged_map_reset($type = NULL) {
+  module_load_include('install', 'biblio_tagged', 'biblio_tagged');
+ _reset_tagged_map($type);
+}
+
+function biblio_tagged_check_md5($md5) {
+  static $tagged_md5s = array();
+  if (empty($tagged_md5s)) {
+    $result = db_query("SELECT * FROM {biblio_tagged} ");
+    foreach ($result as $row ) {
+      $tagged_md5s[$row->biblio_tagged_md5] = $row->nid;
+    }
+  }
+  if (isset($tagged_md5s[$md5])) {
+    return $tagged_md5s[$md5];
+  }
+  else {
+    $tagged_md5s[$md5] = TRUE; // gaurd against duplicates in the same import
+    return;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/endnote/biblio_xml.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Biblio - EndNote XML
+description = Provides EndNote XML file import and export to the Biblio module.
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = endnote_xml_parser.inc
+files[] = views/biblio_handler_field_export_link_xml.inc
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/endnote/biblio_xml.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,390 @@
+<?php
+/**
+ * @file
+ * Database table creation for biblio_xml module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function biblio_xml_install() {
+  _save_xml_maps();
+}
+
+function biblio_xml_uninstall() {
+  if (db_table_exists('biblio_type_maps')) {
+
+    db_delete('biblio_type_maps')
+      ->condition('format', 'endnote8')
+      ->execute();
+
+    db_delete('biblio_type_maps')
+      ->condition('format', 'endnote7')
+      ->execute();
+  }
+}
+
+function biblio_xml_enable() {
+  biblio_xml_set_system_weight();
+}
+
+function biblio_xml_set_system_weight() {
+  db_update('system')
+    ->fields(array('weight' => 26))
+    ->condition('name', 'biblio_xml')
+    ->execute();
+}
+
+function _save_xml_maps() {
+  _save_endnote7_maps();
+  _save_endnote8_maps();
+}
+function _save_endnote7_maps() {
+  $format = 'endnote7';
+  $typemap = _get_endnote7_type_map();
+  $typenames = _get_endnote7_type_names();
+  $fieldmap = _get_endnote7_field_map();
+  $maps = array_merge($typemap, $typenames, $fieldmap);
+  biblio_save_map($maps);
+}
+
+function _save_endnote8_maps() {
+  $typemap = _get_endnote8_type_map();
+  $typenames = _get_endnote8_type_names();
+  $fieldmap = _get_endnote8_field_map();
+  $maps = array_merge($typemap, $typenames, $fieldmap);
+  biblio_save_map($maps);
+}
+
+function _reset_endnote_xml_map($version, $type) {
+  $count = db_query("SELECT COUNT(*) FROM {biblio_type_maps} WHERE format=:format", array(':format' => $version))->fetchField();
+  if ($count && $type) { //update
+    $function = '_get_' . $version . '_' . $type;
+    if (!function_exists($function)) return;
+    $map = $function();
+    drupal_write_record('biblio_type_maps', $map, 'format');
+    db_update('biblio_type_maps')
+      ->fields($map)
+      ->condition('format', $version)
+      ->execute();
+  }
+  else { // install
+    db_delete('biblio_type_maps')
+      ->condition('format', $version)
+      ->execute();
+    $save_maps = '_save_' . $version . '_maps';
+    $save_maps();
+  }
+}
+
+function _get_endnote8_type_map() {
+  $map['type_map'] = serialize(
+        array(
+                2 => 112, // artwork
+                3 => 114, // Audio Visual
+                4 => 117, // bill
+                5 => 101, // Book Section
+                6 => 100, // Book
+                7 => 116, // case
+                9 => 113, // software
+                17 => 102, // Journal Article
+                10 => 104, // Conference Proceeding
+                12 => 107, // web page
+                13 => 129, // Generic
+                14 => 115, // hearing
+                19 => 106, // magazine_article
+                20 => 122, // map
+                21 => 110, // film
+                21 => 111, // broadcast
+                23 => 105, // newspaper_article
+                25 => 119, // patent
+                26 => 120, // personal communication
+                27 => 109, // Report
+                28 => 129, // Edited Book
+                31 => 118, // statute
+                32 => 108, // Thesis
+                34 => 124, // unpublished
+                36 => 121, // manuscript
+                37 => 129, // figure
+                38 => 123, // chart
+                39 => 129, // equation
+                43 => 129, // electronic article
+                44 => 129, // electronic book
+                45 => 125, // online database
+                46 => 126, // government_document
+                47 => 103, // conference_paper
+                48 => 129, // online multimedia
+                49 => 127, // Classical Work
+                50 => 128, // legal_ruling
+                52 => 129, // Dictionary
+                53 => 129, // Encyclopedia
+                54 => 129, // Grant
+        )
+  );
+  $map['format'] = 'endnote8';
+  return $map;
+}
+
+function _get_endnote8_type_names() {
+  $map['type_names'] =  serialize(
+        array(
+                2 => 'Artwork',
+                3 => 'Audio Visual',
+                4 => 'Bill',
+                5 => 'Book Section',
+                6 => 'Book',
+                7 => 'Case',
+                9 => 'Software',
+                17 => 'Journal Article',
+                10 => 'Conference Proceeding',
+                12 => 'Web page',
+                13 => 'Generic',
+                14 => 'Hearing',
+                19 => 'Magazine Article',
+                20 => 'Map',
+                21 => 'Film',
+                21 => 'Broadcast',
+                23 => 'Newspaper Article',
+                25 => 'Patent',
+                26 => 'Personal Communication',
+                27 => 'Report',
+                28 => 'Edited Book',
+                31 => 'Statute',
+                32 => 'Thesis',
+                34 => 'Unpublished',
+                36 => 'Manuscript',
+                37 => 'Figure',
+                38 => 'Chart',
+                39 => 'Equation',
+                43 => 'Electronic Article',
+                44 => 'Electronic Book',
+                45 => 'Online Database',
+                46 => 'Government Document',
+                47 => 'Conference Paper',
+                48 => 'Online Multimedia',
+                49 => 'Classical Work',
+                50 => 'Legal Ruling',
+                52 => 'Dictionary',
+                53 => 'Encyclopedia',
+                54 => 'Grant',
+        )
+  );
+  $map['format'] = 'endnote8';
+  return $map;
+}
+
+function _get_endnote8_field_map() {
+
+  $map['field_map'] =  serialize(
+        array(
+                 'source-app'               => '',
+                 'rec-number'               => '',
+                 'ref-type'                 => 'biblio_type',
+                 'auth-address'             => 'biblio_auth_address',
+                 'auth-affiliaton'          => '',
+                 'secondary-title'          => 'biblio_secondary_title',
+                 'tertiary-title'           => 'biblio_tertiary_title',
+                 'alt-title'                => 'biblio_alternate_title',
+                 'short-title'              => 'biblio_short_title',
+                 'translated-title'         => 'biblio_translated_title',
+                 'full-title'               => 'biblio_secondary_title',
+                 'abbr-1'                   => 'biblio_short_title',
+                 'abbr-2'                   => '',
+                 'abbr-3'                   => '',
+                 'pages'                    => 'biblio_pages',
+                 'volume'                   => 'biblio_volume',
+                 'number'                   => 'biblio_number',
+                 'issue'                    => 'biblio_issue',
+                 'secondary-volume'         => '',
+                 'secondary-issue'          => '',
+                 'num-vols'                 => 'biblio_number_of_volumes',
+                 'edition'                  => 'biblio_edition',
+                 'section'                  => 'biblio_section',
+                 'reprint-edition'          => 'biblio_reprint_edition',
+                 'reprint-status'           => '',
+                 'year'                     => 'biblio_year',
+                 'pub-dates'                => 'biblio_date',
+                 'copyright-dates'          => '',
+                 'pub-location'             => 'biblio_place_published',
+                 'publisher'                => 'biblio_publisher',
+                 'orig-pub'                 => 'biblio_original_publication',
+                 'isbn'                     => 'biblio_isbn',
+                 'accession-num'            => 'biblio_accession_number',
+                 'call-num'                 => 'biblio_call_number',
+                 'report-id'                => '',
+                 'coden'                    => '',
+                 'electronic-resource-num'  => '',
+                 'abstract'                 => 'biblio_abst_e',
+                 'label'                    => 'biblio_label',
+                 'image'                    => '',
+                 'caption'                  => '',
+                 'notes'                    => 'biblio_notes',
+                 'research-notes'           => 'biblio_research_notes',
+                 'work-type'                => 'biblio_type_of_work',
+                 'reviewed-item'            => '',
+                 'availability'             => '',
+                 'remote-source'            => '',
+                 'meeting-place'            => '',
+                 'work-location'            => '',
+                 'work-extent'              => '',
+                 'pack-method'              => '',
+                 'size'                     => '',
+                 'repro-ratio'              => '',
+                 'remote-database-name'     => 'biblio_remote_db_name',
+                 'remote-database-provider' => 'biblio_remote_db_provider',
+                 'language'                 => 'biblio_lang',
+                 'web-urls'                 => '',
+                 'pdf-urls'                 => '',
+                 'text-urls'                => '',
+                 'image-urls'               => '',
+                 'related-urls'             => 'biblio_url',
+                 'access-date'              => 'biblio_access_date',
+                 'modified-date'            => '',
+                 'custom1'                  => 'biblio_custom1',
+                 'custom2'                  => 'biblio_custom2',
+                 'custom3'                  => 'biblio_custom3',
+                 'custom4'                  => 'biblio_custom4',
+                 'custom5'                  => 'biblio_custom5',
+                 'custom6'                  => 'biblio_custom6',
+                 'custom7'                  => 'biblio_custom7',
+                 'misc1'                    => '',
+                 'misc2'                    => '',
+                 'misc3'                    => '',
+        )
+  );
+
+  $map['format'] = 'endnote8';
+  return $map;
+}
+function _get_endnote7_type_map() {
+
+  $map['type_map'] = serialize(
+        array(
+                0 => 102, // Journal Article
+                1 => 100, // Book
+                2 => 108, // Thesis
+                3 => 103, // Conference Proceedings
+                4 => 120, // Personal Communication
+                5 => 105, // NewsPaper Article
+                6 => 113, // Computer Program
+                7 => 101, // Book Section
+                8 => 106, // Magazine Article
+                9 => 100, // Edited Book
+                10 => 109, // Report
+                11 => 122, // Map
+                12 => 114, // Audiovisual Material
+                13 => 112, // Artwork
+                15 => 119, // Patent
+                16 => 107, // Electronic Source
+                17 => 117, // Bill
+                18 => 116, // Case
+                19 => 115, // Hearing
+                20 => 121, // Manuscript
+                21 => 110, // Film or Broadcast
+                22 => 118, // Statute
+                26 => 123, // Chart or Table
+                31 => 129 // Generic
+        )
+  );
+  $map['format'] = 'endnote7';
+  return $map;
+}
+function _get_endnote7_type_names() {
+
+  $map['type_names'] =  serialize(
+        array(
+                0 => 'Journal Article',
+                1 => 'Book',
+                2 => 'Thesis',
+                3 => 'Conference Proceedings',
+                4 => 'Personal Communication',
+                5 => 'NewsPaper Article',
+                6 => 'Computer Program',
+                7 => 'Book Section',
+                8 => 'Magazine Article',
+                9 => 'Edited Book',
+                10 => 'Report',
+                11 => 'Map',
+                12 => 'Audiovisual Material',
+                13 => 'Artwork',
+                15 => 'Patent',
+                16 => 'Electronic Source',
+                17 => 'Bill',
+                18 => 'Case',
+                19 => 'Hearing',
+                20 => 'Manuscript',
+                21 => 'Film or Broadcast',
+                22 => 'Statute',
+                26 => 'Chart or Table',
+                31 => 'Generic',
+        )
+  );
+  $map['format'] = 'endnote7';
+  return $map;
+}
+
+function _get_endnote7_field_map() {
+
+  $map['field_map'] =  serialize(
+        array(
+                'REFERENCE_TYPE'    => 'biblio_type',
+                'REFNUM'            => '',
+                'YEAR'              => 'biblio_year',
+                'SECONDARY_TITLE'   => 'biblio_secondary_title',
+                'PLACE_PUBLISHED'   => 'biblio_place_published',
+                'PUBLISHER'         => 'biblio_publisher',
+                'VOLUME'            => 'biblio_volume',
+                'ISSUE'             => 'biblio_issue',
+                'NUMBER_OF_VOLUMES' => 'biblio_number_of_volumes',
+                'NUMBER'            => 'biblio_number',
+                'PAGES'             => 'biblio_pages',
+                'SECTION'           => 'biblio_section',
+                'TERTIARY_TITLE'    => 'biblio_tertiary_title',
+                'EDITION'           => 'biblio_edition',
+                'DATE'              => 'biblio_date',
+                'TYPE_OF_WORK'      => 'biblio_type_of_work',
+                'SHORT_TITLE'       => 'biblio_short_title',
+                'ALTERNATE_TITLE'   => 'biblio_alternate_title',
+                'ISBN'              => 'biblio_isbn',
+                'ORIGINAL_PUB'      => 'biblio_original_publication',
+                'REPRINT_EDITION'   => 'biblio_reprint_edition',
+                'REVIEWED_ITEM'     => '',
+                'CUSTOM1'           => 'biblio_custom1',
+                'CUSTOM2'           => 'biblio_custom2',
+                'CUSTOM3'           => 'biblio_custom3',
+                'CUSTOM4'           => 'biblio_custom4',
+                'CUSTOM5'           => 'biblio_custom5',
+                'CUSTOM6'           => 'biblio_custom6',
+                'ACCESSION_NUMBER'  => 'biblio_accession_number',
+                'CALL_NUMBER'       => 'biblio_call_number',
+                'LABEL'             => 'biblio_label',
+                'KEYWORD'           => 'biblio_keywords',
+                'ABSTRACT'          => 'biblio_abst_e',
+                'NOTES'             => 'biblio_notes',
+                'URL'               => 'biblio_url',
+                'AUTHOR_ADDRESS'    => '',
+                'IMAGE'             => '',
+                'CAPTION'           => '',
+        )
+  );
+
+  $map['format'] = 'endnote7';
+  return $map;
+}
+/**
+ * Implementation of hook_schema().
+ *
+ * Note:  Pro Drupal Development models use of t() to translate 'description'
+ * for field definitions, but Drupal core does not use them.  We follow core.
+ */
+function biblio_xml_schema() {
+  $schema = array();
+  $schema['biblio_xml'] = array(
+    'fields' => array(
+      'nid'       => array('type' => 'int', 'not null' => TRUE),
+      'biblio_xml_md5' => array('type' => 'char', 'length' => 32, 'not null' => TRUE),
+      ),
+  'primary key' => array('nid'),
+  );
+  return $schema;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/endnote/biblio_xml.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,139 @@
+<?php
+/*
+ * @file biblio_xml.module
+ *
+ */
+function biblio_xml_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'biblio_xml') . '/views',
+  );
+}
+
+ /*
+ *   add the xml option to the option list of the biblio_import_form
+ *   the key is the module name use by module_invoke to call hook_biblio_import
+ *   module_invoke('biblio_xml', 'biblio_import',...)
+ */
+function biblio_xml_biblio_import_options() {
+  return array('biblio_xml' => t('EndNote XML'));
+}
+function biblio_xml_biblio_mapper_options() {
+  return array(
+    'endnote7' => array(
+      'title' => t('EndNote 7 XML'),
+      'export' => TRUE,
+      ),
+    'endnote8' => array(
+      'title' => t('EndNote X3 XML'),
+      'export' => TRUE,
+      ),
+  );
+}
+
+function biblio_xml_biblio_export_options() {
+  return array('xml'  => t('EndNote XML'));
+}
+
+function biblio_xml_node_view($node, $view_mode) {
+  if ($node->type == 'biblio') {
+    switch ($view_mode) {
+      case 'full':
+      case 'teaser':
+        $links = biblio_xml_biblio_export_link($node->nid);
+        $node->content['links']['biblio_xml'] = array(
+          '#links' => $links,
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
+    }
+  }
+}
+
+/**
+ * Creates a link to export a node (or view) in xml format
+ *
+ * @param $base this is the base url (defaults to /biblio)
+ * @param $nid  the node id, if NULL then the current view is exported
+ * @return  a link (<a href=...>xml</a>)
+ */
+function biblio_xml_biblio_export_link($nid = NULL, $filter = array()) {
+  $show_link = variable_get('biblio_export_links', array('xml' => TRUE));
+  if (!isset($show_link['xml']) || empty($show_link['xml']) || !biblio_access('export')) {
+    return array();
+  }
+  $base = variable_get('biblio_base', 'biblio');
+
+  $link = array();
+  $link['attributes']['title'] = t("Click to download the EndNote XML formatted file");
+  $link['attributes'] += array('rel' => 'nofollow');
+
+  $link['href']  = "$base/export/xml";
+  if (!empty($nid)) {
+    $link['href'] .= '/' . $nid;
+  }
+  $link['title'] = t('XML');
+
+  if (empty($nid) && !empty($filter)) { // add any filters which may be on the current page
+    $link['query'] = $filter;
+  }
+  return array('biblio_xml' => $link);
+}
+
+function biblio_xml_node_delete($node) {
+  if ($node->type != 'biblio') {
+    return;
+  }
+  db_delete('biblio_xml')
+    ->condition('nid', $node->nid)
+    ->execute();
+}
+
+function biblio_xml_node_insert($node) {
+  if ($node->type != 'biblio' || !isset($node->biblio_xml_md5)) {
+    return;
+  }
+    drupal_write_record('biblio_xml', $node);
+}
+
+function biblio_xml_biblio_import($file, $terms = array(), $batch = FALSE, $session_id = NULL, $save = TRUE, $string = FALSE) {
+  module_load_include('inc', 'biblio_xml', 'endnote_xml_parser');
+
+  $nids = array();
+  $dups = array();
+
+  $parser = new EndNoteXMLParser;
+
+  list($nids, $dups) = $parser->parse($file, $terms, $batch, $session_id);
+
+  return array($nids, $dups);
+}
+
+function biblio_xml_biblio_export($nids) {
+  module_load_include('inc', 'biblio_xml', 'endnote8_export');
+  drupal_add_http_header('Content-type', 'application/xml; charset=utf-8');
+  drupal_add_http_header('Content-Disposition', 'attachment; filename="Biblio-EndNote.xml"');
+
+  print _endnote8_XML_export('', 'begin');
+  $nodes = node_load_multiple($nids, array(), TRUE);
+  foreach ($nodes as $node) {
+  //  $node = node_load($nid, FALSE, TRUE);
+    if (variable_get('biblio_hide_bibtex_braces', 0) ) {
+      $node->title = biblio_remove_brace($node->title);
+    }
+    print _endnote8_XML_export($node);
+  }
+
+  print _endnote8_XML_export('', 'end');
+}
+
+function biblio_xml_endnote8_map_reset($type = NULL) {
+  module_load_include('install', 'biblio_xml', 'biblio_xml');
+  _reset_endnote_xml_map('endnote8', $type);
+}
+
+function biblio_xml_endnote7_map_reset($type = NULL) {
+  module_load_include('install', 'biblio_xml', 'biblio_xml');
+  _reset_endnote_xml_map('endnote7', $type);
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/endnote/endnote8_export.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,201 @@
+<?php
+function _endnote8_XML_export($node, $part = 'record') {
+  $style_attr = 'face="normal" font="default" size="100%"';
+  switch ($part) {
+    case 'begin':
+      $xml = '<?xml version="1.0" encoding="UTF-8"?>';
+      $xml .= "<xml><records>";
+      break;
+    case 'record':
+      $xml = "<record>";
+      $xml .= '<source-app name="Biblio" version="7.x">Drupal-Biblio</source-app>';
+      $xml .= "<ref-type>" . _endnote8_type_map($node->biblio_type) . "</ref-type>";
+      unset($node->biblio_type);
+      //<!-- Author information -->
+      $xml .= en8_add_contributors($node);
+      $xml .= en8_add_titles($node);
+      $xml .= en8_add_keywords($node);
+      $xml .= en8_add_dates($node);
+      $xml .= en8_add_urls($node);
+
+      foreach ($node as $key => $value) {
+        $entag = en8_field_map($key);
+        if (!empty($entag) && !empty($value)) {
+          $xml .=  "<" . $entag . '><style face="normal" font="default" size="100%">' . htmlspecialchars($value) . "</style></$entag>";
+        }
+      }
+      $xml .= "</record>";
+      break;
+    case 'end':
+      $xml = '</records></xml>';
+      break;
+  }
+    return $xml;
+}
+
+function en8_encode_font_faces(&$node) {
+  $search = array('<b>', '<i>', '<u>', '<sup>', '<sub>', '</b>', '</i>', '</u>', '</sup>', '</sub>');
+  $replace = array(
+    '<style face="bold" font="default" size="100%">',
+    '<style face="italic" font="default" size="100%">',
+    '<style face="underline" font="default" size="100%">',
+    '<style face="superscript" font="default" size="100%">',
+    '<style face="subscript" font="default" size="100%">',
+    '</sytle>',
+    '</sytle>',
+    '</sytle>',
+    '</sytle>',
+    '</sytle>',
+  );
+  foreach ($node as $key => $value) {
+    $node->$key = str_ireplace($search, $replace, $value);
+  }
+}
+
+function en8_add_titles(&$node) {
+  $xml = '<titles>';
+  $xml .= (!empty ($node->title)) ? '<title><style face="normal" font="default" size="100%">' . htmlspecialchars($node->title) . "</style></title>" :'';
+  $xml .= (!empty ($node->biblio_secondary_title)) ? '<secondary-title><style face="normal" font="default" size="100%">' . htmlspecialchars($node->biblio_secondary_title) . "</style></secondary-title>" :'';
+  $xml .= (!empty ($node->biblio_tertiary_title)) ? '<tertiary-title><style face="normal" font="default" size="100%">' . htmlspecialchars($node->biblio_tertiary_title) . "</style></tertiary-title>" :'';
+  $xml .= (!empty ($node->biblio_alternate_title)) ? '<alt-title><style face="normal" font="default" size="100%">' . htmlspecialchars($node->biblio_alternate_title) . "</style></alt-title>" :'';
+  $xml .= (!empty ($node->biblio_short_title)) ? '<short-title><style face="normal" font="default" size="100%">' . htmlspecialchars($node->biblio_short_title) . "</style></short-title>" :'';
+  $xml .= (!empty ($node->biblio_translated_title)) ? '<translated-title><style face="normal" font="default" size="100%">' . htmlspecialchars($node->biblio_translated_title) . "</style></translated-title>" :'';
+  $xml .= '</titles>';
+  unset($node->title);
+  unset($node->biblio_secondary_title);
+  unset($node->biblio_tertiary_title);
+  unset($node->biblio_alternate_title);
+  unset($node->biblio_short_title);
+  unset($node->biblio_translated_title);
+
+  return $xml;
+}
+function en8_add_urls(&$node) {
+  global $base_path;
+  $xml = '';
+  // TODO: fix URLS
+  if (!empty($node->biblio_url)) {
+    $xml .= "<web-urls>";
+    $xml .= '<url><style face="normal" font="default" size="100%">' . htmlspecialchars($node->biblio_url) . "</style></url>";
+    $xml .= "</web-urls>";
+  }
+  unset($node->biblio_url);
+  if (!empty ($node->upload) && count($node->upload['und'])  && user_access('view uploaded files')) {
+      $xml .= "<related-urls>";
+    foreach ($node->upload['und'] as $file) {
+      $xml .= '<url><style face="normal" font="default" size="100%">';
+      $xml .= htmlspecialchars(file_create_url($file['uri']));
+      $xml .= "</style></url>";
+    }
+    $xml .= "</related-urls>";
+  }
+  unset($node->upload['und']);
+  if (!empty($xml)) return "<urls>$xml</urls>";
+  return ;
+}
+
+function en8_add_dates(&$node) {
+  $xml = '';
+  if (!empty($node->biblio_year) || !empty($node->biblio_date) ) {
+    $xml .= '<dates>';
+    $xml .=  (!empty($node->biblio_year)) ? '<year><style  face="normal" font="default" size="100%">' . htmlspecialchars($node->biblio_year) . "</style></year>":'';
+    $xml .=  (!empty($node->biblio_date)) ? '<pub-dates><date><style  face="normal" font="default" size="100%">' . htmlspecialchars($node->biblio_date) . "</style></date></pub-dates>":'';
+    $xml .= "</dates>";
+  }
+  unset($node->biblio_year);
+  unset($node->biblio_date);
+  return $xml;
+}
+
+function en8_add_keywords(&$node) {
+  $kw_array = array();
+  $xml = '';
+  if (!empty($node->biblio_keywords)) {
+    foreach ($node->biblio_keywords as $term) {
+      $kw_array[] = trim($term);
+    }
+  }
+  if (!empty($kw_array)) {
+    $kw_array = array_unique($kw_array);
+    $xml .= '<keywords>';
+    foreach ($kw_array as $word) {
+      $xml .= '<keyword><style  face="normal" font="default" size="100%">' . htmlspecialchars(trim($word)) . "</style></keyword>";
+    }
+    $xml .= "</keywords>";
+  }
+  unset($node->biblio_keywords);
+  return $xml;
+}
+
+function en8_add_contributors(&$node) {
+  $xml = '<contributors>';
+  $authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  if (!empty($authors)) {
+    $xml .= "<authors>";
+    foreach ($authors as $auth) {
+      $xml .= '<author><style face="normal" font="default" size="100%">';
+      $xml .= htmlspecialchars(trim($auth['name'])); // insert author here.
+      $xml .= "</style></author>";
+    }
+    $xml .= "</authors>";
+  }
+  $authors = biblio_get_contributor_category($node->biblio_contributors, 2);
+  if (!empty($authors)) {
+    $xml .= "<secondary-authors>";
+    foreach ($authors as $auth) {
+      $xml .= '<author><style face="normal" font="default" size="100%">';
+      $xml .= htmlspecialchars(trim($auth['name'])); // insert author here.
+      $xml .= "</style></author>";
+    }
+    $xml .= "</secondary-authors>";
+  }
+  $authors = biblio_get_contributor_category($node->biblio_contributors, 3);
+  if (!empty($authors)) {
+    $xml .= "<tertiary-authors>";
+    foreach ($authors as $auth) {
+      $xml .= '<author><style face="normal" font="default" size="100%">';
+      $xml .= htmlspecialchars(trim($auth['name'])); // insert author here.
+      $xml .= "</style></author>";
+    }
+    $xml .= "</tertiary-authors>";
+  }
+  $authors = biblio_get_contributor_category($node->biblio_contributors, 4);
+  if (!empty($authors)) {
+    $xml .= "<subsidiary-authors>";
+    foreach ($authors as $auth) {
+      $xml .= '<author><style face="normal" font="default" size="100%">';
+      $xml .= htmlspecialchars(trim($auth['name'])); // insert author here.
+      $xml .= "</style></author>";
+    }
+    $xml .= "</subsidiary-authors>";
+  }
+  $authors = biblio_get_contributor_category($node->biblio_contributors, 5);
+  if (!empty($authors)) {
+    $xml .= "<translated-authors>";
+    foreach ($authors as $auth) {
+      $xml .= '<author><style face="normal" font="default" size="100%">';
+      $xml .= htmlspecialchars(trim($auth['name'])); // insert author here.
+      $xml .= "</style></author>";
+    }
+    $xml .= "</translated-authors>";
+  }
+  $xml .= '</contributors>';
+  unset($node->biblio_contributors);
+  return $xml;
+}
+
+function en8_field_map($biblio_field) {
+  static $fmap = array();
+  if (empty($fmap)) {
+    $fmap = biblio_get_map('field_map', 'endnote8');
+  }
+  return ($en8_field = array_search($biblio_field, $fmap)) ? $en8_field : '';
+}
+
+function _endnote8_type_map($bibliotype) {
+  static $map = array();
+  if (empty($map)) {
+    $map = biblio_get_map('type_map', 'endnote8');
+  }
+  return ($en8_type = array_search($bibliotype, $map)) ? $en8_type : 13; //return the biblio type or 129 (Misc) if type not found
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/endnote/endnote_xml_parser.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,456 @@
+<?php
+/*
+ * @file endnote_xml_parser.inc
+ *
+ */
+class EndNoteXMLParser {
+  private $parser;
+  private $format;
+  private $node;
+  private $keyword_count;
+  private $contributors;
+  private $contributor_type;
+  private $contrib_count;
+  private $titles;
+  private $periodical;
+  private $dates;
+  private $urls;
+  private $font_attr;
+  private $session_id;
+  private $batch_proc;
+  private $terms;
+  private $nids;
+  private $dups;
+  private $unmapped;
+
+  function parse($file, $terms, $batch, $session_id) {
+    $this->terms = $terms;
+    $this->batch_proc = $batch;
+    $this->session_id = $session_id;
+    $this->nids = array();
+    $this->dups = array();
+    $this->unmapped = array();
+
+    if (!($fp = fopen($file->uri, "r"))) {
+      drupal_set_message(t("could not open XML input"), 'error');
+      return;
+    }
+    $data = fread($fp, 2048);
+    if ((strpos($data, 'record') !== FALSE) && (strpos($data, 'ref-type') !== FALSE)) {
+      $this->format = 'endnote8';
+    }
+    elseif (strpos($data, 'RECORD') !== FALSE && strpos($data, 'REFERENCE_TYPE') !== FALSE) {
+      $this->format = 'endnote7';
+    }
+    if ($this->format) {
+      $this->parser = drupal_xml_parser_create($data);
+      xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, FALSE);
+      xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, TRUE);
+      xml_set_object($this->parser, $this);
+      xml_set_element_handler($this->parser, $this->format . '_startElement', $this->format . '_endElement');
+      xml_set_character_data_handler($this->parser, $this->format . '_characterData');
+
+      xml_parse($this->parser, $data, feof($fp));
+
+      while ($data = fread($fp, 2048)) {
+        // $data = fread($fp, 2048);
+        set_time_limit(300);
+        if (!xml_parse($this->parser, $data, feof($fp))) {
+          drupal_set_message(sprintf("XML error: %s at line %d",
+          xml_error_string(xml_get_error_code($this->parser)),
+          xml_get_current_line_number($this->parser)), 'error');
+        }
+      }
+      xml_parser_free($this->parser);
+    }
+
+    fclose($fp);
+
+    if (!empty($this->unmapped)) {
+      $ignored_tags = array_unique($this->unmapped);
+      $message = t("The following elements were ignored because they do not map to any biblio fields:") . ' ';
+      $message .= implode(', ', $ignored_tags);
+      if (user_access('administer biblio')) {
+        $message .= '. ' . t('Click !url if you wish to check the field mapping', array('!url' => l(t('here'), 'admin/config/content/biblio/iomap/edit/' . $this->format)));
+      }
+      drupal_set_message($message, 'warning');
+    }
+    return array($this->nids, $this->dups);
+
+  }
+
+  function endnote8_startElement($parser, $name, $attrs) {
+    switch ($name) {
+      case 'record' :
+        $this->node = new stdClass();
+        $this->node->biblio_contributors = array();
+        break;
+      case 'style' :
+        $this->font_attr = explode(' ', $attrs['face']);
+        foreach ($this->font_attr as $fatt) {
+          switch ($fatt) {
+            case 'normal':
+              break;
+            case 'bold':
+              $this->endnote8_characterData(NULL, '<b>');
+              break;
+            case 'italic':
+              $this->endnote8_characterData(NULL, '<i>');
+              break;
+            case 'underline':
+              $this->endnote8_characterData(NULL, '<u>');
+              break;
+            case 'superscript':
+              $this->endnote8_characterData(NULL, '<sup>');
+              break;
+            case 'subscript':
+              $this->endnote8_characterData(NULL, '<sub>');
+              break;
+          }
+        }
+        break;
+      case 'keywords' :
+        $this->keyword_count = 0;
+        break;
+      case 'authors' :
+      case 'secondary-authors' :
+      case 'tertiary-authors' :
+      case 'subsidiary-authors' :
+      case 'translated-authors' :
+        $this->contributors_type = $name;
+        $this->contributors = array();
+        $this->contrib_count = 0;
+        break;
+      case 'author' :
+        $this->contributors[$this->contrib_count]['name'] = '';
+        $this->element = $name;
+        break;
+      case 'year' :
+      case 'pub-dates' :
+      case 'copyright-dates' :
+        $this->dates = $name;
+        break;
+      case 'web-urls' :
+      case 'pdf-urls' :
+      case 'text-urls' :
+      case 'related-urls' :
+      case 'image-urls' :
+        $this->urls = $name;
+        break;
+      case 'keyword':
+        $this->node->biblio_keywords[$this->keyword_count] = '';
+        $this->element = $name;
+        break;
+
+      default :
+        $this->element = $name;
+    }
+  }
+
+  function endnote8_endElement($parser, $name) {
+    //    global $this->node, $nids, $this->element, $terms, $batch_proc, $session_id, $this->contributors_type, $this->contrib_count, $this->dates, $this->urls, $this->keyword_count, $this->font_attr;
+    switch ($name) {
+      case 'record' :
+        $this->element = $this->contributors_type = $this->contrib_count = $this->dates = $this->urls = '';
+        $this->node->biblio_xml_md5 = md5(serialize($this->node));
+        if ( !($dup = $this->biblio_xml_check_md5($this->node->biblio_xml_md5)) ) {
+          biblio_save_node($this->node, $this->terms, $this->batch_proc, $this->session_id);
+          if (!empty($this->node->nid)) $this->nids[] = $this->node->nid;
+        }
+        else {
+          $this->dups[] = $dup;
+        }
+        break;
+      case 'authors' :
+      case 'secondary-authors' :
+      case 'tertiary-authors' :
+      case 'subsidiary-authors' :
+      case 'translated-authors' :
+        $this->contributors_type = '';
+        foreach ($this->contributors as $contributor) {
+          $this->node->biblio_contributors[] = $contributor;
+        }
+        break;
+      case 'author' :
+        switch ($this->contributors_type) {
+          case 'authors' :
+            $this->contributors[$this->contrib_count]['auth_category'] = 1;
+            $this->contributors[$this->contrib_count]['auth_type'] =  1;
+            break;
+          case 'secondary-authors' :
+            $this->contributors[$this->contrib_count]['auth_category'] = 2;
+            $this->contributors[$this->contrib_count]['auth_type'] = 2;
+            break;
+          case 'tertiary-authors' :
+            $this->contributors[$this->contrib_count]['auth_category'] = 3;
+            $this->contributors[$this->contrib_count]['auth_type'] = 3;
+            break;
+          case 'subsidiary-authors' :
+            $this->contributors[$this->contrib_count]['auth_category'] = 4;
+            $this->contributors[$this->contrib_count]['auth_type'] = 4;
+            break;
+          case 'translated-authors' :
+            $this->contributors[$this->contrib_count]['auth_category'] = 5;
+            $this->contributors[$this->contrib_count]['auth_type'] = 5;
+            break;
+        }
+        $this->contrib_count++;
+        break;
+      case 'keyword' :
+        $this->keyword_count++;
+        break;
+      case 'year' :
+      case 'pub-dates' :
+      case 'copyright-dates' :
+        $this->dates = '';
+        break;
+      case 'web-urls' :
+      case 'pdf-urls' :
+      case 'text-urls' :
+      case 'related-urls' :
+      case 'image-urls' :
+        $this->urls = '';
+        break;
+      case 'ref-type':
+        $this->node->biblio_type = $this->type_map($this->node->biblio_type);
+        $this->element = '';
+        break;
+      case 'style' :
+        foreach ($this->font_attr as $fatt) {
+          switch ($fatt) {
+            case 'normal':
+              break;
+            case 'bold':
+              $this->endnote8_characterData(NULL, '</b>');
+              break;
+            case 'italic':
+              $this->endnote8_characterData(NULL, '</i>');
+              break;
+            case 'underline':
+              $this->endnote8_characterData(NULL, '</u>');
+              break;
+            case 'superscript':
+              $this->endnote8_characterData(NULL, '</sup>');
+              break;
+            case 'subscript':
+              $this->endnote8_characterData(NULL, '</sub>');
+              break;
+          }
+        }
+        $this->font_attr = array();
+        break;
+      default :
+        $this->element = '';
+    }
+
+
+  }
+
+  function endnote8_characterData($parser, $data) {
+    // first replace any carriage returns with html line breaks
+    $data = str_ireplace("\r", "<br/>", $data);
+    if (trim(htmlspecialchars_decode($data))) {
+      switch ($this->element) {
+        //Author information
+        case 'author' :
+          $this->contributors[$this->contrib_count]['name'] .= $data;
+          break;
+        case 'keyword' :
+          $this->node->biblio_keywords[$this->keyword_count] .= $data;
+          break;
+        case 'dates' :
+          switch ($this->dates) {
+            case 'year' :
+              $this->node->biblio_year .= $data;
+              break;
+          }
+          break;
+        case 'date' :
+          switch ($this->dates) {
+            case 'pub-dates' :
+              $this->node->biblio_date .= $data;
+              break;
+            case 'copyright-dates' :
+              break;
+          }
+          break;
+        case 'urls' :
+        case 'url' :
+          switch ($this->urls) {
+            case 'web-urls' :
+              $this->node->biblio_url .= $data;
+              break;
+            case 'pdf-urls' :
+            case 'text-urls' :
+            case 'image-urls' :
+              break;
+            case 'related-urls' :
+          }
+          break;
+        case 'title':
+          $this->node->title .= $data;
+          break;
+        default:
+          if ($field = $this->field_map(trim($this->element))) {
+            $this->node->$field .= $data;
+          }
+          else {
+            if (!in_array($this->element, $this->unmapped)) {
+              $this->unmapped[] = $this->element;
+            }
+          }
+      }
+    }
+  }
+
+  function endnote7_startElement($parser, $name, $attrs) {
+    switch ($name) {
+      case 'RECORD' :
+        $this->node = new stdClass();
+        $this->node->biblio_contributors = array();
+        $this->node->biblio_type = 102; // we set 102 here because the xml parser won't
+        // process a value of 0 (ZERO) which is the
+        // ref-type 102. if there is a non-zero value it will be overwritten
+        $this->element = '';
+        break;
+      case 'AUTHORS':
+      case 'SECONDARY_AUTHORS':
+      case 'TERTIARY_AUTHORS':
+      case 'SUBSIDIARY_AUTHORS':
+        $this->contrib_count = 0;
+        $this->contributors = array();
+        break;
+      case 'AUTHOR':
+      case 'SECONDARY_AUTHOR':
+      case 'TERTIARY_AUTHOR':
+      case 'SUBSIDIARY_AUTHOR':
+          $this->contributors[$this->contrib_count]['name'] = '';
+          $this->element = $name;
+        break;
+      case 'KEYWORDS':
+        $this->keyword_count = 0;
+        break;
+      case 'KEYWORD':
+        $this->node->biblio_keywords[$this->keyword_count] = '';
+        $this->element = $name;
+        break;
+      default:
+        $this->element = $name;
+    }
+  }
+
+  function endnote7_endElement($parser, $name) {
+    switch ($name) {
+      case 'RECORD' :
+        $this->node->biblio_xml_md5 = md5(serialize($this->node));
+        if ( !($dup = $this->biblio_xml_check_md5($this->node->biblio_xml_md5)) ) {
+          biblio_save_node($this->node, $this->terms, $this->batch_proc, $this->session_id);
+          if (!empty($this->node->nid)) $this->nids[] = $this->node->nid;
+        }
+        else {
+          $this->dups[] = $dup;
+        }
+        break;
+      case 'AUTHORS':
+      case 'SECONDARY_AUTHORS':
+      case 'TERTIARY_AUTHORS':
+      case 'SUBSIDIARY_AUTHORS':
+        $this->contributors_type = '';
+        foreach ($this->contributors as $contributor) {
+          $this->node->biblio_contributors[] = $contributor;
+        }
+        break;
+      case 'AUTHOR':
+        $this->contributors[$this->contrib_count]['auth_category'] = 1;
+        $this->contributors[$this->contrib_count]['auth_type'] = 1;
+        $this->contrib_count++;
+        break;
+      case 'SECONDARY_AUTHOR':
+        $this->contributors[$this->contrib_count]['auth_category'] = 2;
+        $this->contributors[$this->contrib_count]['auth_type'] = 2;
+        $this->contrib_count++;
+        break;
+      case 'TERTIARY_AUTHOR':
+        $this->contributors[$this->contrib_count]['auth_category'] = 3;
+        $this->contributors[$this->contrib_count]['auth_type'] = 3;
+        $this->contrib_count++;
+        break;
+      case 'SUBSIDIARY_AUTHOR':
+        $this->contributors[$this->contrib_count]['auth_category'] = 4;
+        $this->contributors[$this->contrib_count]['auth_type'] = 4;
+        $this->contrib_count++;
+        break;
+      case 'KEYWORD':
+        $this->keyword_count++;
+        break;
+      default:
+
+    }
+    $this->element = '';
+  }
+
+  function endnote7_characterData($parser, $data) {
+    if (trim($data)) {
+      switch ($this->element) {
+        case 'REFERENCE_TYPE':
+          $this->node->biblio_type = $this->type_map($data);
+          break;
+        case 'AUTHOR':
+        case 'SECONDARY_AUTHOR':
+        case 'TERTIARY_AUTHOR':
+        case 'SUBSIDIARY_AUTHOR':
+          $this->contributors[$this->contrib_count]['name'] .= $data;
+          break;
+        case 'KEYWORD':
+          $this->node->biblio_keywords[$this->keyword_count] .= $data;
+          break;
+        case 'TITLE':
+          $this->node->title .= $data;
+          break;
+        default:
+          if ($field = $this->field_map(trim($this->element))) {
+            $this->node->$field .= $data;
+          }
+          else {
+            if (!in_array($this->element, $this->unmapped)) {
+              $this->unmapped[] = $this->element;
+            }
+          }
+      }
+    }
+  }
+
+  function field_map($enfield) {
+    static $fmap = array();
+    if (empty($fmap)) {
+      $fmap = biblio_get_map('field_map', $this->format);
+    }
+    return (!empty($fmap[$enfield])) ? $fmap[$enfield] : '';
+  }
+
+  function type_map($entype) {
+    static $map = array();
+    if (empty($map)) {
+      $map = biblio_get_map('type_map', $this->format);
+    }
+    return (isset($map[$entype]))?$map[$entype]:129; //return the biblio type or 129 (Misc) if type not found
+  }
+
+  function biblio_xml_check_md5($md5) {
+    static $xml_md5s = array();
+    if (empty($xml_md5s)) {
+      $result = db_query("SELECT * FROM {biblio_xml} ");
+      foreach ($result as $row) {
+        $xml_md5s[$row->biblio_xml_md5] = $row->nid;
+      }
+    }
+    if (isset($xml_md5s[$md5])) {
+      return $xml_md5s[$md5];
+    }
+    else {
+      $xml_md5s[$md5] = TRUE; // gaurd against duplicates in the same import
+      return;
+    }
+  }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/marcParse/biblio_marc.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Biblio - MARC
+description = Provides MARC file import to the Biblio module.
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = php-marc.php
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/marcParse/biblio_marc.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,96 @@
+<?php
+/**
+ * @file
+ * Database table creation for biblio_marc module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function biblio_marc_install() {
+  _save_marc_maps();
+}
+
+function biblio_marc_uninstall() {
+  if (db_table_exists('biblio_type_maps')) {
+    db_delete('biblio_type_maps')
+      ->condition('format', 'marc')
+      ->execute();
+  }
+}
+
+function biblio_marc_enable() {
+  biblio_marc_set_system_weight();
+}
+
+function biblio_marc_set_system_weight() {
+  db_update('system')
+    ->fields(array('weight' => 24))
+    ->condition('name', 'biblio_marc')
+    ->execute();
+}
+
+function _save_marc_maps() {
+  $maps['type_map'] = serialize(
+        array(
+                'ab' => 102, // Journal Article
+                'as' => 102, // Journal Article
+                'am' => 100, // Book
+                2 => 108, // Thesis
+                3 => 103, // Conference Proceedings
+                4 => 120, // Personal Communication
+                5 => 105, // NewsPaper Article
+                6 => 113, // Computer Program
+                'aa' => 101, // Book Section
+                8 => 106, // Magazine Article
+                9 => 100, // Edited Book
+                10 => 109, // Report
+                'em' => 122, // Map
+                12 => 114, // Audiovisual Material
+                13 => 112, // Artwork
+                15 => 119, // Patent
+                16 => 107, // Electronic Source
+                17 => 117, // Bill
+                18 => 116, // Case
+                19 => 115, // Hearing
+                20 => 121, // Manuscript
+                21 => 110, // Film or Broadcast
+                22 => 118, // Statute
+                26 => 123, // Chart or Table
+                31 => 129 // Generic
+
+        )
+  );
+
+  $maps['type_names'] =  serialize(
+        array(
+        )
+  );
+
+  $maps['field_map'] =  serialize(
+        array(
+        )
+  );
+
+  $maps['format'] = 'marc';
+  biblio_save_map($maps);
+
+
+}
+/**
+ * Implementation of hook_schema().
+ *
+ * Note:  Pro Drupal Development models use of t() to translate 'description'
+ * for field definitions, but Drupal core does not use them.  We follow core.
+ */
+function biblio_marc_schema() {
+  $schema = array();
+  $schema['biblio_marc'] = array(
+    'fields' => array(
+      'nid'       => array('type' => 'int', 'not null' => TRUE),
+      'biblio_marc_md5' => array('type' => 'char', 'length' => 32, 'not null' => TRUE),
+      ),
+  'primary key' => array('nid'),
+  );
+  return $schema;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/marcParse/biblio_marc.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,376 @@
+<?php
+/*
+ * @file biblio_marc.module
+ *
+ */
+
+/*
+ *   add the marc option to the option list of the biblio_import_form
+ *   the key is the module name use by module_invoke to call hook_biblio_import
+ *   module_invoke('biblio_marc', 'biblio_import',...)
+ */
+function biblio_marc_biblio_import_options() {
+  return array('biblio_marc' => t('MARC'));
+}
+
+function biblio_marc_node_delete($node) {
+  if ($node->type != 'biblio') {
+    return;
+  }
+  db_delete('biblio_marc')
+    ->condition('nid', $node->nid)
+    ->execute();
+}
+
+function biblio_marc_node_insert($node) {
+  if ($node->type != 'biblio') {
+    return;
+  }
+  if (!isset($node->biblio_marc_md5)) {
+    return;
+  }
+  drupal_write_record('biblio_marc', $node);
+}
+
+function biblio_marc_biblio_import($file, $terms = array(), $batch = FALSE, $session_id = NULL, $save = TRUE, $string = FALSE) {
+  $nids = array();
+  $dups = array();
+  module_load_include('php', 'biblio_marc', 'php-marc');
+  $marcfile = new File($file->uri);
+  while ($record = $marcfile->next() ) {
+    $node = new stdClass();
+    $node->biblio_contributors = array();
+    $fields = $record->fields();
+    $leader = $record->leader();
+    $pubtype = $leader[6];
+    $pubtype .= $leader[7];
+    $node->biblio_type = _biblio_marc_type_map($pubtype);
+    foreach ($record->fields() as $fields) {
+      foreach ($fields as $field) {
+        $tagnum = $field->tagno;
+        switch ($tagnum) {
+          case '008':
+            $data = $field->data();
+            $node->biblio_year = substr($data, 7, 4);
+            $node->biblio_lang = substr($data, 35, 3);
+            break;
+          case '020':
+            $node->biblio_isbn = $field->subfield('a');
+            break;
+          case '022':
+            $node->biblio_issn = $field->subfield('a');
+            break;
+          case '024':
+            $node->biblio_other_number = $field->subfield('a');
+            break;
+          case '050': //LIBRARY OF CONGRESS CALL NUMBER
+          case '055': //CLASSIFICATION NUMBERS ASSIGNED IN CANADA
+          case '060': //NATIONAL LIBRARY OF MEDICINE CALL NUMBER
+            $node->biblio_call_number = $field->subfield('a');
+            break;
+          case '130':
+            $node->title = str_replace(' /', '', $field->subfield('a'));
+            break;
+          case '210':
+            $node->biblio_short_title = str_replace(' /', '', $field->subfield('a'));
+            break;
+          case '245':
+            $node->title = str_replace(' /', '', $field->subfield('a')) . ' ' . $field->subfield('b');
+            break;
+          case '250':
+            $node->biblio_edition = $field->subfield('a');
+            break;
+          case '260':
+            $node->biblio_place_published = str_replace(' :', '', $field->subfield('a'));
+            $node->biblio_publisher = $field->subfield('b');
+            $node->biblio_date = $field->subfield('c');
+            break;
+          case '300':
+            $node->biblio_pages = $field->subfield('a');
+            break;
+          case '490':
+            $node->biblio_volume = $field->subfield('v');
+            break;
+          case ($tagnum >= 500 && $tagnum <= 599):
+            $value = $field->subfield('a');
+            if (!empty($value)) {
+              $node->biblio_notes .= $value;
+            }
+            break;
+          case '650':
+            foreach ($field->subfields() as $subject) {
+              $node->biblio_keywords[] = $subject[0];
+            }
+            break;
+          case '100':
+          case '700':
+            $value = $field->subfield('a');
+            if (!empty($value)) {
+              $node->biblio_contributors[] = array(
+              'name' => $value,
+              'auth_category' => 1,
+              'auth_type' => 1
+              );
+            }
+            break;
+          case '110':
+          case '710':
+            $node->biblio_contributors[] = array(
+              'name' => $field->subfield('a'),
+              'auth_category' => 5,
+              'auth_type' => 5
+            );
+            break;
+          case '856':
+            $value = $field->subfield('u');
+            if (!empty($value)) {
+              $node->biblio_url = $value;
+            }
+            break;
+        }
+      }
+    }
+    if (!empty($node)) {
+      $node->biblio_marc_md5 = md5(serialize($node));
+
+      if (! ($dup = biblio_marc_check_md5($node->biblio_marc_md5))) {
+        biblio_save_node($node, $terms, $batch, $session_id);
+        if (!empty($node->nid)) $nids[] = $node->nid;
+      }
+      else {
+        $dups[] = $dup;
+      }
+    }
+
+  }
+  return array($nids, $dups);
+}
+
+function biblio_marc_check_md5($md5) {
+  static $marc_md5s = array();
+  if (empty($marc_md5s)) {
+    $result = db_query("SELECT * FROM {biblio_marc} ");
+    foreach ($result as $row) {
+      $marc_md5s[$row->biblio_marc_md5] = $row->nid;
+    }
+  }
+  if (isset($marc_md5s[$md5])) {
+    return $marc_md5s[$md5];
+  }
+  else {
+    $marc_md5s[$md5] = TRUE; // gaurd against duplicates in the same import
+    return;
+  }
+}
+
+
+function _biblio_marc_type_map($type, $reverse = FALSE) {
+  static $map = array();
+
+  if (empty($map)) {
+    $map = biblio_get_map('type_map', 'marc');
+  }
+
+  if ($reverse) {
+    return ($tag = array_search($type, $map)) ? $tag : 'Generic'; //return the biblio type or 129 (Misc) if type not found
+  }
+  return (isset($map[$type]))?$map[$type]:129; //return the biblio type or 129 (Misc) if type not found
+}
+
+function biblio_marc_biblio_export_options() {
+  return array('marc' => t('MARC'));
+}
+
+function biblio_marc_node_view($node, $view_mode) {
+  if ($node->type == 'biblio') {
+    switch ($view_mode) {
+      case 'full':
+      case 'teaser':
+        $links = biblio_marc_biblio_export_link($node->nid);
+        $node->content['links']['biblio_marc'] = array(
+          '#links' => $links,
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
+    }
+  }
+}
+
+/**
+ * Creates a link to export a node (or view) in MARC format
+ *
+ * @param $nid  the node id, if NULL then the current view is exported
+ * @return  a link (<a href=...>marc</a>)
+ */
+function biblio_marc_biblio_export_link($nid = NULL, $filter = array()) {
+  $show_link = variable_get('biblio_export_links', array('marc' => TRUE));
+  if (!isset($show_link['marc']) || empty($show_link['marc']) || !biblio_access('export')) {
+    return array();
+  }
+  $base = variable_get('biblio_base', 'biblio');
+
+  if (module_exists('popups') && !empty($nid)) {
+    $link = array(
+        'attributes' => array(
+          'class' => 'popups',
+          'title' => t("Click to get the MARC formatted output")));
+  }
+  else {
+    $link = array(
+        'attributes' => array(
+          'title' => t("Click to download the MARC formatted file")));
+  }
+
+  $link['attributes'] += array('rel' => 'nofollow');
+
+  $link['href']  = "$base/export/marc";
+  if (!empty($nid)) {
+    $link['href'] .= '/' . $nid;
+  }
+  $link['title'] = t('MARC');
+
+  if (empty($nid) && !empty($filter)) { // add any filters which may be on the current page
+    $link['query'] = $filter;
+  }
+
+  return array('biblio_marc' => $link);
+}
+
+function biblio_marc_biblio_export($nids) {
+  if (module_exists('popups') && count($nids)) {
+    $popup = TRUE;
+  }
+  else {
+    $popup = FALSE;
+    drupal_add_http_header('Content-type', 'application/text; charset=utf-8');
+    drupal_add_http_header('Content-Disposition', 'attachment; filename="Biblio.mrc"');
+  }
+
+  $nodes = node_load_multiple($nids, array(), TRUE);
+  foreach ($nodes as $node) {
+    if (!$popup) {
+      print _biblio_marc_export($node);
+    }
+    else{
+      $popup_data .=  _biblio_marc_export($node);
+    }
+  }
+  if ($popup && !empty($popup_data)) return '<pre>' . $popup_data . '</pre>';
+}
+
+function  _biblio_marc_export($node) {
+  module_load_include('php', 'biblio_marc', 'php-marc');
+  $record = new Record();
+  //           case '008':
+  //             $data = $field->data();
+  //             $node->biblio_year = substr($data, 7, 4);
+  //             $node->biblio_lang = substr($data, 35, 3);
+  //             break;
+  $leader = $record->leader();
+  if ($node->biblio_type == 100) {
+    $type = 'nam a';
+  }
+  else {
+    $type = 'nas a';
+  }
+  $record->leader(substr_replace($leader, $type, 5, 5));
+
+  $rec_eight = str_repeat(' ', 40);
+  $rec_eight = substr_replace($rec_eight, $node->biblio_year, 7, 4);
+  $rec_eight = substr_replace($rec_eight, $node->biblio_lang, 35, 3);
+  $rec_eight = substr_replace($rec_eight, 'd', 39, 1);
+  $field = new Field("008", $rec_eight);
+  $record->append_fields($field);
+
+  if (!empty($node->biblio_isbn)) {
+    $field = new Field("020", "", "", array("a" => $node->biblio_isbn));
+    $record->append_fields($field);
+  }
+  if (!empty($node->biblio_issn)) {
+    $field = new Field("022", "", "", array("a" => $node->biblio_issn));
+    $record->append_fields($field);
+  }
+  if (!empty($node->biblio_other_number)) {
+    $field = new Field("024", "", "", array("a" => $node->biblio_other_number));
+    $record->append_fields($field);
+  }
+  if (!empty($node->biblio_call_number)) {
+    $field = new Field("050", "", "", array("a" => $node->biblio_call_number));
+    $record->append_fields($field);
+  }
+  if (!empty($node->title)) {
+    $field = new Field("245", "0", "0", array("a" => $node->title));
+    $record->append_fields($field);
+  }
+  if (!empty($node->biblio_sort_title)) {
+    $field = new Field("210", "0", "#", array("a" => $node->biblio_sort_title));
+    $record->append_fields($field);
+  }
+  //           case '245':
+  //             $node->title = str_replace(' /', '', $field->subfield('a')) . ' ' . $field->subfield('b');
+  //             break;
+  if (!empty($node->biblio_edition)) {
+    $field = new Field("250", "", "", array("a" => $node->biblio_edition));
+    $record->append_fields($field);
+  }
+  if (!empty($node->biblio_place_published)) {
+    $subfields['a'] = $node->biblio_place_published;
+  }
+  if (!empty($node->biblio_publisher)) {
+    $subfields['b'] = $node->biblio_publisher;
+  }
+  if (!empty($node->biblio_date)) {
+    $subfields['c'] = $node->biblio_date;
+  }
+  if (!empty($subfields)) {
+    $field = new Field("260", "", "", $subfields);
+    $record->append_fields($field);
+  }
+  if (!empty($node->biblio_pages)) {
+    $field = new Field("300", "", "", array("a" => $node->biblio_pages));
+    $record->append_fields($field);
+  }
+  if (!empty($node->biblio_volume)) {
+    $field = new Field("490", "0", "", array("v" => $node->biblio_volume));
+    $record->append_fields($field);
+  }
+  if (!empty($node->biblio_abst_e)) {
+    $field = new Field("520", "3", "#", array("a" => $node->biblio_abst_e));
+    $record->append_fields($field);
+  }
+  //           case ($tagnum >= 500 && $tagnum <= 599):
+  //             $value = $field->subfield('a');
+  //             if (!empty($value)) {
+  //               $node->biblio_notes .= $value;
+  //             }
+  if (!empty($node->biblio_keywords)) {
+    foreach($node->biblio_keywords as $keyword) {
+      $field = new Field("653", "1", "0", array("a" => $keyword));
+      $record->append_fields($field);
+    }
+  }
+  if (!empty($node->biblio_contributors)) {
+    foreach ($node->biblio_contributors as $i => $author) {
+      $first = $author['firstname'];
+      $last  = $author['lastname'];
+      $init  = $author['initials'];
+      $cat   = $author['auth_category'];
+      $name = $last . ($first ? ', ' . $first : '') . ($init ? ', ' . $init : '');
+      $tag = ($i == 0 ? ($cat == 5 ? 110 :100) : ($cat == 5 ? 710 :700));
+      $field = new Field($tag, "1", "#", array("a" => $name));
+      $record->append_fields($field);
+    }
+  }
+  if (!empty($node->biblio_url)) {
+    $url = $node->biblio_url;
+  }
+  else {
+    $options['absolute'] = TRUE;
+    $url = url("node/$node->nid", $options);
+  }
+  if (!empty($url)) {
+    $field = new Field("856", "", "", array("u" => $url));
+    $record->append_fields($field);
+  }
+  return $record->raw();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/marcParse/example.mrc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1 @@
+01850     2200517   45000010011000000030007000110080039000180200026000570350015000830400007000980420012001050840018001170840018001350840021001530840022001741000030001962450062002262500013002882600058003013000033003594400037003925000023004295990010004527400024004627750034004868410048005208410049005688410047006178410048006648410047007128410047007598520038008068520021008448520013008658520016008788520028008948520021009229000056009439000060009999000057010599000056011169000057011729000060012299760026012890050017013150000000044EMILDA980120s1998    fi     j      000 0 swe  a9515008808cFIM 72:00  99515008808  aNB  9NB9SEE  aHcd,u2kssb/6  5NBauHc2kssb  5SEEaHcf2kssb/6  5QaHcd,uf2kssb/61 aJansson, Tove,d1914-200104aDet osynliga barnet och andra berättelser /cTove Jansson  a7. uppl.  aHelsingfors :bSchildt,c1998 ;e(Falun :fScandbook)  a166, [4] s. :bill. ;c21 cm 0aMumin-biblioteket,x99-0698931-9  aOriginaluppl. 1962  aLi: S4 aDet osynliga barnet1 z951-50-0385-7w9515003857907  5Liaxab0201080u    0   4000uu   |000000e1  5SEEaxab0201080u    0   4000uu   |000000e1  5Laxab0201080u    0   4000uu   |000000e1  5NBaxab0201080u    0   4000uu   |000000e1  5Qaxab0201080u    0   4000uu   |000000e1  5Saxab0201080u    0   4000uu   |000000e1  5NBbNBcNB98:12hpliktjR, 980520  5LibLicCNBhh,u  5SEEbSEE  5QbQj98947  5LbLc0100h98/j3043 H  5SbShSv97j72351saYanson, Tobe,d1914-2001uJansson, Tove,d1914-20011saJanssonová, Tove,d1914-2001uJansson, Tove,d1914-20011saJansone, Tuve,d1914-2001uJansson, Tove,d1914-20011saJanson, Tuve,d1914-2001uJansson, Tove,d1914-20011saJansson, Tuve,d1914-2001uJansson, Tove,d1914-20011saJanssonova, Tove,d1914-2001uJansson, Tove,d1914-2001 2aHcd,ubSkönlitteratur20050204111518.0
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/marcParse/example.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * @package PHP-MARC
+ */
+
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) 2003-2005 Oy Realnode Ab
+//
+//-----------------------------------------------------------------------------
+//
+// example.php
+//     Part of the Emilda Project (http://www.emilda.org/)
+//
+// Description
+//     Examples how to use PHP-MARC
+//
+// Authors
+//     Christoffer Landtman <landtman (at) realnode com>
+//
+//-----------------------------------------------------------------------------
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// $Revision$
+//
+//-----------------------------------------------------------------------------
+
+require_once "../php-marc/php-marc.php";
+
+// Other way to access file
+/*$string = file("example.mrc");
+$file = new USMARC($string[0]);*/
+
+// Open file
+$file = new File("example.mrc");
+
+// Read next record
+$record = $file->next();
+
+// Create new field
+$field = new Field("245", "", "", array("a" => "Mumin"));
+// Add subfield
+$field->add_subfields(array("b" => "Det Osynliga Barnet"));
+// Other ways to update field
+$field->update(array("ind2" => "1", "b" => "Vinter i Mumindalen", "c" => "Tove Jansson"));
+
+// Replace existing field
+$existing =& $record->field("245");
+$existing->replace_with($field);
+
+$clone = $field->make_clone();
+// Change some more
+$clone->update(array("a" => "Muminsagor", "b" => "Muminpappans memoarer"));
+
+// And append to record
+$record->append_fields($clone);
+
+// Some output
+print "<pre>";
+print $record->formatted();
+print "\n\n";
+print $file->raw[0];
+print "\n";
+print $record->raw();
+print "\n\n";
+print $record->ffield("245", "Formatted output: Title: <b>%a</b>, Remainder of title: <b>%b</b>, Responsibility: <b>%c</b>\n");
+print "</pre>";
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/marcParse/php-marc.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1016 @@
+<?php
+
+/**
+ * @package PHP-MARC
+ */
+
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) 2003-2005 Oy Realnode Ab
+//
+//-----------------------------------------------------------------------------
+//
+// php-marc.php
+//     Part of the Emilda Project (http://www.emilda.org/)
+//
+// Description
+//     MARC Record parser. Syntatically and logically identical to
+//     the Perl library MARC::Record. MARC parsing rules have been
+//     checked up from MARC::Record.
+//
+// Authors
+//     Christoffer Landtman <landtman (at) realnode com>
+//
+//-----------------------------------------------------------------------------
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+//-----------------------------------------------------------------------------
+//
+// $Revision$
+//
+//-----------------------------------------------------------------------------
+
+/**
+ * Hexadecimal value for Subfield indicator
+ * @global hex SUBFIELD_INDICATOR
+ */
+define("SUBFIELD_INDICATOR", "\x1F");
+/**
+ * Hexadecimal value for End of Field
+ * @global hex END_OF_FIELD
+ */
+define("END_OF_FIELD", "\x1E");
+/**
+ * Hexadecimal value for End of Record
+ * @global hex END_OF_RECORD
+ */
+define("END_OF_RECORD", "\x1D");
+/**
+ * Length of the Directory
+ * @global integer DIRECTORY_ENTRY_LEN
+ */
+define("DIRECTORY_ENTRY_LEN", 12);
+/**
+ * Length of the Leader
+ * @global integer LEADER_LEN
+ */
+define("LEADER_LEN", 24);
+
+/**
+ * Class File
+ * Class to read MARC records from file(s)
+ */
+Class File {
+
+  /**
+   * ========== VARIABLE DECLARATIONS ==========
+   */
+
+  /**
+   * Array containing raw records
+   * @var array
+   */
+  var $raw;
+  /**
+   * Array of warnings
+   * @var array
+   */
+  var $warn;
+  /**
+   * Current position in the array of records
+   * @var integer
+   */
+  var $pointer;
+
+  /**
+   * ========== ERROR FUNCTIONS ==========
+   */
+
+  /**
+   * Croaking function
+   *
+   * Similar to Perl's croak function, which ends parsing and raises an
+   * user error with a descriptive message.
+   * @param string The message to display
+   */
+  function _croak($msg) {
+    trigger_error($msg, E_USER_ERROR);
+  }
+
+  /**
+   * Fuction to issue warnings
+   *
+   * Warnings will not be displayed unless explicitly accessed, but all
+   * warnings issued during parse will be stored
+   * @param string Warning
+   * @return string Last added warning
+   */
+  function _warn($msg) {
+    $this->warn[] = $msg;
+    return $msg;
+  }
+
+  /**
+   * Get warning(s)
+   *
+   * Get either all warnings or a specific warning ID
+   * @param integer ID of the warning
+   * @return array|string Return either Array of all warnings or specific warning
+   */
+  function warnings($id = "") {
+    if (!$id) {
+      return $this->warn;
+    } else {
+      if (array_key_exists($id, $this->warn)) {
+        return $this->warn[$id];
+      } else {
+        return "Invalid warning ID: $id";
+      }
+    }
+  }
+
+  /**
+   * ========== PROCESSING FUNCTIONS ==========
+   */
+
+  /**
+   * Return the next raw MARC record
+   *
+   * Returns th nexts raw MARC record from the read file, unless all
+   * records already have been read.
+   * @return string|FALSE Either a raw record or False
+   */
+  function _next() {
+    /**
+     * Exit if we are at the end of the file
+     */
+    if ($this->pointer >= count($this->raw)) {
+      return FALSE;
+    }
+
+    /**
+     * Read next line
+     */
+    $usmarc = $this->raw[$this->pointer++];
+
+    // remove illegal stuff that sometimes occurs between records
+    // preg_replace does not know what to do with \x00, thus omitted.
+    $usmarc = preg_replace("/^[\x0a\x0d]+/", "", $usmarc);
+
+    /**
+     * Record validation
+     */
+    if ( strlen($usmarc) < 5 ) {
+      $this->_warn( "Couldn't find record length" );
+    }
+    $reclen = substr($usmarc,0,5);
+    if ( preg_match("/^\d{5}$/", $reclen) || $reclen != strlen($usmarc) ) {
+      $this->_warn( "Invalid record length \"$reclen\"" );
+    }
+
+    return $usmarc;
+  }
+
+  /**
+   * Read in MARC record file
+   *
+   * This function will read in MARC record files that either
+   * contain a single MARC record, or numerous records.
+   * @param string Name of the file
+   * @return string Returns warning if issued during read
+   */
+  function file($in) {
+    if (file_exists($in)) {
+      $input = file($in);
+      $recs = explode(END_OF_RECORD, join("", $input));
+      // Append END_OF_RECORD as we lost it when splitting
+      // Last is not record, as it is empty because every record ends
+      // with END_OF_RECORD.
+      for ($i = 0; $i < (count($recs)-1); $i++) {
+        $this->raw[] = $recs[$i].END_OF_RECORD;
+      }
+      $this->pointer = 0;
+    } else {
+      return $this->_warn("Invalid input file: $i");
+    }
+  }
+
+  /**
+   * Return next Record-object
+   *
+   * Decode the next raw MARC record and return
+   * @return Record A Record object
+   */
+  function next() {
+    if ($raw = $this->_next()) {
+      return $this->decode($raw);
+    } else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Decode a given raw MARC record
+   *
+   * "Port" of Andy Lesters MARC::File::USMARC->decode() function into PHP. Ideas and
+   * "rules" have been used from USMARC::decode().
+   *
+   * @param string Raw MARC record
+   * @return Record Decoded MARC Record object
+   */
+  function decode($text) {
+    if (!preg_match("/^\d{5}/", $text, $matches)) {
+      $this->_croak('Record length "'.substr( $text, 0, 5 ).'" is not numeric');
+    }
+
+    $marc = new Record;
+
+    // Store record length
+    $reclen = $matches[0];
+
+    if ($reclen != strlen($text)) {
+      $this->_croak( "Invalid record length: Leader says $reclen bytes, but it's actually ".strlen($text));
+    }
+
+    if (substr($text, -1, 1) != END_OF_RECORD)
+      $this->_croak("Invalid record terminator");
+
+      // Store leader
+    $marc->leader(substr( $text, 0, LEADER_LEN ));
+
+    // bytes 12 - 16 of leader give offset to the body of the record
+    $data_start = 0 + substr( $text, 12, 5 );
+
+    // immediately after the leader comes the directory (no separator)
+    $dir = substr( $text, LEADER_LEN, $data_start - LEADER_LEN - 1 );  // -1 to allow for \x1e at end of directory
+
+    // character after the directory must be \x1e
+    if (substr($text, $data_start-1, 1) != END_OF_FIELD) {
+      $this->_croak("No directory found");
+    }
+
+    // All directory entries 12 bytes long, so length % 12 must be 0
+    if (strlen($dir) % DIRECTORY_ENTRY_LEN != 0) {
+      $this->_croak("Invalid directory length");
+    }
+
+    // go through all the fields
+    $nfields = strlen($dir) / DIRECTORY_ENTRY_LEN;
+    for ($n=0; $n<$nfields; $n++) {
+      // As pack returns to key 1, leave place 0 in list empty
+      list(, $tagno) = unpack("A3", substr($dir, $n*DIRECTORY_ENTRY_LEN, DIRECTORY_ENTRY_LEN));
+      list(, $len) = unpack("A3/A4", substr($dir, $n*DIRECTORY_ENTRY_LEN, DIRECTORY_ENTRY_LEN));
+      list(, $offset) = unpack("A3/A4/A5", substr($dir, $n*DIRECTORY_ENTRY_LEN, DIRECTORY_ENTRY_LEN));
+
+      // Check directory validity
+      if (!preg_match("/^[0-9A-Za-z]{3}$/", $tagno)) {
+        $this->_croak("Invalid tag in directory: \"$tagno\"");
+      }
+      if (!preg_match("/^\d{4}$/", $len)) {
+        $this->_croak("Invalid length in directory, tag $tagno: \"$len\"");
+      }
+      if (!preg_match("/^\d{5}$/", $offset)) {
+        $this->_croak("Invalid offset in directory, tag $tagno: \"$offset\"");
+      }
+      if ($offset + $len > $reclen) {
+        $this->_croak("Directory entry runs off the end of the record tag $tagno");
+      }
+
+      $tagdata = substr( $text, $data_start + $offset, $len );
+
+      if ( substr($tagdata, -1, 1) == END_OF_FIELD ) {
+        # get rid of the end-of-tag character
+        $tagdata = substr($tagdata, 0, -1);
+        --$len;
+      } else {
+        $this->_croak("field does not end in end of field character in tag $tagno");
+      }
+
+      if ( preg_match("/^\d+$/", $tagno) && ($tagno < 10) ) {
+        $marc->append_fields(new Field($tagno, $tagdata));
+      } else {
+        $subfields = explode(SUBFIELD_INDICATOR, $tagdata);
+        $indicators = array_shift($subfields);
+
+        if ( strlen($indicators) > 2 || strlen( $indicators ) == 0 ) {
+          $this->_warn("Invalid indicators \"$indicators\" forced to blanks for tag $tagno\n");
+          list($ind1,$ind2) = array(" ", " ");
+        } else {
+          $ind1 = substr( $indicators, 0, 1 );
+          $ind2 = substr( $indicators, 1, 1 );
+        }
+
+        // Split the subfield data into subfield name and data pairs
+        $subfield_data = array();
+        foreach ($subfields as $subfield) {
+          if ( strlen($subfield) > 0 ) {
+            $subfield_data[substr($subfield, 0, 1)][] = substr($subfield, 1);
+          } else {
+            $this->_warn( "Entirely empty subfield found in tag $tagno" );
+          }
+        }
+
+        if (!isset($subfield_data)) {
+          $this->_warn( "No subfield data found $location for tag $tagno" );
+        }
+
+        $marc->append_fields(new Field($tagno, $ind1, $ind2, $subfield_data ));
+      }
+    }
+    return $marc;
+  }
+
+  /**
+   * Get the number of records available in this Record
+   * @return int The number of records
+   */
+  function num_records() {
+    return count($this->raw);
+  }
+}
+
+/**
+ * USMARC Class
+ * Extension class to File class, which allows passing of raw MARC string
+ * instead of filename
+ */
+Class USMARC Extends File {
+  /**
+   * Read raw MARC string for decoding
+   * @param string Raw MARC
+  */
+  function usmarc($string) {
+    $this->raw[] = $string;
+    $this->pointer = 0;
+  }
+}
+
+/**
+ * Record Class
+ * Create a MARC Record class
+ */
+Class Record {
+
+  /**
+   * ========== VARIABLE DECLARATIONS ==========
+   */
+
+  /**
+   * Contain all @link Field objects of the Record
+   * @var array
+   */
+  var $fields;
+  /**
+   * Leader of the Record
+   * @var string
+   */
+  var $ldr;
+  /**
+   * Array of warnings
+   * @var array
+   */
+  var $warn;
+
+  /**
+   * ========== ERROR FUNCTIONS ==========
+   */
+
+  /**
+   * Croaking function
+   *
+   * Similar to Perl's croak function, which ends parsing and raises an
+   * user error with a descriptive message.
+   * @param string The message to display
+   */
+  function _croak($msg) {
+    trigger_error($msg, E_USER_ERROR);
+  }
+
+  /**
+   * Fuction to issue warnings
+   *
+   * Warnings will not be displayed unless explicitly accessed, but all
+   * warnings issued during parse will be stored
+   * @param string Warning
+   * @return string Last added warning
+   */
+  function _warn($msg) {
+    $this->warn[] = $msg;
+    return $msg;
+  }
+
+  /**
+   * Return an array of warnings
+   */
+  function warnings() {
+    return $this->warn;
+  }
+
+  /**
+   * ========== PROCESSING FUNCTIONS ==========
+   */
+
+  /**
+   * Start function
+   *
+   * Set all variables to defaults to create new Record object
+   */
+  function record() {
+    $this->fields = array();
+    $this->ldr = str_repeat(' ', 24);
+  }
+
+  /**
+   * Get/Set Leader
+   *
+   * If argument specified, sets leader, otherwise gets leader. No validation
+   * on the specified leader is performed
+   * @param string Leader
+   * @return string|null Return leader in case requested.
+   */
+  function leader($ldr = "") {
+    if ($ldr) {
+      $this->ldr = $ldr;
+    } else {
+      return $this->ldr;
+    }
+  }
+
+  /**
+   * Append field to existing
+   *
+   * Given Field object will be appended to the existing list of fields. Field will be
+   * appended last and not in its "correct" location.
+   * @param Field The field to append
+   */
+  function append_fields($field) {
+    if (strtolower(get_class($field)) == "field") {
+      $this->fields[$field->tagno][] = $field;
+    } else {
+      $this->_croak(sprintf("Given argument must be Field object, but was '%s'", get_class($field)));
+    }
+  }
+
+  /**
+   * Build Record Directory
+   *
+   * Generate the directory of the Record according to existing data.
+   * @return array Array ( $fields, $directory, $total, $baseaddress )
+   */
+  function _build_dir() {
+    // Vars
+    $fields = array();
+    $directory = array();
+
+    $dataend = 0;
+    foreach ($this->fields as $field_group ) {
+      foreach ($field_group as $field) {
+        // Get data in raw format
+        $str = $field->raw();
+        $fields[] = $str;
+
+        // Create directory entry
+        $len = strlen($str);
+        $direntry = sprintf( "%03s%04d%05d", $field->tagno(), $len, $dataend );
+        $directory[] = $direntry;
+        $dataend += $len;
+      }
+    }
+
+    /**
+     * Rules from MARC::Record::USMARC
+     */
+    $baseaddress =
+      LEADER_LEN +    // better be 24
+      ( count($directory) * DIRECTORY_ENTRY_LEN ) +
+      // all the directory entries
+      1;              // end-of-field marker
+
+
+    $total =
+      $baseaddress +  // stuff before first field
+      $dataend +      // Length of the fields
+      1;              // End-of-record marker
+
+    return array($fields, $directory, $total, $baseaddress);
+  }
+
+  /**
+   * Set Leader lengths
+   *
+   * Set the Leader lengths of the record according to defaults specified in
+   * http://www.loc.gov/marc/bibliographic/ecbdldrd.html
+   */
+  function leader_lengths($reclen, $baseaddr) {
+    $this->ldr = substr_replace($this->ldr, sprintf("%05d", $reclen), 0, 5);
+    $this->ldr = substr_replace($this->ldr, sprintf("%05d", $baseaddr), 12, 5);
+    $this->ldr = substr_replace($this->ldr, '22', 10, 2);
+    $this->ldr = substr_replace($this->ldr, '4500', 20, 4);
+  }
+
+  /**
+   * Return all Field objects
+   * @return array Array of Field objects
+   */
+  function fields() {
+    return $this->fields;
+  }
+
+  /**
+   * Get specific field
+   *
+   * Search for field in Record fields based on field name, e.g. 020
+   * @param string Field name
+   * @return Field|FALSE Return Field if found, otherwise FALSE
+   */
+  function field($spec) {
+    if (array_key_exists($spec, $this->fields)) {
+      return $this->fields[$spec][0];
+    } else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Get subfield of Field object
+   *
+   * Returns the value of a specific subfield of a given Field object
+   * @param string Name of field
+   * @param string Name of subfield
+   * @return string|FALSE Return value of subfield if Field exists, otherwise FALSE
+   */
+  function subfield($field, $subfield) {
+    if (!$field = $this->field($field)) {
+      return FALSE;
+    } else {
+      return $field->subfield($subfield);
+    }
+  }
+
+  /**
+   * Delete Field
+   *
+   * Delete a given field from within a Record
+   * @param Field The field to be deleted
+   */
+  function delete_field($obj) {
+    unset($this->fields[$obj->field]);
+  }
+
+  /**
+   * Clone record
+   *
+   * Clone a record with all its Fields and subfields
+   * @return Record Clone record
+   */
+  function make_clone() {
+    $clone = new Record;
+    $clone->leader($this->ldr);
+
+    foreach ($this->fields() as $data) {
+      foreach ($data as $field) {
+        $clone->append_fields($field);
+      }
+    }
+
+    return $clone;
+  }
+
+  /**
+   * ========== OUTPUT FUNCTIONS ==========
+   */
+
+  /**
+   * Formatted representation of Field
+   *
+   * Format a Field with a sprintf()-like formatting syntax. The formatting
+   * codes are the names of the subfields of the Field.
+   * @param string Field name
+   * @param string Format string
+   * @return string|FALSE Return formatted string if Field exists, otherwise False
+   */
+  function ffield($tag, $format) {
+    $result = "";
+    if ($field = $this->field($tag)) {
+      for ($i=0; $i<strlen($format); $i++) {
+        $curr = $format[$i];
+        if ($curr != "%") {
+          $result[] = $curr;
+        } else {
+          $i++;
+          $curr = $format[$i];
+          if ($curr == "%") {
+            $result[] = $curr;
+          } else {
+            $result[] = $field->subfield($curr);
+          }
+        }
+      }
+      return implode("", $result);
+    } else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Return Raw
+   *
+   * Return the Record in raw MARC format.
+   * @return string Raw MARC data
+   */
+  function raw() {
+    list ($fields, $directory, $reclen, $baseaddress) = $this->_build_dir();
+    $this->leader_lengths($reclen, $baseaddress);
+
+    /**
+     * Glue together all parts
+     */
+    return $this->ldr.implode("", $directory).END_OF_FIELD.implode("", $fields).END_OF_RECORD;
+  }
+
+  /**
+   * Return formatted
+   *
+   * Return the Record in a formatted fashion. Similar to the output
+   * of the formatted() function in MARC::Record in Perl
+   * @return string Formatted representation of MARC record
+   */
+  function formatted() {
+    $formatted = "";
+    foreach ($this->fields as $field_group) {
+      foreach ($field_group as $field) {
+        $formatted .= $field->formatted(). "\n";
+      }
+    }
+    return $formatted;
+  }
+}
+
+/**
+ * Field Class
+ * Create a MARC Field object
+ */
+Class Field {
+
+  /**
+   * ========== VARIABLE DECLARATIONS ==========
+   */
+
+  /**
+   * The tag name of the Field
+   * @var string
+   */
+  var $tagno;
+  /**
+   * Value of the first indicator
+   * @var string
+   */
+  var $ind1;
+  /**
+   * Value of the second indicator
+   * @var string
+   */
+  var $ind2;
+  /**
+   * Array of subfields
+   * @var array
+   */
+  var $subfields = array();
+  /**
+   * Specify if the Field is a Control field
+   * @var bool
+   */
+  var $is_control;
+  /**
+   * Array of warnings
+   * @var array
+   */
+  var $warn;
+  /**
+   * Value of field, if field is a Control field
+   * @var string
+   */
+  var $data;
+
+  /**
+   * ========== ERROR FUNCTIONS ==========
+   */
+
+  /**
+   * Croaking function
+   *
+   * Similar to Perl's croak function, which ends parsing and raises an
+   * user error with a descriptive message.
+   * @param string The message to display
+   */
+  function _croak($msg) {
+    trigger_error($msg, E_USER_ERROR);
+  }
+
+  /**
+   * Fuction to issue warnings
+   *
+   * Warnings will not be displayed unless explicitly accessed, but all
+   * warnings issued during parse will be stored
+   * @param string Warning
+   * @return string Last added warning
+   */
+  function _warn($msg) {
+    $this->warn[] = $msg;
+    return $msg;
+  }
+
+  /**
+   * Return an array of warnings
+   */
+  function warnings() {
+    return $this->warn;
+  }
+
+  /**
+   * ========== PROCESSING FUNCTIONS ==========
+   */
+
+  /**
+   * Field init function
+   *
+   * Create a new Field object from passed arguments
+   * @param array Array ( tagno, ind1, ind2, subfield_data )
+   * @return string Returns warnings if any issued during parse
+   */
+  function field() {
+    $args = func_get_args();
+
+    $tagno = array_shift($args);
+    $this->tagno = $tagno;
+
+    // Check if valid tag
+    if (!preg_match("/^[0-9A-Za-z]{3}$/", $tagno)) {
+      return $this->_warn("Tag \"$tagno\" is not a valid tag.");
+    }
+
+    // Check if field is Control field
+    $this->is_control = (preg_match("/^\d+$/", $tagno) && $tagno < 10);
+    if ($this->is_control) {
+      $this->data = array_shift($args);
+    } else {
+      foreach (array("ind1", "ind2") as $indcode) {
+        $indicator = array_shift($args);
+        if (!preg_match("/^[0-9A-Za-z ]$/", $indicator)) {
+          if ($indicator != "") {
+            $this->_warn("Illegal indicator '$indicator' in field '$tagno' forced to blank");
+          }
+          $indicator = " ";
+        }
+        $this->$indcode = $indicator;
+      }
+
+      $subfields = array_shift($args);
+
+      if (count($subfields) < 1) {
+        return $this->_warn("Field $tagno must have at least one subfield");
+      } else {
+        $this->add_subfields($subfields);
+      }
+    }
+  }
+
+  /**
+   * Add subfield
+   *
+   * Appends subfields to existing fields last, not in "correct" plase
+   * @param array Subfield data
+   * @return string Returns warnings if issued during parse.
+   */
+  function add_subfields() {
+    // Process arguments
+    $args = func_get_args();
+    if (count($args) == 1 && is_array($args[0])) {
+      $args = $args[0];
+    }
+    // Add subfields, is appropriate
+    if ($this->is_control) {
+      return $this->_warn("Subfields allowed only for tags bigger or equal to 10");
+    } else {
+      $this->subfields = array_merge($this->subfields, $args);
+    }
+
+    return count($args)/2;
+  }
+
+  /**
+   * Return Tag number of Field
+   */
+  function tagno() {
+    return $this->tagno;
+  }
+
+  /**
+   * Set/Get Data of Control field
+   *
+   * Sets the Data if argument given, otherwise Data returned
+   * @param string Data to be set
+   * @return string Data of Control field if argument not given
+   */
+  function data($data = "") {
+    if (!$this->is_control) {
+      $this->_croak("data() is only allowed for tags bigger or equal to 10");
+    }
+    if ($data) {
+      $this->data = $data;
+    } else {
+      return $this->data;
+    }
+  }
+
+  /**
+   * Get values of indicators
+   *
+   * @param string Indicator number
+   */
+  function indicator($ind) {
+    if ($ind == 1) {
+      return $this->ind1;
+    } elseif ($ind == 2) {
+      return $this->ind2;
+    } else {
+      $this->_warn("Invalid indicator: $ind");
+    }
+  }
+
+  /**
+   * Check if Field is Control field
+   *
+   * @return bool True or False
+   */
+  function is_control() {
+    return $this->is_control;
+  }
+
+  /**
+   * Get the value of a subfield
+   *
+   * Return of the value of the given subfield, if exists
+   * @param string Name of subfield
+   * @return string|FALSE Value of the subfield if exists, otherwise FALSE
+   */
+  function subfield($code, $repeatable = FALSE) {
+    if (array_key_exists($code, $this->subfields)) {
+      return $repeatable ? $this->subfields[$code] : $this->subfields[$code][0];
+    } else {
+      return $repeatable ? array(): FALSE;
+    }
+  }
+
+  /**
+   * Return array of subfields
+   *
+   * @return array Array of subfields
+   */
+  function subfields() {
+    return $this->subfields;
+  }
+
+  /**
+   * Update Field
+   *
+   * Update Field with given array of arguments.
+   * @param array Array of key->value pairs of data
+   */
+  function update() {
+    // Process arguments
+    $args = func_get_args();
+    if (count($args) == 1 && is_array($args[0])) {
+      $args = $args[0];
+    }
+    if ($this->is_control) {
+      $this->data = array_shift($args);
+    } else {
+      foreach ($args as $subfield => $value) {
+        if ($subfield == "ind1") {
+          $this->ind1 = $value;
+        } elseif ($subfield == "ind2") {
+          $this->ind2 = $value;
+        } else {
+          $this->subfields[$subfield] = $value;
+        }
+      }
+    }
+  }
+
+  /**
+   * Replace Field with given Field
+   *
+   * @param Field Field to replace with
+   */
+  function replace_with($obj) {
+    if (strtolower(get_class($obj)) == "field") {
+      $this->tagno = $obj->tagno;
+      $this->ind1 = $obj->ind1;
+      $this->ind2 = $obj->ind2;
+      $this->subfields = $obj->subfields;
+      $this->is_control = $obj->is_control;
+      $this->warn = $obj->warn;
+      $this->data = $obj->data;
+    } else {
+      $this->_croak(sprintf("Argument must be Field-object, but was '%s'", get_class($obj)));
+    }
+  }
+
+  /**
+   * Clone Field
+   *
+   * @return Field Cloned Field object
+   */
+  function make_clone() {
+    if ($this->is_control) {
+      return new Field($this->tagno, $this->data);
+    } else {
+      return new Field($this->tagno, $this->ind1, $this->ind2, $this->subfields);
+    }
+  }
+
+  /**
+   * ========== OUTPUT FUNCTIONS ==========
+   */
+
+  /**
+   * Return Field formatted
+   *
+   * Return Field as string, formatted in a similar fashion to the
+   * MARC::Record formatted() functio in Perl
+   * @return string Formatted output of Field
+   */
+  function formatted() {
+    // Variables
+    $lines = array();
+    // Process
+    if ($this->is_control) {
+      return sprintf("%3s     %s", $this->tagno, $this->data);
+    } else {
+      $pre = sprintf("%3s %1s%1s", $this->tagno, $this->ind1, $this->ind2);
+    }
+    // Process subfields
+    foreach ($this->subfields as $subfield => $value) {
+      $lines[] = sprintf("%6s _%1s%s", $pre, $subfield, $value);
+      $pre = "";
+    }
+
+    return join("\n", $lines);
+  }
+
+  /**
+   * Return Field in Raw MARC
+   *
+   * Return the Field formatted in Raw MARC for saving into MARC files
+   * @return string Raw MARC
+   */
+  function raw() {
+    if ($this->is_control) {
+      return $this->data.END_OF_FIELD;
+    } else {
+      $subfields = array();
+      foreach ($this->subfields as $subfield => $value) {
+        $subfields[] = SUBFIELD_INDICATOR.$subfield.$value;
+      }
+      return $this->ind1.$this->ind2.implode("", $subfields).END_OF_FIELD;
+    }
+  }
+
+  /**
+   * Return Field as String
+   *
+   * Return Field formatted as String, with either all subfields or special
+   * subfields as specified.
+   * @return string Formatted as String
+   */
+  function string($fields = "") {
+    $matches = array();
+    if ($fields) {
+      for($i=0; $i<strlen($fields); $i++) {
+        if (array_key_exists($fields[$i], $this->subfields)) {
+          $matches[] = $this->subfields[$fields[$i]];
+        }
+      }
+    } else {
+      $matches = $this->subfields;
+    }
+    return implode(" ", $matches);
+  }
+
+}
+
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/pubmed/EntrezClient.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,505 @@
+<?php
+/**
+ * @file EntrezClient.php
+ * Provides Entrez client to retrieve items from the NCBI databases
+ * Orginally writen by Stefan Freudenberg
+ */
+
+class BiblioEntrezClient
+{
+  const DEFAULT_DATABASE = 'pubmed';
+
+  const BASE_URL = 'http://eutils.ncbi.nlm.nih.gov/entrez/eutils/';
+
+  private $database = self::DEFAULT_DATABASE;
+
+  private $useHistory = 'y';
+
+  private $webEnvironment;
+
+  private $queryKey;
+
+  private $tool;
+
+  private $email;
+
+  private $term;
+
+  private $dateRange;
+
+  private $returnMax = 100;
+
+  private $sort;
+
+  private $query;
+
+  private $count;
+
+  /**
+   * Sets a web environment.
+   *
+   * @param string $webEnvironment
+   */
+  public function setWebEnvironment($webEnvironment)
+  {
+    $this->webEnvironment = $webEnvironment;
+  }
+
+  /**
+   * Returns the web environment from the previous ESearch results.
+   *
+   * This value may change with each utility call. If WebEnv is used, History
+   * search numbers can be included in an ESummary URL, e.g.,
+   * term=cancer+AND+%23X (where %23 replaces # and X is the History search
+   * number).
+   *
+   * @return string
+   */
+  public function getWebEnvironment()
+  {
+    return $this->webEnvironment;
+  }
+
+  /**
+   * Sets a history search number.
+   *
+   * @param int $key
+   */
+  public function setQueryKey($key)
+  {
+    $this->queryKey = $key;
+  }
+
+  /**
+   * Returns the history search number from the previous ESearch results.
+   *
+   * @return int
+   */
+  public function getQueryKey()
+  {
+    return $this->queryKey;
+  }
+
+  /**
+   * Sets the entrez database to be queried.
+   *
+   * Values available from EInfo, PubMed is the default db.
+   *
+   * @param string $database
+   * @see getAvailableDatabases
+   */
+  public function setDatabase($database)
+  {
+    $this->database = strtolower($database);
+  }
+
+  /**
+   * Returns the database to be queried in the next search.
+   *
+   * @return string
+   */
+  public function getDatabase()
+  {
+    return $this->database;
+  }
+
+  /**
+   * Returns the available entrez databases from EInfo.
+   *
+   * @return array
+   * @throws Exception
+   */
+  public function getAvailableDatabases()
+  {
+    $databases = array();
+
+    $url = self::BASE_URL . 'einfo.fcgi';
+    $result = @simplexml_load_file($url);
+
+    if (!$result) {
+      throw new Exception('Query ' . $url . ' failed.');
+    }
+
+    if (isset($result->DbList->DbName)) {
+      foreach ($result->DbList->DbName as $name) {
+        $databases[] = (string)$name;
+      }
+    }
+
+    return $databases;
+  }
+
+  /**
+   * Sets a string identifying the resource.
+   *
+   * A string with no internal spaces that identifies the resource which is
+   * using Entrez links (e.g., tool=flybase). This argument is used to help
+   * NCBI provide better service to third parties generating Entrez queries
+   * from programs. As with any query system, it is sometimes possible to ask
+   * the same question different ways, with different effects on performance.
+   * NCBI requests that developers sending batch requests include a constant
+   * 'tool' argument for all requests using the utilities.
+   *
+   * @param string $tool
+   */
+  public function setTool($tool)
+  {
+    $this->tool = str_replace(array(" ", "\n", "\r"), '', $tool);
+  }
+
+  /**
+   * Returns the resource identifier.
+   *
+   * @return string
+   */
+  public function getTool()
+  {
+    return $this->tool;
+  }
+
+  /**
+   * Sets a contact email address for NCBI.
+   *
+   * If you choose to provide an email address, we will use it to contact you
+   * if there are problems with your queries or if we are changing software
+   * interfaces that might specifically affect your requests. If you choose
+   * not to include an email address we cannot provide specific help to you,
+   * but you can still sign up for utilities-announce to receive general
+   * announcements.
+   *
+   * @param string $email
+   */
+  public function setEmail($email)
+  {
+    $this->email = $email;
+  }
+
+  /**
+   * Returns the NCBI contact email address.
+   *
+   * @return string
+   */
+  public function getEmail()
+  {
+    return $this->email;
+  }
+
+  /**
+   * Sets the search terms for the next query.
+   *
+   * The search command uses terms or phrases with or without Boolean
+   * operators.  See the PubMed or Entrez help for information about search
+   * field descriptions and tags. Search fields and tags are database specific.
+   *
+   * @param string $term
+   */
+  public function setTerm($term)
+  {
+    $this->term = $term;
+    $this->webEnvironment = NULL;
+    $this->count = NULL;
+  }
+
+  /**
+   * Returns the current search terms.
+   *
+   * @return string
+   */
+  public function getTerm()
+  {
+    return $this->term;
+  }
+
+  /**
+   * Sets two specific dates bounding the results.
+   *
+   * @param $minDate
+   * @param $maxDate
+   * @throws Exception
+   */
+  public function setDateRange($minDate, $maxDate=null)
+  {
+    if (is_null($maxDate)) {
+      $maxDate = date('Y/m/d');
+    } else {
+      $maxDate = date('Y/m/d', strtotime($maxDate));
+    }
+
+    $minDate = date('Y/m/d', strtotime($minDate));
+
+    if ($maxDate < $minDate) {
+      throw new Exception('First argument must be an earlier date.');
+    }
+
+    $this->dateRange = array($minDate, $maxDate);
+  }
+
+  /**
+   * Returns the specified date range bounding the results.
+   *
+   * @return array
+   *   a pair of dates
+   */
+  public function getDateRange()
+  {
+    return $this->dateRange;
+  }
+
+  /**
+   * Returns the minimum date of the specified date range bounding the results.
+   *
+   * @return string
+   */
+  public function getMinDate()
+  {
+    return $this->dateRange[0];
+  }
+
+  /**
+   * Returns the maximum date of the specified date range bounding the results.
+   *
+   * @return string
+   */
+  public function getMaxDate()
+  {
+    return $this->dateRange[1];
+  }
+
+  /**
+   * Sets the maximum number of items retrieved by a search query.
+   *
+   * @param int $number
+   * @see search
+   */
+  public function setReturnMax($number)
+  {
+    $this->returnMax = $number;
+  }
+
+  /**
+   * Returns the maximum number of items retrieved by a search query.
+   *
+   * @return int
+   */
+  public function getReturnMax()
+  {
+    return $this->returnMax;
+  }
+
+  /**
+   * Returns the URL of the last executed query.
+   *
+   * @return string
+   */
+  public function getLastQuery()
+  {
+    return $this->query;
+  }
+
+  /**
+   * Returns up to the maximum number of items from the result set starting
+   * at $retstart.
+   *
+   * If this is the first search for a given term a web environment and a query
+   * key is retrieved from the NCBI server in addition to the result set.
+   * See http://eutils.ncbi.nlm.nih.gov/corehtml/query/static/esearch_help.html
+   *
+   * @param int $retStart
+   *   the sequential number of the first record retrieved - default=0
+   *   which will retrieve the first record
+   * @return SimpleXMLElement
+   *   an array of PubMed IDs
+   * @throws Exception
+   * @see setReturnMax
+   * @see setRelativeDate
+   */
+  public function search($retStart=0)
+  {
+    if (!is_null($this->webEnvironment)) {
+      $params['WebEnv'] = $this->webEnvironment;
+      $params['query_key'] = $this->queryKey;
+    } else {
+      $params['usehistory'] = $this->useHistory;
+      $params['tool'] = $this->getTool();
+      $params['email'] = $this->getEmail();
+      $params['term'] = $this->getTerm();
+    }
+
+    if (isset($this->dateRange)) {
+      $params['mindate'] = $this->getMinDate();
+      $params['maxdate'] = $this->getMaxDate();
+    }
+
+    $params['retstart'] = $retStart;
+    $params['retmax'] = $this->getReturnMax();
+    $params['db'] = $this->getDatabase();
+
+    $this->query = self::BASE_URL . 'esearch.fcgi?' . http_build_query($params);
+    $result = @simplexml_load_file($this->query);
+
+    if (!$result) {
+      throw new Exception('Query ' . $this->query . ' failed.');
+    }
+
+    if (isset($result->WebEnv)) {
+      $this->webEnvironment = (string)$result->WebEnv;
+      $this->queryKey = (int)$result->QueryKey;
+      $this->count = (int)$result->Count;
+    }
+
+    return $result;
+  }
+
+  /**
+   * Returns the number of results for the previously set search terms.
+   *
+   * @return int
+   * @throws Exception
+   */
+  public function count()
+  {
+    if (is_null($this->count)) {
+      $params['tool'] = $this->getTool();
+      $params['email'] = $this->getEmail();
+      $params['db'] = $this->getDatabase();
+      $params['term'] = $this->getTerm();
+      $params['rettype'] = 'count';
+
+      if (isset($this->dateRange)) {
+        $params['mindate'] = $this->getMinDate();
+        $params['maxdate'] = $this->getMaxDate();
+      }
+
+      $this->query = self::BASE_URL . 'esearch.fcgi?' . http_build_query($params);
+      $result = @simplexml_load_file($this->query);
+
+      if (!$result) {
+        throw new Exception('Query ' . $this->query . ' failed.');
+      }
+
+      if (isset($result->Count)) {
+        $this->count = (int)$result->Count;
+      }
+    }
+
+    return $this->count;
+  }
+
+  /**
+   * Returns the document identified by the given PubMed ID as a SimpleXMl
+   * object. The root element is PubmedArticleSet.
+   *
+   * @param int $id
+   * @return SimpleXMLElement
+   */
+  public function fetch($id)
+  {
+    $params['db'] = $this->getDatabase();
+    $params['retmode'] = 'xml';
+    $params['id'] = $id;
+
+    $this->query = self::BASE_URL . 'efetch.fcgi?' . http_build_query($params);
+    $request_options = array(
+      'method' => 'POST');
+    $result = drupal_http_request($this->query, $request_options);
+    if ($result->code != 200) {
+      throw new Exception('Query ' . $this->query . ' failed.');
+    }
+    $result = @simplexml_load_string($result->data);
+
+    if (!$result) {
+      throw new Exception('Query ' . $this->query . ' failed.');
+    }
+
+    return $result;
+  }
+  public function fetchSummaries($retStart=0) {
+    return $this->fetchRecords($retStart, TRUE);
+  }
+  public function fetchResult($retStart=0) {
+    return $this->fetchRecords($retStart);
+  }
+
+  /**
+   * Returns up to the maximum number of results starting at $retstart
+   * found by the previous search.
+   *
+   * In order to return results this method must be called after search. The
+   * search method retrieves a web environment and query key from the NCBI
+   * server which is used to fetch the results. After setting a new search term
+   * the old web environment is deleted and search must be executed again
+   * before utilizing this method.
+   *
+   * The root element of the returned SimpleXML object is PubmedArticleSet.
+   *
+   * @param $retStart
+   *   the sequential number of the first record retrieved - default=0
+   *   which will retrieve the first record
+   * @return SimpleXMLElement
+   * @throws Exception
+   * @see search
+   * @see setReturnMax
+   */
+  public function fetchRecords($retStart=0, $summaries = FALSE) {
+    if (is_null($this->webEnvironment)) {
+      throw new Exception(t('No web environment set.'));
+    }
+
+    $params['WebEnv'] = $this->webEnvironment;
+    $params['query_key'] = $this->queryKey;
+    $params['retstart'] = $retStart;
+    $params['retmax'] = $this->getReturnMax();
+    $params['db'] = $this->getDatabase();
+    $params['retmode'] = 'xml';
+
+    if (isset($this->dateRange)) {
+      $params['mindate'] = $this->getMinDate();
+      $params['maxdate'] = $this->getMaxDate();
+    }
+    if ($summaries) {
+      $this->query = self::BASE_URL . 'esummary.fcgi?' . http_build_query($params);
+    }
+    else {
+      $this->query = self::BASE_URL . 'efetch.fcgi?' . http_build_query($params);
+    }
+    $request_options = array('method' => 'POST');
+    $result = drupal_http_request($this->query, $request_options);
+
+    if ($result->code != 200) {
+      throw new Exception('Query ' . $this->query . ' failed.');
+    }
+
+    $result = @simplexml_load_string($result->data);
+
+
+    if (isset($result->body->pre->ERROR)) return FALSE;
+
+    return $result;
+  }
+
+  public function post($uids) {
+    $params['db'] = $this->getDatabase();
+    $params['id'] = implode(',', $uids);
+    $this->query = self::BASE_URL . 'epost.fcgi?' . http_build_query($params);
+    $request_options = array('method' => 'POST');
+    $result = drupal_http_request($this->query, $request_options);
+
+    if ($result->code != 200) {
+      throw new Exception('Query ' . $this->query . ' failed.');
+    }
+
+    $result = @simplexml_load_string($result->data);
+
+    if (!$result) {
+      throw new Exception('Query ' . $this->query . ' failed.');
+    }
+
+    if (isset($result->WebEnv)) {
+      $this->webEnvironment = (string)$result->WebEnv;
+      $this->queryKey = (int)$result->QueryKey;
+      $this->count = (int)$result->Count;
+    }
+
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/pubmed/EntrezPubmedArticle.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,241 @@
+<?php
+/**
+ * @file EntrezPubmedArticle.php
+ * Provides a class for handling PubMed articles retrieved with EFetch.
+ * Orginally writen by Stefan Freudenberg
+ */
+
+class BiblioEntrezPubmedArticle
+{
+  private $article;
+
+  private $id;
+
+  private $md5;
+
+  private $biblio = array();
+
+  /**
+   * Stores the given SimpleXMLElement the PubMed ID and the md5 hash of the
+   * serialized XML.
+   *
+   * @param $pubmedArticle
+   *   a PubmedArticle element
+   */
+  public function __construct(SimpleXMLElement $pubmedArticle = NULL)
+  {
+    if ($pubmedArticle) {
+      $this->setArticle($pubmedArticle);
+    }
+  }
+
+  /**
+   * Returns the PubMed ID of the article.
+   *
+   * @return int
+   */
+  public function setArticle(SimpleXMLElement $pubmedArticle)
+  {
+    $this->biblio = array();
+    $this->article = $pubmedArticle->MedlineCitation;
+    $this->pubmeddata = $pubmedArticle->PubmedData;
+    $this->id = (int)$pubmedArticle->MedlineCitation->PMID;
+    $this->md5 = md5($pubmedArticle->asXML());
+    return $this;
+  }
+  public function getId()
+  {
+    return $this->id;
+  }
+
+  /**
+   * Returns the md5 hash of the serialized XML.
+   *
+   * @return string
+   */
+  public function getMd5()
+  {
+    return $this->md5;
+  }
+
+  public function getBiblioAsObject() {
+    return (object)$this->getBiblio();
+  }
+
+  /**
+   * Returns article elements as an associative array suitable for import into
+   * a biblio node.
+   *
+   * @return array
+   */
+  public function getBiblio()
+  {
+    if (empty($this->biblio)) {
+        if (variable_get('biblio_auto_citekey', 1) ) {
+          $citekey = '';
+        }
+        else {
+          $citekey = $this->id;
+        }
+
+        // Attempts to extract the name of the journal from MedlineTA if
+        // available.
+        if (!empty($this->article->MedlineJournalInfo->MedlineTA)) {
+          $journal = (string)$this->article->MedlineJournalInfo->MedlineTA;
+        }
+        elseif (!empty($this->article->Article->Journal->ISOAbbreviation)) {
+          $journal = (string)$this->article->Article->Journal->ISOAbbreviation;
+        }
+        else {
+          $journal = (string)$this->article->Article->Journal->Title;
+        }
+
+        $this->biblio = array(
+        'title'           => (string)$this->article->Article->ArticleTitle,
+        'biblio_citekey'  => $citekey,
+        'biblio_pubmed_id' => $this->id,
+        'biblio_pubmed_md5' => $this->md5,
+        'biblio_contributors' => $this->contributors(),
+        // MedlineCitations are always articles from journals or books
+        'biblio_type'     => 102,
+        'biblio_date'     => $this->date(),
+        'biblio_year'     => substr($this->date(), 0, 4),
+        'biblio_secondary_title' => $journal,
+        'biblio_alternate_title' => (string)$this->article->Article->Journal->ISOAbbreviation,
+        'biblio_volume'   => (string)$this->article->Article->Journal->JournalIssue->Volume,
+        'biblio_issue'    => (string)$this->article->Article->Journal->JournalIssue->Issue,
+        'biblio_issn'     => (string)$this->article->Article->Journal->ISSN,
+        'biblio_pages'    => (string)$this->article->Article->Pagination->MedlinePgn,
+        'biblio_abst_e'   => $this->abst(),
+        'biblio_custom1'  => "http://www.ncbi.nlm.nih.gov/pubmed/{$this->id}?dopt=Abstract",
+        'biblio_keywords' => $this->keywords(),
+        'biblio_lang'     => $this->lang(),
+      );
+
+      $doi = $this->article->xpath('.//ELocationID[@EIdType="doi"]/text()');
+      if (empty($doi)) {
+        $doi = $this->pubmeddata->xpath('.//ArticleId[@IdType="doi"]/text()');
+      }
+      if (!empty($doi)) {
+        $this->biblio['biblio_doi'] = (string)$doi[0];
+      }
+
+      $pmcid = $this->pubmeddata->xpath('.//ArticleId[@IdType="pmc"]/text()');
+      if (!empty($pmcid)) {
+        $this->biblio['biblio_pmcid'] = (string)$pmcid[0];
+      }
+
+      $grants = $this->grants();
+      if (!empty($grants)) {
+        $this->biblio['biblio_pubmed_grants'] = $grants;
+      }
+    }
+
+    return $this->biblio;
+  }
+
+  /**
+   * Returns the list of contributors for import obtained from the given
+   * MedlineCitation element.
+   *
+   * @return array
+   *   the contributors of the article
+   */
+  private function contributors()
+  {
+    $contributors = array();
+
+    if (isset($this->article->Article->AuthorList->Author)) {
+      foreach ($this->article->Article->AuthorList->Author as $author) {
+        $name = '';
+        if (isset($author->CollectiveName)) {
+          $category = 5; // corporate author
+          $name = (string)$author->CollectiveName;
+        } else {
+          $category = 1; //primary (human) author
+          $lastname = (string)$author->LastName;
+          if (isset($author->ForeName)) {
+            $name = $lastname . ', ' . (string)$author->ForeName;
+          } elseif (isset($author->FirstName)) {
+            $name = $lastname . ', ' . (string)$author->FirstName;
+          } elseif (isset($author->Initials)) {
+            $name = $lastname . ', ' . (string)$author->Initials;
+          }
+        }
+        if (!empty($name)) {
+          $contributors[] = array('name' => $name, 'auth_category' => $category);
+        }
+      }
+    }
+
+    return $contributors;
+  }
+
+  private function grants() {
+    $grants = array();
+    if (isset($this->article->Article->GrantList->Grant)) {
+      foreach ($this->article->Article->GrantList->Grant as $grant) {
+         $grants[] = array('grantid' => (string)$grant->GrantID,
+                           'acronym' => (string)$grant->Acronym,
+                           'agency'  => (string)$grant->Agency,
+                           'country' => (string)$grant->Country
+                     );
+      }
+    }
+    return $grants;
+  }
+
+  /**
+   * Returns the publication date obtained from the given MedlineCitation's
+   * PubDate element. See the reference documentation for possible values:
+   * http://www.nlm.nih.gov/bsd/licensee/elements_descriptions.html#pubdate
+   * According to the above source it always begins with a four digit year.
+   *
+   * @return string
+   *   the publication date of the article
+   */
+  private function date()
+  {
+    $pubDate = $this->article->Article->Journal->JournalIssue->PubDate;
+
+    if (isset($pubDate->MedlineDate)) {
+      $date = (string)$pubDate->MedlineDate;
+    } else {
+      $date = implode(' ', (array)$pubDate);
+    }
+
+    return $date;
+  }
+
+  private function keywords() {
+    $keywords = array();
+    if (isset($this->article->MeshHeadingList->MeshHeading)) {
+      foreach ($this->article->MeshHeadingList->MeshHeading as $heading) {
+        $keywords[] = (string)$heading->DescriptorName;
+      }
+    }
+    return $keywords;
+  }
+
+  private function lang() {
+    if (isset($this->article->Article->Language)) {
+      return (string)$this->article->Article->Language;
+    }
+
+  }
+
+  private function abst() {
+    if (isset($this->article->Article->Abstract)) {
+      $abst = '';
+      foreach ($this->article->Article->Abstract->AbstractText  as $text) {
+        $abst .= "<p>";
+        $attrs = $text->attributes();
+        if (isset($attrs['Label'])) {
+          $abst .= '<b>' . $attrs['Label'] . ': </b>';
+        }
+        $abst .=  (string)$text . '</p>';
+      }
+      return $abst;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/pubmed/biblio_pm.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,101 @@
+<?php
+/*
+ * @file biblio_pm.admin.inc
+ *
+ */
+
+/**
+ * @return multitype:string NULL multitype:NULL  multitype:multitype:multitype:boolean
+ */
+function biblio_pm_settings_form() {
+  $form = array();
+
+  $form['pm_options'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#group'     => 'biblio_settings',
+    '#title' => t('PubMed'),
+    '#description' => t('Please select the action to be performed by the PubMed module when it detects changes to an existing entry.'),
+    '#weight' => 105,
+  );
+  $form['pm_options']['biblio_pm_dup_action'] = array(
+    '#type' => 'radios',
+    '#title' => t('Actions'),
+    '#default_value' => variable_get('biblio_pm_dup_action', 'newrev'),
+    '#options'  => array(
+      'newrev'  => t('Accept and create a new revision of the existing node.'),
+      'replace' => t('Accept and replace the existing node.'),
+      'reject'  => t('Reject and keep the existing node.'),
+    )
+  );
+  $form['pm_options']['biblio_pm_auto_update'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Automatically check for updates via CRON'),
+      '#return_value' => 1,
+      '#default_value' => variable_get('biblio_pm_auto_update', 0),
+      '#description' => t('Entries which were orginally downloaded from PubMed will be periodically checked and updated if the source record has changed.')
+  );
+  $form['pm_options']['pm_cron'] = array(
+      '#type' => 'fieldset',
+      '#collapsible' => FALSE,
+      '#collapsed' => FALSE,
+//      '#group'     => 'pm_options',
+      '#title' => t('CRON Settings'),
+  );
+  $form['pm_options']['pm_cron']['biblio_pm_update_interval'] = array(
+      '#type' => 'select',
+      '#title' => t('PubMed update frequency'),
+      '#default_value' => variable_get('biblio_pm_update_interval', 3600),
+      '#options' => array(
+          0 => t('Every CRON run'),
+          3600 => t('Hourly'),
+          86400 => t('Daily'),
+          604800 => t('Weeekly'),
+      ),
+      '#description' => t('How frequently should we check for updates.'),
+      '#states' => array(
+          'invisible' => array(
+              'input[name="biblio_pm_auto_update"]' => array('checked' => FALSE),
+          ),
+      ),
+  );
+  $form['pm_options']['pm_cron']['biblio_pm_update_limit'] = array(
+      '#type' => 'select',
+      '#title' => t('Number of items to check per CRON run'),
+      '#default_value' => variable_get('biblio_pm_update_limit', 100),
+      '#options' => array(
+          10 => 10,
+          20 => 20,
+          50 => 50,
+          100 => 100,
+          500 => 500,
+      ),
+      '#description' => t('The maximum number of items updated in each pass of a cron maintenance task. If necessary, reduce the number of items to prevent timeouts and memory errors while updating.'),
+      '#states' => array(
+          'invisible' => array(
+              'input[name="biblio_pm_auto_update"]' => array('checked' => FALSE),
+          ),
+      ),
+  );
+  $form['pm_options']['pm_cron']['biblio_pm_age_limit'] = array(
+      '#type' => 'select',
+      '#title' => t('Length of time to wait before re-checking for updates'),
+      '#default_value' => variable_get('biblio_pm_age_limit', 2419200),
+      '#options' => array(
+          86400 => t('1 Day'),
+          604800 => t('1 Week'),
+          2419200 => t('1 Month'),
+          29030400 => t('1 Year'),
+      ),
+      '#description' => t('Wait this long before checking for updates on a given node again.'),
+      '#states' => array(
+          'invisible' => array(
+              'input[name="biblio_pm_auto_update"]' => array('checked' => FALSE),
+          ),
+      ),
+  );
+
+
+   return ($form);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/pubmed/biblio_pm.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Biblio - PubMed
+description = Provides PubMed import and search to the Biblio module.
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = EntrezClient.php
+files[] = EntrezPubmedArticle.php
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/pubmed/biblio_pm.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,158 @@
+<?php
+/**
+ * @file
+ * Database table creation for biblio_pm module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function biblio_pm_install() {
+}
+
+function biblio_pm_uninstall() {
+  variable_del('biblio_pm_dup_action');
+  variable_del('biblio_pm_auto_update');
+  variable_del('biblio_pm_update_interval');
+  variable_del('biblio_pm_update_limit');
+  variable_del('biblio_pm_age_limit');
+  variable_del('biblio_pm_update_next_execution');
+
+}
+
+function biblio_pm_enable() {
+  biblio_pm_set_system_weight();
+}
+
+function biblio_pm_set_system_weight() {
+  db_update('system')
+    ->fields(array('weight' => 19))
+    ->condition('name', 'biblio_pm')
+    ->execute();
+}
+
+/**
+ * Implementation of hook_schema().
+ *
+ * Note:  Pro Drupal Development models use of t() to translate 'description'
+ * for field definitions, but Drupal core does not use them.  We follow core.
+ */
+function biblio_pm_schema() {
+  $schema = array();
+  $schema['biblio_pubmed'] = array(
+    'fields' => array(
+      'biblio_pubmed_id' => array(
+        'type'     => 'int',
+        'not null' => TRUE
+      ),
+      'biblio_pmcid' => array(
+        'type'     => 'varchar',
+        'length' => 20,
+      ),
+        'nid' => array(
+        'type' => 'int',
+        'not null' => TRUE
+      ),
+      'biblio_pubmed_md5' => array(
+        'type' => 'char',
+        'length' => 32,
+        'not null' => TRUE
+      ),
+      'biblio_pm_changed' => array(
+        'description' => 'The Unix timestamp when the pmid was most recently saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0
+      ),
+    ),
+    'primary key' => array('nid'),
+  );
+
+  $schema['biblio_pubmed_grant_info'] = array(
+    'fields' => array(
+      'id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+      ),
+      'nid' => array(
+        'type' => 'int',
+        'not null' => TRUE
+      ),
+        'biblio_pubmed_id' => array(
+        'type'     => 'int',
+        'not null' => TRUE
+      ),
+      'grantid' => array(
+        'type'     => 'varchar',
+        'length' => 255,
+      ),
+      'acronym' => array(
+        'type'     => 'varchar',
+        'length' => 2,
+      ),
+      'agency' => array(
+        'type'     => 'varchar',
+        'length' => 255,
+      ),
+      'country' => array(
+        'type'     => 'varchar',
+        'length' => 255,
+      ),
+    ),
+    'primary key' => array('id'),
+  );
+  return $schema;
+}
+
+
+/**
+*
+* UPDATES
+*
+*/
+
+
+/**
+*
+* add two new fields to the biblio_pubmed table
+*
+*/
+
+function biblio_pm_update_7001() {
+  $spec =  array(
+    'description' => 'The Unix timestamp when the pmid was most recently saved.',
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0
+  );
+  db_add_field('biblio_pubmed', 'biblio_pm_changed', $spec);
+  $spec =  array(
+    'type'     => 'int',
+    'not null' => TRUE,
+    'default'  => 0,
+  );
+  db_add_field('biblio_pubmed', 'biblio_pmcid', $spec);
+}
+/**
+*
+* change field type for biblio_pmcid field to the biblio_pubmed table
+*
+*/
+
+function biblio_pm_update_7002() {
+  $spec =  array(
+    'type'     => 'varchar',
+    'length'   => 20,
+    'not null' => FALSE,
+  );
+  db_change_field('biblio_pubmed', 'biblio_pmcid', 'biblio_pmcid', $spec);
+}
+/**
+ * Add a new table 'biblio_pubmed_grant_info'
+ */
+function biblio_pm_update_7004() {
+  $schema = biblio_pm_schema();
+  $spec = $schema['biblio_pubmed_grant_info'];
+  db_create_table('biblio_pubmed_grant_info', $spec);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/pubmed/biblio_pm.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,525 @@
+<?php
+/*
+ * @file pubmed.module
+ *
+ */
+function biblio_pm_cron() {
+  if (variable_get('biblio_pm_auto_update', 0)) {
+    module_load_include('inc', 'biblio', 'includes/biblio.import.export');
+    $interval    = variable_get('biblio_pm_update_interval', 3600);    // defaults to once per hour
+    $count_limit = variable_get('biblio_pm_update_limit', 100);         // only update 100 at a time
+    $age         = variable_get('biblio_pm_age_limit', 2419200); // defaults to one month since last update
+    $age_limit   = time() - $age;
+
+    if (time() >= variable_get('biblio_pm_update_next_execution', 0)) {
+      $ids = array();
+      $result = db_select('biblio_pubmed', 'bpm')
+          ->fields('bpm', array('nid', 'biblio_pubmed_id'))
+          ->condition('biblio_pm_changed', $age_limit, '<')
+          ->orderBy('nid', 'ASC')
+          ->range(0, $count_limit)
+          ->execute();
+      foreach ($result as $pm) {
+        $ids[$pm->nid] = $pm->biblio_pubmed_id;
+      }
+      if (count($ids)) {
+
+        list($nids, $dups) = biblio_pm_import_ids($ids);
+
+        if (count($nids)) {
+          foreach ($nids as $nid) {
+            $message = '';
+            $message = t('!nid was updated due to changes originating at !url', array(
+                '!nid' => l($nid, 'node/' . $nid),
+                '!url' => l(t('PubMed'), 'http://www.ncbi.nlm.nih.gov/pubmed/' . $ids[$nid]),
+              )
+            );
+            watchdog('biblio_pm', $message, array(), WATCHDOG_WARNING);
+          }
+        }
+
+        if (count($dups)) {
+          $count = count($dups);
+          $message = format_plural($count, 'One duplicate PubMed entry was checked, but no changes were found.',
+              '@count PubMed entries were checked, but no changes were found.');
+          watchdog('biblio_pm', $message, array('@count' => $count), WATCHDOG_INFO);
+
+          $now = time();
+
+          db_update('biblio_pubmed')
+            ->fields(array('biblio_pm_changed' => $now))
+            ->condition('nid', $dups, 'IN')
+            ->execute();
+        }
+      }
+      else {
+        $message = t('There were no PubMed entries older than @age to check.', array(
+                     '@age' => format_interval($age))
+                    );
+      }
+      watchdog('biblio_pm', $message, array(), WATCHDOG_INFO);
+      variable_set('biblio_pm_update_next_execution', time() + $interval);
+    }
+  }
+}
+
+function biblio_pm_form_biblio_admin_settings_alter(&$form, &$form_state) {
+  module_load_include('inc', 'biblio_pm', 'biblio_pm.admin');
+  $form += biblio_pm_settings_form();
+}
+
+function biblio_pm_form_biblio_node_form_alter(&$form, &$form_state, $form_id) {
+
+  if (($form_id == 'biblio_node_form') && isset($form_state['biblio_fields'])) {
+
+     if (isset($form_state['values']['biblio_pubmed_id'])) {
+        $default_pubmed_id = $form_state['values']['biblio_pubmed_id'];
+     }
+     elseif (isset($form_state['node']->biblio_pubmed_id))  {
+        $default_pubmed_id = $form_state['node']->biblio_pubmed_id ;
+     }
+     else {
+        $default_pubmed_id = '';
+     }
+
+     if (isset($form_state['values']['biblio_pmcid'])) {
+        $default_pmcid = $form_state['values']['biblio_pmcid'];
+     }
+     elseif (isset($form_state['node']->biblio_pmcid))  {
+        $default_pmcid = $form_state['node']->biblio_pmcid ;
+     }
+     else {
+        $default_pmcid = '';
+     }
+
+     $form['biblio_tabs'][4]['biblio_pubmed_id'] = array(
+        '#type' => 'textfield',
+        '#title' => t('PMID'),
+        '#required' => FALSE,
+        '#description' => t('PubMed ID'),
+        '#default_value' => $default_pubmed_id,
+        '#size' => 50,
+        '#maxlength' => 50,
+      );
+
+
+     $form['biblio_tabs'][4]['biblio_pmcid'] = array(
+        '#type' => 'textfield',
+        '#title' => t('PMCID'),
+        '#required' => FALSE,
+        '#description' => t('PubMed Central ID'),
+        '#default_value' => $default_pmcid,
+        '#size' => 50,
+        '#maxlength' => 50,
+      );
+
+  }
+  if ((!isset($form_state['biblio_type']) || empty($form_state['biblio_type'])) && !isset($form_state['node']->nid)) {
+    $form['biblio_pubmed_lookup'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('PubMed Lookup'),
+        '#weight' => -20,
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+    );
+
+    $form['biblio_pubmed_lookup']['PMID'] = array(
+        '#type' => 'textfield',
+        '#title' => t('PubMed ID'),
+        '#required' => FALSE,
+        '#default_value' => '',
+        '#description' => t('Enter a PubMed ID</b>'),
+        '#size' => 60,
+        '#maxlength' => 255,
+        '#weight' => -4
+    );
+    $form['biblio_pubmed_lookup']['pubmed_submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Populate using PubMed'),
+        '#submit' => array('biblio_pm_form_biblio_node_form_submit')
+    );
+   // $form['#submit'] = array_merge(array('biblio_pm_form_biblio_node_form_submit'), isset($form['#submit'])?$form['#submit']:array()); // put my validator first
+  }
+  if (isset($form_state['values']['biblio_pubmed_id'])) {
+    $form['biblio_pubmed_id'] = array('#type' => 'value', '#value' => $form_state['values']['biblio_pubmed_id']);
+  }
+  if (isset($form_state['values']['biblio_pubmed_md5'])) {
+    $form['biblio_pubmed_md5'] = array('#type' => 'value', '#value' => $form_state['values']['biblio_pubmed_md5']);
+  }
+  if (isset($form_state['values']['biblio_pmcid'])) {
+    $form['biblio_pmcid'] = array('#type' => 'value', '#value' => $form_state['values']['biblio_pmcid']);
+  }
+  if (isset($form_state['values']['biblio_pubmed_grants'])) {
+    $form['biblio_pubmed_grants'] = array('#type' => 'value', '#value' => $form_state['values']['biblio_pubmed_grants']);
+  }
+
+}
+
+function biblio_pm_form_biblio_node_form_submit($form, &$form_state) {
+  $node_data = array();
+  if (strlen($pmid = $form_state['values']['PMID'])) {
+    if (!($dup = biblio_pm_check_pmid($pmid))) {
+      module_load_include('php', 'biblio_pm', 'EntrezClient');
+      module_load_include('php', 'biblio_pm', 'EntrezPubmedArticle');
+      $Eclient = new BiblioEntrezClient;
+      try {
+        $result = $Eclient->fetch($pmid);
+      } catch (Exception $e) {
+        form_set_error($e->getMessage());
+      }
+      if (!isset($result->PubmedArticle)) {
+        unset($form_state['values']['biblio_type']);
+        unset($form_state['post']['biblio_type']);
+        form_set_error('PMID', 'No data available for PubMed ID: ' . check_plain($pmid));
+        return;
+      }
+      $data = new BiblioEntrezPubmedArticle($result->PubmedArticle);
+      $node_data = $data->getBiblio();
+    }
+    else {
+      $message = t('The PubMed ID that you are trying to import already exists in the database, see !url', array('!url' => l('node/' . $dup, 'node/' . $dup)));
+      form_set_error('PMID', $message);
+      $form_state['rebuild'] = TRUE;
+      $form_state['submitted'] = FALSE;
+      unset($form_state['values']['biblio_type']);
+    }
+  }
+  if (!empty($node_data)) {
+    $form_state['values'] = array_merge($form_state['values'], $node_data);
+    $form_state['input']['biblio_type'] = $form_state['biblio_type'] = $node_data['biblio_type'];
+    $form_state['input']['biblio_pmcid'] = $form_state['biblio_pmcid'] = isset($node_data['biblio_pmcid']) ? $node_data['biblio_pmcid'] : '';
+    $form_state['input']['biblio_pubmed_id'] = $form_state['biblio_pubmed_id'] = $node_data['biblio_pubmed_id'];
+    $form_state['input']['biblio_pubmed_grants'] = $form_state['biblio_pubmed_grants'] = isset($node_data['biblio_pmcid']) ? $node_data['biblio_pmcid'] : array();
+    $form_state['rebuild'] = TRUE;
+  }
+
+  return;
+}
+
+function biblio_pm_biblio_import_options() {
+  return array(
+    'biblio_pm'  => t('PubMed ID List'),
+    'biblio_pm_xml' => t('PubMed XML')
+  );
+}
+
+function biblio_pm_biblio_import($file, $terms = array(), $batch = FALSE, $session_id = NULL, $save = TRUE, $string = FALSE) {
+  $nids = array();
+  $dups = array();
+  $pmids = file($file->uri, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
+  if (empty($pmids)) {
+    drupal_set_message(t("Could not open PubMed ID file"), 'error');
+    return;
+  }
+  return biblio_pm_import_ids($pmids, $terms, $batch, $session_id);
+}
+
+/**
+ * Imports article(s) from an XML file (exported) from PubMed Central
+ *
+ * @param file object $file
+ * @param array $terms
+ * @param bool $batch
+ * @param string $session_id
+ * @return array
+ */
+function biblio_pm_xml_biblio_import($file, $terms = array(), $batch = FALSE, $session_id = NULL) {
+  libxml_use_internal_errors(true);
+  $xml = @simplexml_load_file($file->uri);
+  if (empty($xml) || isset($xml->body->pre->ERROR)) {
+    drupal_set_message(t("Could not parse file as PubMed XML"), 'error');
+    return;
+  }
+  return _biblio_pm_create_node_from_xml($xml, $terms, $batch, $session_id);
+}
+
+/**
+ * Imports multiple PMIDs
+ *
+ * @param array $pmids
+ * @param array $terms
+ * @param bool $batch
+ * @param string $session_id
+ * @return array:
+ */
+function biblio_pm_import_ids($pmids, $terms = array(), $batch = FALSE, $session_id = NULL) {
+  module_load_include('php', 'biblio_pm', 'EntrezClient');
+  $retmax = 100;
+  $resmax = count($pmids);
+  $start = 0;
+  $Eclient = new BiblioEntrezClient;
+  $Eclient->post($pmids);
+  $Eclient->setReturnMax($retmax);
+  $nids = array();
+  $dups = array();
+  while ($start < $resmax && ($result = $Eclient->fetchRecords($start))) {
+    $start += count($result->xpath('//PubmedArticle'));
+    list($nid, $dup) =  _biblio_pm_create_node_from_xml($result, $terms, $batch, $session_id);
+    $nids = array_merge($nids, $nid);
+    $dups = array_merge($dups, $dup);
+  }
+
+  return array($nids, $dups);
+}
+
+/**
+ * Fetches the article for the given PMID and returns a biblio node object
+ *
+ * Returns an empty node object if the PMID is not found.
+ *
+ * @param int $pmid
+ * @return stdClass $node
+ */
+function biblio_pm_fetch_pmid($pmid) {
+  $node     = new stdClass;
+  $Eclient  = new BiblioEntrezClient;
+  $paser    = new BiblioEntrezPubmedArticle();
+  try {
+    $xml = $Eclient->fetch($pmid);
+  }
+  catch (Exception $e) {
+    return $node;
+  }
+  $articles = $xml->xpath('//PubmedArticle');
+  if (count($articles)) {
+    $node = $paser->setArticle($articles[0])->getBiblioAsObject();
+    if (!empty($node)) {
+      $node->type = 'biblio';
+      node_object_prepare($node);
+    }
+  }
+  return $node;
+}
+
+function _biblio_pm_create_node_from_xml($xml, $terms, $batch, $session_id) {
+  module_load_include('php', 'biblio_pm', 'EntrezPubmedArticle');
+  $nids = array();
+  $dups = array();
+  $node = new stdClass();
+  $data = new BiblioEntrezPubmedArticle();
+
+  foreach ($xml->xpath('//PubmedArticle') as $article) {
+    $node = $data->setArticle($article)->getBiblioAsObject();
+    if (isset($node)) {
+      $dup = biblio_pm_check_md5($node->biblio_pubmed_id, $node->biblio_pubmed_md5);
+      $action = variable_get('biblio_pm_dup_action', 'newrev');
+      if ($dup < 0 && $action == 'newrev') { //entry has be imported before, but may have changed
+        // Load the node in order to preserve all its data and merge the new
+        // data from pubmed.
+        $node = (object) array_merge((array)node_load(-$dup), (array)$node);
+        $node->nid = -$dup;
+        $node->revision = 1;
+        $curr_date = format_date(time());
+        $node->log = t('Automatically updated by the Biblio PubMed module on !date due to changes at !url', array(
+                       '!date' => $curr_date,
+                       '!url' => l('PubMed', 'http://www.ncbi.nlm.nih.gov/pubmed/' . $node->biblio_pubmed_id),
+                       ));
+        $dup = NULL;
+      }
+      if ($dup < 0 && $action == 'replace') { //entry has be imported before, but may have changed
+        $node->nid = -$dup;
+        $existing_node = db_query("SELECT * FROM {node} WHERE nid=:nid", array(':nid' => $node->nid))->fetchObject();
+        $node = (object) array_merge((array)$existing_node, (array)$node);
+        $dup = NULL;
+      }
+      if (!$dup) {
+        // Allows other modules to alter the node before it is being saved. (Note: $article is a SimpleXML object)
+        drupal_alter('biblio_pm_node', $node, $article);
+        biblio_save_node($node, $terms, $batch, $session_id);
+        if (!empty($node->nid)) $nids[] = $node->nid;
+      }
+      else {
+        $dups[] = $dup;
+      }
+      $node = NULL;
+    }
+  }
+  return array($nids, $dups);
+}
+
+function biblio_pm_check_pmid($pmid) {
+    return db_query("SELECT nid FROM {biblio_pubmed} WHERE biblio_pubmed_id = :pmid", array(':pmid' => $pmid))->fetchField();
+}
+
+function biblio_pm_biblio_lookup_link_settings() {
+  return array('pubmed'  => t('PubMed'));
+}
+
+function biblio_pm_biblio_lookup_link($node) {
+  $show_link = variable_get('biblio_lookup_links', array('pubmed' => TRUE));
+  if (!isset($show_link['pubmed']) ||
+      !$show_link['pubmed'] ||
+      !isset($node) ||
+      $node->type != 'biblio' ||
+      !isset($node->biblio_pubmed_id)) {
+    return array();
+  }
+
+  $link  = 'http://www.ncbi.nlm.nih.gov/pubmed/' . $node->biblio_pubmed_id . '?dopt=Abstract';
+  $attrs = array('title' => t("Click to view the PubMed listing for this node"));
+  if (variable_get('biblio_links_target_new_window', NULL)) {
+    $attrs = array_merge($attrs, array('target' => '_blank'));
+  }
+  return array('biblio_pubmed' => array(
+        'title'      => t('PubMed'),
+        'href'       => $link,
+        'attributes' => $attrs,
+  ));
+}
+
+function biblio_pm_node_view($node, $view_mode, $langcode) {
+  if ($node->type == 'biblio' && isset($node->biblio_pubmed_id)) {
+    switch ($view_mode) {
+      case 'full':
+      case 'teaser':
+        $node->content['links']['biblio_pubmed'] = array(
+          '#links' => biblio_pm_biblio_lookup_link($node),
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
+    }
+  }
+}
+
+function biblio_pm_node_delete($node) {
+  if ($node->type != 'biblio') {
+    return;
+  }
+  db_delete('biblio_pubmed')
+    ->condition('nid', $node->nid)
+    ->execute();
+  db_delete('biblio_pubmed_grant_info')
+    ->condition('nid', $node->nid)
+    ->execute();
+}
+
+
+function biblio_pm_node_insert($node) {
+  if (isset($node->biblio_pubmed_id) && !empty($node->biblio_pubmed_id)) {
+    $node->biblio_pm_changed = time();
+    drupal_write_record('biblio_pubmed', $node);
+  }
+  if (isset($node->biblio_pubmed_grants) && is_array($node->biblio_pubmed_grants)) {
+    foreach ($node->biblio_pubmed_grants as $grant) {
+      $info = array(
+          'nid' => $node->nid,
+          'biblio_pubmed_id' => $node->biblio_pubmed_id
+      );
+      $info += $grant;
+      drupal_write_record('biblio_pubmed_grant_info', $info);
+    }
+  }
+}
+
+function biblio_pm_node_update($node) {
+  if (isset($node->biblio_pubmed_id) && !empty($node->biblio_pubmed_id)) {
+    $node->biblio_pm_changed = time();
+    drupal_write_record('biblio_pubmed', $node, 'nid');
+  }
+  if (isset($node->biblio_pubmed_grants) && is_array($node->biblio_pubmed_grants) && !empty($node->biblio_pubmed_grants)) {
+    db_delete('biblio_pubmed_grant_info')
+      ->condition('nid', $node->nid)
+      ->execute();
+    foreach ($node->biblio_pubmed_grants as $grant) {
+      $info = array(
+          'nid' => $node->nid,
+          'biblio_pubmed_id' => $node->biblio_pubmed_id
+      );
+      $info += $grant;
+      drupal_write_record('biblio_pubmed_grant_info', $info);
+    }
+  }
+}
+
+function biblio_pm_node_load($nodes, $types) {
+  $result = db_select('biblio_pubmed', 'bpm')
+          ->fields('bpm', array('nid', 'biblio_pubmed_id', 'biblio_pmcid', 'biblio_pubmed_md5'))
+          ->condition('nid', array_keys($nodes))
+          ->execute();
+
+// $result = db_query('SELECT  biblio_pubmed_id  FROM {biblio_pubmed} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)));
+  foreach ($result as $record) {
+    $nodes[$record->nid]->biblio_pubmed_id = $record->biblio_pubmed_id;
+    $nodes[$record->nid]->biblio_pmcid = $record->biblio_pmcid;
+    $nodes[$record->nid]->biblio_pubmed_md5 = $record->biblio_pubmed_md5;
+  }
+
+  $result = db_select('biblio_pubmed_grant_info', 'bpmgi')
+          ->fields('bpmgi')
+          ->condition('nid', array_keys($nodes))
+          ->execute();
+
+  foreach ($result as $record) {
+    $nodes[$record->nid]->biblio_pubmed_grants[] = array(
+                           'grantid' => $record->grantid,
+                           'acronym' => $record->acronym,
+                           'agency'  => $record->agency,
+                           'country' => $record->country);
+  }
+}
+
+function biblio_pm_check_md5($pmid, $md5) {
+  static $pm_md5s = array();
+  static $pm_nids = array();
+  if (empty($pm_md5s)) {
+    $result = db_query("SELECT * FROM {biblio_pubmed} ");
+    foreach ($result as $row ) {
+      $pm_md5s[$row->biblio_pubmed_md5] = $row->nid;
+      $pm_nids[$row->biblio_pubmed_id] = $row->nid;
+    }
+  }
+  if (isset($pm_nids[$pmid]) && isset($pm_md5s[$md5])) { // must be an exact duplicate of an existing node (return the nid)
+      return $pm_md5s[$md5];
+  }
+  elseif (isset($pm_nids[$pmid]) && !isset($pm_md5s[$md5])) { //pmid has been save previously but content must have changed (return negative nid)
+    return -$pm_nids[$pmid];
+  }
+  else {
+    $pm_md5s[$md5]  = TRUE; // gaurd against duplicates in the same import
+    $pm_nids[$pmid] = TRUE;
+    return;
+  }
+}
+
+function biblio_pm_views_api() {
+  return array('api' => 2);
+}
+
+function biblio_pm_biblio_node_table_rows_alter(&$rows, $node) {
+  if (isset($node->biblio_pubmed_id) && !empty($node->biblio_pubmed_id)) {
+    $rows[] = array(
+        array(
+            'data' => t('PubMed ID'),
+            'class' => array('biblio-row-title')
+        ),
+        array(
+            'data' =>  l($node->biblio_pubmed_id, 'http://www.ncbi.nlm.nih.gov/pubmed/' . $node->biblio_pubmed_id . '?dopt=Abstract')
+        )
+    );
+  }
+  if (isset($node->biblio_pmcid) && !empty($node->biblio_pmcid)) {
+    $rows[] = array(
+        array(
+            'data' => t('PubMed Central ID'),
+            'class' => array('biblio-row-title')
+        ),
+        array(
+            'data' =>  check_plain($node->biblio_pmcid)
+        )
+    );
+  }
+  if (isset($node->biblio_pubmed_grants) &&  is_array($node->biblio_pubmed_grants)) {
+
+    foreach ($node->biblio_pubmed_grants as $grant) {
+      $list[] = check_plain(implode(' / ', $grant));
+    }
+    $rows[] = array(
+        array(
+            'data' => t('Grant List'),
+            'class' => array('biblio-row-title')
+        ),
+        array(
+            'data' =>  implode('<br>', $list)
+        )
+    );
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/pubmed/biblio_pm.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,157 @@
+<?php
+function biblio_pm_views_data() {
+
+  $data['biblio_pubmed']['table']['group']  = t('Biblio');
+  $data['biblio_pubmed']['table']['base']  = array(
+      'field' => 'nid',
+      'title' => t('PubMed Table'),
+      'help' => t('This table contains PubMed Identifiers'),
+      'weight' => 10,
+  );
+
+  $data['biblio_pubmed']['table']['join'] = array(
+      'node' => array(
+          'left_field' => 'nid',
+          'field' => 'nid',
+      ),
+  );
+
+  $data['biblio_pubmed']['biblio_pubmed_id'] = array(
+      'title' => t('PubMed ID'),
+      'help' => t('The PubMed ID (http://pubmed.org)'),
+      'field' => array(
+          'handler' => 'views_handler_field',
+          'click sortable' => TRUE,
+      ),
+      'sort' => array(
+          'handler' => 'views_handler_sort',
+      ),
+      'filter' => array(
+          'handler' => 'views_handler_filter_integer',
+      ),
+      'argument' => array(
+          'handler' => 'views_handler_argument_integer',
+      ),
+
+  );
+  $data['biblio_pubmed']['biblio_pmcid'] = array(
+      'title' => t('PMCID'),
+      'help' => t('The PubMed Central ID (http://www.ncbi.nlm.nih.gov/pmc/)'),
+      'field' => array(
+          'handler' => 'views_handler_field',
+          'click sortable' => TRUE,
+      ),
+      'sort' => array(
+          'handler' => 'views_handler_sort',
+      ),
+      'filter' => array(
+          'handler' => 'views_handler_filter_string',
+      ),
+      'argument' => array(
+          'handler' => 'views_handler_argument_string',
+      ),
+
+  );
+  $data['biblio_pubmed_grant_info']['table']['group']  = t('Biblio');
+  $data['biblio_pubmed_grant_info']['table']['base']  = array(
+      'field' => 'nid',
+      'title' => t('PubMed Grant Table'),
+      'help' => t('This table contains Grant information for PubMed entries'),
+      'weight' => 10,
+  );
+
+  $data['biblio_pubmed_grant_info']['table']['join'] = array(
+      'node' => array(
+          'left_field' => 'nid',
+          'field' => 'nid',
+      ),
+  );
+  $data['biblio_pubmed_grant_info']['biblio_pubmed_id'] = array(
+      'title' => t('PubMed ID'),
+      'help' => t('The PubMed ID (http://pubmed.org)'),
+      'field' => array(
+          'handler' => 'views_handler_field',
+          'click sortable' => TRUE,
+      ),
+      'sort' => array(
+          'handler' => 'views_handler_sort',
+      ),
+      'filter' => array(
+          'handler' => 'views_handler_filter_integer',
+      ),
+      'argument' => array(
+          'handler' => 'views_handler_argument_integer',
+      ),
+  );
+  $data['biblio_pubmed_grant_info']['grantid'] = array(
+      'title' => t('PubMed Grant ID'),
+      'help' => t('The PubMed ID (http://pubmed.org)'),
+      'field' => array(
+          'handler' => 'views_handler_field',
+          'click sortable' => TRUE,
+      ),
+      'sort' => array(
+          'handler' => 'views_handler_sort',
+      ),
+      'filter' => array(
+          'handler' => 'views_handler_filter_string',
+      ),
+      'argument' => array(
+          'handler' => 'views_handler_argument_string',
+      ),
+  );
+  $data['biblio_pubmed_grant_info']['acronym'] = array(
+      'title' => t('PubMed Grant Acronym'),
+      'help' => t('The PubMed ID (http://pubmed.org)'),
+      'field' => array(
+          'handler' => 'views_handler_field',
+          'click sortable' => TRUE,
+      ),
+      'sort' => array(
+          'handler' => 'views_handler_sort',
+      ),
+      'filter' => array(
+          'handler' => 'views_handler_filter_string',
+      ),
+      'argument' => array(
+          'handler' => 'views_handler_argument_string',
+      ),
+  );
+  $data['biblio_pubmed_grant_info']['agency'] = array(
+      'title' => t('PubMed Grant Agency'),
+      'help' => t('The PubMed ID (http://pubmed.org)'),
+      'field' => array(
+          'handler' => 'views_handler_field',
+          'click sortable' => TRUE,
+      ),
+      'sort' => array(
+          'handler' => 'views_handler_sort',
+      ),
+      'filter' => array(
+          'handler' => 'views_handler_filter_string',
+      ),
+      'argument' => array(
+          'handler' => 'views_handler_argument_string',
+      ),
+  );
+  $data['biblio_pubmed_grant_info']['country'] = array(
+      'title' => t('PubMed Grant Country'),
+      'help' => t('The PubMed ID (http://pubmed.org)'),
+      'field' => array(
+          'handler' => 'views_handler_field',
+          'click sortable' => TRUE,
+      ),
+      'sort' => array(
+          'handler' => 'views_handler_sort',
+      ),
+      'filter' => array(
+          'handler' => 'views_handler_filter_string',
+      ),
+      'argument' => array(
+          'handler' => 'views_handler_argument_string',
+      ),
+  );
+
+  return $data;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/rtf/biblio_rtf.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Biblio - RTF
+description = Provides Rich Text Format file export to the Biblio module.
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+files[] = rtf_export.inc
+files[] = views/biblio_handler_field_export_link_rtf.inc
+
+; Information added by drupal.org packaging script on 2013-07-20
+version = "7.x-1.0-rc7"
+core = "7.x"
+project = "biblio"
+datestamp = "1374290470"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/rtf/biblio_rtf.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @file
+ * Database table creation for biblio_rtf module.
+ */
+
+/**
+ * Implementation of hook_install().
+ */
+function biblio_rtf_install() {
+}
+
+function biblio_rtf_uninstall() {
+}
+
+function biblio_rtf_enable() {
+  biblio_rtf_set_system_weight();
+}
+
+function biblio_rtf_set_system_weight() {
+  db_update('system')
+    ->fields(array('weight' => 22))
+    ->condition('name', 'biblio_rtf')
+    ->execute();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/rtf/biblio_rtf.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,95 @@
+<?php
+/*
+ * @file biblio_rtf.module
+ *
+ */
+function biblio_rtf_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'biblio_rtf') . '/views',
+  );
+}
+
+function biblio_rtf_biblio_export_options() {
+  return array('rtf' => t('RTF'));
+}
+
+function biblio_rtf_node_view($node, $view_mode) {
+  if ($node->type == 'biblio') {
+    switch ($view_mode) {
+      case 'full':
+      case 'teaser':
+        $links = biblio_rtf_biblio_export_link($node->nid);
+        $node->content['links']['biblio_rtf'] = array(
+          '#links' => $links,
+          '#attributes' => array('class' => array('links', 'inline')),
+        );
+    }
+  }
+}
+function biblio_rtf_link($type, $node = NULL, $teaser = FALSE) {
+  if ($type != 'node' && $node->type != 'biblio') return;
+
+  return biblio_rtf_biblio_export_link($node->nid);
+}
+
+/**
+ * Creates a link to export a node (or view) in rtf format
+ *
+ * @param $base this is the base url (defaults to /biblio)
+ * @param $nid  the node id, if NULL then the current view is exported
+ * @return  a link (<a href=...>rtf</a>)
+ */
+function biblio_rtf_biblio_export_link($nid = NULL, $filter = array()) {
+  $show_link = variable_get('biblio_export_links', array('rtf' => TRUE));
+  if (!isset($show_link['rtf']) || empty($show_link['rtf']) || !biblio_access('export') ) {
+    return array();
+  }
+  $base = variable_get('biblio_base', 'biblio');
+
+  $link = array(
+      'attributes' => array(
+           'title' => t("Click to download the RTF formatted file"),
+            'rel'  => 'nofollow')
+      );
+
+  $link['href']  = (!empty($nid) ? "$base/export/rtf/$nid" : "$base/export/rtf");
+  $link['title'] = t('RTF');
+
+  if (empty($nid) && !empty($filter)) { // add any filters which may be on the current page
+    $link['query'] = $filter;
+  }
+  return array('biblio_rtf' => $link);
+}
+
+function biblio_rtf_biblio_export($nids) {
+  $count = 0;
+  $variables = array(
+    'style_name' => biblio_get_style(),
+  );
+
+  $nodes = node_load_multiple($nids, array(), TRUE);
+  foreach ($nodes as $node) {
+    if (variable_get('biblio_hide_bibtex_braces', 0) ) {
+      $node->title = biblio_remove_brace($node->title);
+    }
+    $count++;
+    $variables['node'] = $node;
+
+    if ($count == 1) {
+      $rtf = new rtf();
+      $rtf->setPaperSize(5);
+      $rtf->setPaperOrientation(1);
+      $rtf->setDefaultFontFace(1);
+      $rtf->setDefaultFontSize(24);
+      $rtf->setAuthor("Biblio 7.x");
+      $rtf->setOperator("");
+      $rtf->setTitle("Biblio RTF Export");
+      $rtf->addColour("#000000");
+    }
+
+    $rtf->addText(filter_xss(theme('biblio_style', $variables) . '<br><br>', array('i', 'b', 'br', 'u', 'p', 'strong', 'em', 'sub', 'sup', 'ul', 'li')));
+  }
+  if ($count > 0) $rtf->getDocument();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/modules/rtf/rtf_export.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,347 @@
+<?php
+
+class rtf {
+
+  // {\colortbl;\red 0\green 0\blue 0;\red 255\green 0\ blue0;\red0 ...}
+  var $colour_table = array();
+  var $colour_rgb;
+  // {\fonttbl{\f0}{\f1}{f...}}
+  var $font_table = array();
+  var $fonts_array = array();
+  var $font_face;
+  var $font_size;
+  // {\info {\title <title>} {\author <author>} {\operator <operator>}}
+  var $info_table = array();
+  var $page_width;
+  var $page_height;
+  var $page_size;
+  var $page_orientation;
+  var $rtf_version;
+  var $tab_width;
+
+  var $document;
+  var $buffer;
+  var $inch;
+  var $cm;
+  var $mm;
+
+  function rtf() {
+    $this->inch = 1440;
+    $this->cm   = 567;
+    $this->mm   = 56.7;
+
+    $this->fonts_array[] = array(
+      "name"    =>  "Arial",
+      "family"  =>  "swiss",
+      "charset" =>  0
+    );
+
+    $this->fonts_array[] = array(
+      "name"    =>  "Times New Roman",
+      "family"  =>  "roman",
+      "charset" =>  0
+    );
+
+    $this->fonts_array[] = array(
+      "name"    =>  "Verdana",
+      "family"  =>  "swiss",
+      "charset" =>  0
+    );
+
+    $this->fonts_array[] = array(
+      "name"    =>  "Symbol",
+      "family"  =>  "roman",
+      "charset" =>  2
+    );
+
+    $this->setDefaultFontFace(0);
+    $this->setDefaultFontSize(24);
+    $this->setPaperSize(5);
+    $this->setPaperOrientation(1);
+    $this->rtf_version = 1;
+    $this->tab_width = 360;
+  }
+
+  function setDefaultFontFace($face) {
+    $this->font_face = $face; // $font is interger
+  }
+
+  function setDefaultFontSize($size) {
+    $this->font_size = $size;
+  }
+
+  function setTitle($title="") {
+    $this->info_table["title"] = $title;
+  }
+
+  function setAuthor($author="") {
+    $this->info_table["author"] = $author;
+  }
+
+  function setOperator($operator="") {
+    $this->info_table["operator"] = $operator;
+  }
+
+  function setPaperSize($size=0) {
+
+    // 1 => Letter (8.5 x 11 inch)
+    // 2 => Legal (8.5 x 14 inch)
+    // 3 => Executive (7.25 x 10.5 inch)
+    // 4 => A3 (297 x 420 mm)
+    // 5 => A4 (210 x 297 mm)
+    // 6 => A5 (148 x 210 mm)
+    // Orientation considered as Portrait
+
+    switch ($size) {
+      case 1:
+        $this->page_width = floor(8.5*$this->inch);
+        $this->page_height = floor(11*$this->inch);
+        $this->page_size = 1;
+        break;
+      case 2:
+        $this->page_width = floor(8.5*$this->inch);
+        $this->page_height = floor(14*$this->inch);
+        $this->page_size = 5;
+        break;
+      case 3:
+        $this->page_width = floor(7.25*$this->inch);
+        $this->page_height = floor(10.5*$this->inch);
+        $this->page_size = 7;
+        break;
+      case 4:
+        $this->page_width = floor(297*$this->mm);
+        $this->page_height = floor(420*$this->mm);
+        $this->page_size = 8;
+        break;
+      case 5:
+      default:
+        $this->page_width = floor(210*$this->mm);
+        $this->page_height = floor(297*$this->mm);
+        $this->page_size = 9;
+        break;
+      case 6:
+        $this->page_width = floor(148*$this->mm);
+        $this->page_height = floor(210*$this->mm);
+        $this->page_size = 10;
+        break;
+    }
+  }
+
+  function setPaperOrientation($orientation=0) {
+    // 1 => Portrait
+    // 2 => Landscape
+
+    switch ($orientation) {
+      case 1:
+      default:
+        $this->page_orientation = 1;
+        break;
+      case 2:
+        $this->page_orientation = 2;
+        break;
+    }
+  }
+
+  function addColour($hexcode) {
+    // Get the RGB values
+    $this->hex2rgb($hexcode);
+
+    // Register in the colour table array
+    $this->colour_table[] = array(
+      "red"    =>  $this->colour_rgb["red"],
+      "green"  =>  $this->colour_rgb["green"],
+      "blue"   =>  $this->colour_rgb["blue"]
+    );
+  }
+
+  // Convert HEX to RGB (#FFFFFF => r255 g255 b255)
+  function hex2rgb($hexcode) {
+    $hexcode = str_replace("#", "", $hexcode);
+    $rgb = array();
+    $rgb["red"] = hexdec(substr($hexcode, 0, 2));
+    $rgb["green"] = hexdec(substr($hexcode, 2, 2));
+    $rgb["blue"] = hexdec(substr($hexcode, 4, 2));
+
+    $this->colour_rgb = $rgb;
+  }
+
+  // Convert newlines into \par
+  function nl2par($text) {
+    $text = str_replace("\n", "\\par ", $text);
+
+    return $text;
+  }
+
+  // Add a text string to the document buffer
+  function addText($text) {
+    $text = str_replace("\n", "", $text);
+    $text = str_replace("\t", "", $text);
+    $text = str_replace("\r", "", $text);
+
+    $this->document .= $text;
+  }
+
+  // Ouput the RTF file
+  function getDocument() {
+    $this->buffer .= "{";
+    // Header
+    $this->buffer .= $this->getHeader();
+    // Font table
+    $this->buffer .= $this->getFontTable();
+    // Colour table
+    $this->buffer .= $this->getColourTable();
+    // File Information
+    $this->buffer .= $this->getInformation();
+    // Default font values
+    $this->buffer .= $this->getDefaultFont();
+    // Page display settings
+    $this->buffer .= $this->getPageSettings();
+    // Parse the text into RTF
+    $this->buffer .= $this->parseDocument();
+    $this->buffer .= "}";
+
+    header("Content-Type: text/enriched\n");
+    header("Content-Disposition: attachment; filename=rtf.rtf");
+    echo $this->buffer;
+  }
+
+  // Header
+  function getHeader() {
+    $header_buffer = "\\rtf{$this->rtf_version}\\ansi\\deff0\\deftab{$this->tab_width}\n\n";
+
+    return $header_buffer;
+  }
+
+  // Font table
+  function getFontTable() {
+
+    $font_buffer = "{\\fonttbl\n";
+    foreach ($this->fonts_array AS $fnum => $farray) {
+      $font_buffer .= "{\\f{$fnum}\\f{$farray['family']}\\fcharset{$farray['charset']} {$farray['name']}}\n";
+    }
+    $font_buffer .= "}\n\n";
+
+    return $font_buffer;
+  }
+
+  // Colour table
+  function getColourTable() {
+    $colour_buffer = "";
+    if (sizeof($this->colour_table) > 0) {
+      $colour_buffer = "{\\colortbl;\n";
+      foreach ($this->colour_table AS $cnum => $carray) {
+        $colour_buffer .= "\\red{$carray['red']}\\green{$carray['green']}\\blue{$carray['blue']};\n";
+      }
+      $colour_buffer .= "}\n\n";
+    }
+
+    return $colour_buffer;
+  }
+
+  // Information
+  function getInformation() {
+    $info_buffer = "";
+    if (sizeof($this->info_table) > 0) {
+      $info_buffer = "{\\info\n";
+      foreach ($this->info_table AS $name => $value) {
+        $info_buffer .= "{\\{$name} {$value}}";
+      }
+      $info_buffer .= "}\n\n";
+    }
+
+    return $info_buffer;
+  }
+
+  // Default font settings
+  function getDefaultFont() {
+    $font_buffer = "\\f{$this->font_face}\\fs{$this->font_size}\n";
+
+    return $font_buffer;
+  }
+
+  // Page display settings
+  function getPageSettings() {
+    if ($this->page_orientation == 1)
+    $page_buffer = "\\paperw{$this->page_width}\\paperh{$this->page_height}\n";
+    else
+    $page_buffer = "\\paperw{$this->page_height}\\paperh{$this->page_width}\\landscape\n";
+
+    $page_buffer .= "\\pgncont\\pgndec\\pgnstarts1\\pgnrestart\n";
+
+    return $page_buffer;
+  }
+
+  // Convert special characters to ASCII
+  function specialCharacters($text) {
+    $text_buffer = "";
+    for ($i = 0; $i < strlen($text); $i++)
+    $text_buffer .= $this->escapeCharacter($text[$i]);
+
+    return $text_buffer;
+  }
+
+  // Convert special characters to ASCII
+  function escapeCharacter($character) {
+    $escaped = "";
+    if (ord($character) >= 0x00 && ord($character) < 0x20) {
+      $escaped = "\\'" . dechex(ord($character));
+    }
+
+    if ((ord($character) >= 0x20 && ord($character) < 0x80) || ord($character) == 0x09 || ord($character) == 0x0A) {
+      $escaped = $character;
+    }
+
+    if (ord($character) >= 0x80 and ord($character) < 0xFF) {
+      $escaped = "\\'" . dechex(ord($character));
+    }
+
+    switch (ord($character)) {
+      case 0x5C:
+      case 0x7B:
+      case 0x7D:
+        $escaped = "\\" . $character;
+        break;
+    }
+
+    return $escaped;
+  }
+
+  // Parse the text input to RTF
+  function parseDocument() {
+    //$doc_buffer = $this->specialCharacters(html_entity_decode($this->document));
+    $doc_buffer = html_entity_decode($this->document, ENT_QUOTES, "utf-8");
+    $doc_buffer = utf8_decode($doc_buffer);
+    $doc_buffer = $this->specialCharacters($doc_buffer);
+    if (preg_match("/<ul>(.*?)<\/ul>/mi", $doc_buffer)) {
+      $doc_buffer = str_replace("<ul>", "", $doc_buffer);
+      $doc_buffer = str_replace("</ul>", "", $doc_buffer);
+      $doc_buffer = preg_replace("/<li>(.*?)<\/li>/mi", "\\f3\\'B7\\tab\\f{$this->font_face} \\1\\par", $doc_buffer);
+    }
+
+    $doc_buffer = preg_replace("/<p>(.*?)<\/p>/mi", "\\1\\par ", $doc_buffer);
+    $doc_buffer = preg_replace("/<strong>(.*?)<\/strong>/mi", "\\b \\1\\b0 ", $doc_buffer);
+    $doc_buffer = preg_replace("/<em>(.*?)<\/em>/mi", "\\i \\1\\i0 ", $doc_buffer);
+    $doc_buffer = preg_replace("/<i>(.*?)<\/i>/mi", "\\i \\1\\i0 ", $doc_buffer);
+    $doc_buffer = preg_replace("/<u>(.*?)<\/u>/mi", "\\ul \\1\\ul0 ", $doc_buffer);
+    $doc_buffer = preg_replace("/<strike>(.*?)<\/strike>/mi", "\\strike \\1\\strike0 ", $doc_buffer);
+    $doc_buffer = preg_replace("/<sub>(.*?)<\/sub>/mi", "{\\sub \\1}", $doc_buffer);
+    $doc_buffer = preg_replace("/<sup>(.*?)<\/sup>/mi", "{\\super \\1}", $doc_buffer);
+
+    //$doc_buffer = preg_replace("/<H1>(.*?)<\/H1>/mi", "\\pard\\qc\\fs40 \\1\\par\\pard\\fs{$this->font_size} ", $doc_buffer);
+    //$doc_buffer = preg_replace("/<H2>(.*?)<\/H2>/mi", "\\pard\\qc\\fs32 \\1\\par\\pard\\fs{$this->font_size} ", $doc_buffer);
+
+    $doc_buffer = preg_replace("/<h1>(.*?)<\/h1>/mi", "\\fs48\\b \\1\\b0\\fs{$this->font_size}\\par ", $doc_buffer);
+    $doc_buffer = preg_replace("/<h2>(.*?)<\/h2>/mi", "\\fs36\\b \\1\\b0\\fs{$this->font_size}\\par ", $doc_buffer);
+    $doc_buffer = preg_replace("/<h3>(.*?)<\/h3>/mi", "\\fs27\\b \\1\\b0\\fs{$this->font_size}\\par ", $doc_buffer);
+
+
+    $doc_buffer = preg_replace("/<hr(.*?)>/i", "\\brdrb\\brdrs\\brdrw30\\brsp20 \\pard\\par ", $doc_buffer);
+    $doc_buffer = str_replace("<br>", "\\par ", $doc_buffer);
+    $doc_buffer = str_replace("<br>", "\\par ", $doc_buffer);
+    $doc_buffer = str_replace("<tab>", "\\tab ", $doc_buffer);
+
+    $doc_buffer = $this->nl2par($doc_buffer);
+
+    return $doc_buffer;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/styles/biblio_style_ama.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,511 @@
+<?php
+// Original File:       ./cite/styles/cite_AMA.php
+// Original Author(s):  Matthias Steffens <mailto:refbase@extracts.de> and
+//                      Richard Karnesky <mailto:karnesky@gmail.com>
+
+// This is a citation style file (which must reside within the 'cite/styles/' sub-directory of your refbase root directory). It contains a
+// version of the 'citeRecord()' function that outputs a reference list from selected records according to the citation style used by
+// the American Medical Association (AMA)
+
+// based on 'cite_Chicago.php'
+
+// TODO: - abstracts, conference proceedings, patents, reports
+//       - book/volume/report/etc titles should be formatted in heading caps
+//       - don't add a dot if the abbreviated journal (or series title) ends with a dot!
+
+// Modified for use in biblio by Ron Jerome
+//
+/**
+ * Get the style information
+ *
+ * @return
+ *   The name of the style
+ */
+function biblio_style_ama_info() {
+  return array(
+    'ama' => 'American Medical Association (AMA)'
+    );
+}
+function biblio_style_ama_author_options() {
+  $author_options = array(
+    'BetweenAuthorsDelimStandard'       => ', ',
+    'BetweenAuthorsDelimLastAuthor'     => ', ',
+    'AuthorsInitialsDelimFirstAuthor'   => ' ',
+    'AuthorsInitialsDelimStandard'      => ' ',
+    'betweenInitialsDelim'              => '',
+    'initialsBeforeAuthorFirstAuthor'   => FALSE,
+    'initialsBeforeAuthorStandard'      => FALSE,
+    'shortenGivenNames'                 => TRUE,
+    'numberOfAuthorsTriggeringEtAl'     => 6,
+    'includeNumberOfAuthors'            => 3,
+    'customStringAfterFirstAuthors'     => ', et al.',
+    'encodeHTML'                        => TRUE
+  );
+
+  return $author_options;
+}
+
+function biblio_style_ama($node) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $output = '';
+  $markupPatternsArray = array("italic-prefix" => "<i>",
+                               "italic-suffix" => "<\/i>",
+                               "endash" => '-');
+  $author_options = biblio_style_ama_author_options();
+  $authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  $editors = biblio_get_contributor_category($node->biblio_contributors, 2);
+
+  if (!empty($authors)) {
+    $authors = theme('biblio_format_authors', array('contributors' => $authors, 'options' => $author_options));
+  }
+  //$editors = theme('biblio_format_authors', array('contributors' => $node->biblio_contributors[2], 'options' => $author_options, 'inline' => $inline));
+  //if (empty($authors)) $authors = theme('biblio_authors', $node->biblio_contributors[5], 'mla', 5, $inline);  // if no authors substitute corp author if available
+  //if (empty($authors)) $authors = '[' . t('Anonymous') . ']';  // use anonymous if we still have nothing.
+  //$output .= '<span class="biblio-authors">' . $authors . "</span>.&nbsp; \n";
+  if (!empty ($node->biblio_citekey)&&(variable_get('biblio_display_citation_key',0))) {
+    $output .= '[' . check_plain($node->biblio_citekey) . '] ';
+  }
+
+  switch ($node->biblio_type) {
+    case 102: //Journal Article
+    case 105: //Newspaper Article
+    case 106: //Magazine Article
+      if (!empty($authors)) {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .=  "</span>";
+      }
+
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors)) $output .= " ";
+        $output .= '"' ;
+        $output .= '<span class="biblio-title-ama">';
+        $url = biblio_get_title_url_info($node);
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+        $output .= '"';
+      }
+
+      // From here on we'll assume that at least either the 'author' or the 'title' field did contain some contents
+      // if this is not the case, the output string will begin with a space. However, any preceding/trailing whitespace will be removed at the cleanup stage (see below)
+
+      if (!empty($node->biblio_alternate_title))      // abbreviated journal name
+      $output .= " <i>" . $node->biblio_alternate_title . "</i>";
+
+      // if there's no abbreviated journal name, we'll use the full journal name
+      elseif (!empty($node->biblio_secondary_title))      // publication (= journal) name
+      $output .= " <i>"  . $node->biblio_secondary_title . "</i>";
+
+      if ($node->biblio_type == 105 || $node->biblio_type == 106 AND !preg_match("/^\d+$/", $node->biblio_volume)) // for newspaper articles (and magazine articles if w/o volume number), volume (=month) and issue (=day) information is printed before the year
+      {
+        if (!empty($node->biblio_volume))      // volume (=month)
+        $output .= ". " . $node->biblio_volume;
+
+        if (!empty($node->biblio_issue))      // issue (=day)
+        $output .= " " . $node->biblio_issue;
+
+        if (!empty($node->biblio_year))      // year
+        $output .= ", " . $node->biblio_year;
+      }
+      else // journal article (or a magazine article with volume numbers)
+      {
+        if (!empty($node->biblio_year))      // year
+        $output .= ". " . $node->biblio_year;
+
+        if (!empty($node->biblio_volume) || !empty($node->biblio_issue))
+        $output .= ";";
+
+        if (!empty($node->biblio_volume))      // volume
+        $output .= $node->biblio_volume;
+
+        if (!empty($node->biblio_issue))      // issue
+        $output .=  "(" . $node->biblio_issue . ")";
+      }
+
+      if (!empty($node->biblio_pages))      // pages
+      {
+        if (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)) // only add ": " if either year, volume, issue, abbrev_journal or publication isn't empty
+        $output .= ":";
+
+        $output .= theme('biblio_page_number', array('orig_page_info' => $node->biblio_pages, 'page_range_delim' => $markupPatternsArray["endash"])); // function 'formatPageInfo()' is defined in 'cite.inc.php'
+      }
+
+      if (isset($node->online_publication)) // this record refers to an online article
+      {
+        // append an optional string (given in 'online_citation') plus the current date and the DOI (or URL):
+
+        $today = date("F j, Y");
+
+        if (!empty($row['online_citation']))      // online_citation
+        {
+          if (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)) // only add ":" or "," if either year, volume, issue, abbrev_journal or publication isn't empty
+          {
+            if (empty($node->biblio_pages))
+            $output .= ":"; // print instead of pages
+            else
+            $output .= ","; // append to pages
+          }
+
+          $output .= $row['online_citation'];
+        }
+
+        if (!empty($row['doi']))      // doi
+        {
+          if (!empty($row['online_citation']) OR (empty($row['online_citation']) AND (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)))) // only add "." if online_citation isn't empty, or else if either year, volume, issue, abbrev_journal or publication isn't empty
+          $output .= ".";
+
+          if ($encodeHTML)
+          $output .= " " . encodeHTML("http://dx.doi.org/" . $row['doi']) . ". Accessed " . $today;
+          else
+          $output .= " " . "http://dx.doi.org/" . $row['doi'] . ". Accessed " . $today;
+        }
+        elseif (!empty($row['url']))      // url
+        {
+          if (!empty($row['online_citation']) OR (empty($row['online_citation']) AND (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)))) // only add "." if online_citation isn't empty, or else if either year, volume, issue, abbrev_journal or publication isn't empty
+          $output .= ".";
+
+          if ($encodeHTML)
+          $output .= " " . encodeHTML($row['url']) . ". Accessed " . $today;
+          else
+          $output .= " " . $row['url'] . ". Accessed " . $today;
+        }
+
+      }
+
+      if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+      break;
+    case 101: //Book Chapter
+    case 103: //Conference Paper
+      if (!empty($authors)) {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors))  $output .= " ";
+
+        $output .= '"<i>' ;
+        $output .= '<span class="biblio-title-ama">';
+        $url = biblio_get_title_url_info($node);
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        $output .= '</i>';
+        if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+        $output .= '"';
+      }
+
+
+      if (!empty($editors)) {
+        $editor_options = array(
+          'BetweenAuthorsDelimStandard'       => ', ',
+          'BetweenAuthorsDelimLastAuthor'     => ', ',
+          'AuthorsInitialsDelimFirstAuthor'   => ' ',
+          'AuthorsInitialsDelimStandard'      => ' ',
+          'betweenInitialsDelim'              => '',
+          'initialsBeforeAuthorFirstAuthor'   => FALSE,
+          'initialsBeforeAuthorStandard'      => FALSE,
+          'shortenGivenNames'                 => TRUE,
+          'numberOfAuthorsTriggeringEtAl'     => 6,
+          'includeNumberOfAuthors'            => 3,
+          'customStringAfterFirstAuthors'     => ' et al.',
+          'encodeHTML'                        => TRUE
+        );
+
+        $editor = theme('biblio_format_authors', array('contributors' => $editors, 'options' => $editor_options));
+
+        $output .= " In: " . $editor . ", ";
+        if (count($editors) > 1) // there are at least two editors (separated by ';')
+        $output .= "eds";
+        else // there's only one editor (or the editor field is malformed with multiple editors but missing ';' separator[s])
+        $output .= "ed";
+      }
+
+      $publication = preg_replace("/[ \r\n]*\(Eds?:[^\)\r\n]*\)/", "", $node->biblio_secondary_title);
+      if (!empty($publication))      // publication
+      {
+        if (!preg_match("/[?!.] *$/", $output))  $output .= ".";
+
+        if (empty($editor))
+        $output .= " In:";
+
+        // TODO: container titles should be formatted in heading caps, however, this doesn't yet work correctly if the publication title contains HTML entities
+        $output .= " <i>" . $publication . "</i>";
+        //        $output .= " " . $markupPatternsArray["italic-prefix"] . changeCase("heading", $publication) . $markupPatternsArray["italic-suffix"]; // function 'changeCase()' is defined in 'include.inc.php'
+      }
+
+      if (!empty($node->biblio_volume))      // volume
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))   $output .= ".";
+
+        $output .= " Vol. " . $node->biblio_volume;
+      }
+
+      if (!empty($node->biblio_edition) && !preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $node->biblio_edition))      // edition
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))
+        $output .= ".";
+
+        if (preg_match("/^\d{1,3}$/", $node->biblio_edition)) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
+        {
+          if ($node->biblio_edition == "2")
+          $editionSuffix = "nd";
+          elseif ($node->biblio_edition == "3")
+          $editionSuffix = "rd";
+          else
+          $editionSuffix = "th";
+        }
+        else
+        $editionSuffix = "";
+
+        if (!preg_match("/( ed\.?| edition)$/i", $node->biblio_edition))
+        $editionSuffix .= " ed.";
+
+        $output .= " " . $node->biblio_edition . $editionSuffix;
+      }
+
+      if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output)) $output .= ".";
+
+      if (!empty($node->biblio_place_published))      // place
+      $output .= " " . $node->biblio_place_published;
+
+      if (!empty($node->biblio_publisher))      // publisher
+      {
+        if (!empty($node->biblio_place_published))
+        $output .= ":";
+
+        $output .= " " . $node->biblio_publisher;
+      }
+
+      if (!empty($node->biblio_year))      // year
+      $output .= "; " . $node->biblio_year;
+
+      if (!empty($node->biblio_pages))      // pages
+      $output .= ":" . theme('biblio_page_number', $node->biblio_pages, $markupPatternsArray["endash"]); // function 'formatPageInfo()' is defined in 'cite.inc.php'
+
+      if (!empty($node->biblio_alternate_title) OR !empty($node->biblio_tertiary_title)) // if there's either a full or an abbreviated series title
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output)) $output .= ".";
+
+        $output .= " ";
+
+        if (!empty($node->biblio_alternate_title))
+        $output .= $node->biblio_alternate_title;      // abbreviated series title
+
+        // if there's no abbreviated series title, we'll use the full series title instead:
+        elseif (!empty($node->biblio_tertiary_title))
+        $output .= $node->biblio_tertiary_title;      // full series title
+
+        if (!empty($node->biblio_volume)||!empty($node->biblio_issue))
+        $output .= " ";
+
+        if (!empty($node->biblio_volume))      // series volume
+        $output .= $node->biblio_volume;
+
+        if (!empty($node->biblio_issue))      // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
+        $output .= "(" . $node->biblio_issue . ")"; // is it correct to format series issues similar to journal article issues?
+      }
+
+      if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+      break;
+
+    default : // all other types
+      //TODO
+      //        if (ereg("[ \r\n]*\(ed\)", $node->author)) // single editor
+      //          $author = $author . ", ed";
+      //        elseif (ereg("[ \r\n]*\(eds\)", $node->author)) // multiple editors
+      //          $author = $author . ", eds";
+
+      if (!empty($authors))      // author
+      {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors))
+        $output .= " ";
+
+        $output .= '<i>';
+        // TODO: book/volume/report/etc titles should be formatted in heading caps, however, this doesn't yet work correctly if the publication title contains HTML entities
+        $output .= '<span class="biblio-title-ama">';
+        $url = biblio_get_title_url_info($node);
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        $output .= '</i>';
+      }
+      if ($node->biblio_type == "Software") // for software, add software label
+      $output .= " [computer program]";
+
+      if (!empty($node->biblio_volume) AND ($node->biblio_type != "Software"))      // volume
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))
+        $output .= ".";
+
+        $output .= " Vol. " . $node->biblio_volume;
+      }
+
+      if (!empty($node->biblio_edition))      // edition
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))
+        $output .= ".";
+
+        if ($row['type'] == "Software")      // software edition (=version)
+        {
+          $output .= " Version " . $node->biblio_edition;
+        }
+        elseif (!preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $node->biblio_edition))      // edition
+        {
+          if (preg_match("/^\d{1,3}$/", $node->biblio_edition)) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
+          {
+            if ($node->biblio_edition == "2")
+            $editionSuffix = "nd";
+            elseif ($node->biblio_edition == "3")
+            $editionSuffix = "rd";
+            else
+            $editionSuffix = "th";
+          }
+          else
+          $editionSuffix = "";
+
+          if (!preg_match("/( ed\.?| edition)$/i", $node->biblio_edition))
+          $editionSuffix .= " ed.";
+
+          $output .= " " . $node->biblio_edition . $editionSuffix;
+        }
+      }
+
+      if (!empty($editors))      // editor (if different from author, see note above regarding the check for ' (ed)' or ' (eds)')
+      {
+
+        $editor_options = array(
+          'BetweenAuthorsDelimStandard'     => ', ',
+          'BetweenAuthorsDelimLastAuthor'   => ', ',
+          'AuthorsInitialsDelimFirstAuthor' => ' ',
+          'AuthorsInitialsDelimStandard'    => ' ',
+          'betweenInitialsDelim'            => '',
+          'initialsBeforeAuthorFirstAuthor' => FALSE,
+          'initialsBeforeAuthorStandard'    => FALSE,
+          'shortenGivenNames'               => TRUE,
+          'numberOfAuthorsTriggeringEtAl'   => 6,
+          'includeNumberOfAuthors'          => 3,
+          'customStringAfterFirstAuthors'   => ' et al.',
+          'encodeHTML'                      => TRUE
+        );
+
+        $editor = theme('biblio_format_authors', array('contributors' => $editors, 'options' => $editor_options));
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+        $output .= " " . $editor;
+        if (count($editors) > 1) // there are at least two editors (separated by ';')
+        $output .= ", eds";
+        else // there's only one editor (or the editor field is malformed with multiple editors but missing ';' separator[s])
+        $output .= ", ed";
+      }
+
+      if (!empty($row['thesis']))      // thesis
+      // TODO: do we need to use the term "[dissertation]" instead of "[Ph.D. thesis]", etc? What about other thesis types then?
+      $output .= " [" . $row['thesis'] . "]";
+
+      if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+      if (!empty($node->biblio_place_published))      // place
+      $output .= " " . $node->biblio_place_published;
+
+      if (!empty($node->biblio_publisher))      // publisher
+      {
+        if (!empty($node->biblio_place_published))
+        $output .= ":";
+
+        $output .= " " . $node->biblio_publisher;
+      }
+
+      $output .= ";";
+
+      if ($node->biblio_type == "Software")      // for software, volume (=month) and issue (=day) information is printed before the year (similar to newspaper articles)
+      {
+        if (!empty($node->biblio_volume))      // volume (=month)
+        $output .= " " . $node->biblio_volume;
+
+        if (!empty($node->biblio_issue))      // issue (=day)
+        $output .= " " . $node->biblio_issue;
+
+        $output .= ",";
+      }
+
+      if (!empty($node->biblio_year))      // year
+      $output .= " " . $node->biblio_year;
+
+      if (!empty($node->biblio_alternate_title) OR !empty($node->biblio_tertiary_title)) // if there's either a full or an abbreviated series title
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+        $output .= " ";
+
+        if (!empty($node->biblio_alternate_title))
+        $output .= $node->biblio_alternate_title;      // abbreviated series title
+
+        // if there's no abbreviated series title, we'll use the full series title instead:
+        elseif (!empty($node->biblio_tertiary_title))
+        $output .= $node->biblio_tertiary_title;      // full series title
+
+        if (!empty($node->biblio_volume)||!empty($node->biblio_issue))
+        $output .= " ";
+
+        if (!empty($node->biblio_volume))      // series volume
+        $output .= $node->biblio_volume;
+
+        if (!empty($node->biblio_issue))      // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
+        $output .= "(" . $node->biblio_issue . ")"; // is it correct to format series issues similar to journal article issues?
+      }
+
+//      if ($row['online_publication'] == "yes" || $row['type'] == "Software") // this record refers to an online article, or a computer program/software
+//      {
+//        // append an optional string (given in 'online_citation') plus the current date and the DOI (or URL):
+//
+//        $today = date("F j, Y");
+//
+//        if (!empty($row['online_citation']))      // online_citation
+//        {
+//          if (!preg_match("/\. *$/", $output)) $output .= ".";
+//
+//          $output .= $row['online_citation'];
+//        }
+//
+//        if (!empty($row['doi']))      // doi
+//        {
+//          if (!preg_match("/\. *$/", $output))  $output .= ".";
+//
+//          if ($encodeHTML)
+//          $output .= " " . encodeHTML("http://dx.doi.org/" . $row['doi']) . ". Accessed " . $today;
+//          else
+//          $output .= " " . "http://dx.doi.org/" . $row['doi'] . ". Accessed " . $today;
+//        }
+//        elseif (!empty($row['url']))      // url
+//        {
+//          if (!preg_match("/\. *$/", $output))  $output .= ".";
+//
+//          if ($encodeHTML)
+//          $output .= " " . encodeHTML($row['url']) . ". Accessed " . $today;
+//          else
+//          $output .= " " . $row['url'] . ". Accessed " . $today;
+//        }
+//
+//      }
+
+      if (!preg_match("/\. *$/", $output))  $output .= ".";
+      break;
+  }
+
+  return filter_xss($output, biblio_get_allowed_tags());
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/styles/biblio_style_apa.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,107 @@
+<?php
+
+/**
+ * Get the style information
+ *
+ * @return
+ *   The name of the style
+ */
+function biblio_style_apa_info() {
+  return array(
+    'apa' => 'American Psychological Association (APA)'
+  );
+}
+
+function biblio_style_apa_author_options() {
+  $author_options = array(
+    'BetweenAuthorsDelimStandard'     =>  ', ',      //4
+    'BetweenAuthorsDelimLastAuthor'   =>  ', & ',    //5
+    'AuthorsInitialsDelimFirstAuthor' =>  ', ',      //7
+    'AuthorsInitialsDelimStandard'    =>  ' ',       //8
+    'betweenInitialsDelim'            =>  '. ',      //9
+    'initialsBeforeAuthorFirstAuthor' =>  FALSE,     //10
+    'initialsBeforeAuthorStandard'    =>  FALSE,     //11
+    'shortenGivenNames'               =>  TRUE,     //12
+    'numberOfAuthorsTriggeringEtAl'   =>  6,         //13
+    'includeNumberOfAuthors'          =>  6,         //14
+    'customStringAfterFirstAuthors'   =>  ', et al.',//15
+    'encodeHTML'                      =>  TRUE
+  );
+  return $author_options;
+}
+
+/**
+ * Apply a bibliographic style to the node
+ *
+ *
+ * @param $node
+ *   An object containing the node data to render
+ *   The base URL of the biblio module (defaults to /biblio)
+ * @return
+ *   The styled biblio entry
+ */
+function biblio_style_apa($node) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $output = '';
+  $authors = '';
+  $author_options = biblio_style_apa_author_options();
+  $primary_authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  $editors = biblio_get_contributor_category($node->biblio_contributors, 2);
+  $corp_authors = biblio_get_contributor_category($node->biblio_contributors, 5);
+
+  if (!empty($primary_authors)) {
+    $authors = theme('biblio_format_authors', array('contributors' => $primary_authors, 'options' => $author_options));
+  }
+  if (empty($authors) && !empty($corp_authors)) {// if no authors substitute corp author if available
+    foreach ($corp_authors as $rank => $author) {
+      $authors .= (empty($authors)) ? '' : ', ';
+      $authors .= (variable_get('biblio_author_links', 1)) ?  theme('biblio_author_link', array('author' => $author)) : $author['name'];
+    }
+  }
+  if (empty($authors)) $authors = '[' . t('Anonymous') . ']';  // use anonymous if we still have nothing.
+  if (!empty ($node->biblio_citekey)&&(variable_get('biblio_display_citation_key',0))) {
+    $output .= '[' . check_plain($node->biblio_citekey) . '] ';
+  }
+  $output .= '<span class="biblio-authors">' . $authors . "</span> \n";
+  $output .= (strrpos($authors, '.') == strlen($authors)) ? ".&nbsp;&nbsp;" : " ";
+  switch ($node->biblio_type) {
+    case 1 : // Journal Article
+    case 2 : //Conference Paper
+    case 3 : // are all
+    case 4 :
+    case 5 :
+    case 6 :
+    case 7 :
+    case 8 :
+    case 9 :
+    default :
+      if (isset ($node->biblio_year)) {
+        $output .= "(" . check_plain($node->biblio_year) . ").&nbsp;&nbsp;";
+      }
+      $output .= '<span class="biblio-title">';
+      $url = biblio_get_title_url_info($node);
+      $output .= l($node->title, $url['link'], $url['options']);
+      $output .= ". </span> \n";
+      $output .= !empty($editors) ? '(' . theme('biblio_format_authors', array('contributors' => $editors, 'options' => $author_options)) . ', Ed.).' : "";
+      $output .= ($node->biblio_secondary_title) ? '<u>' . check_plain($node->biblio_secondary_title) . '. ' : '<u>';
+      $output .= ($node->biblio_volume) ? check_plain($node->biblio_volume) . ($node->biblio_issue ? '</u>(' . check_plain($node->biblio_issue) . '),&nbsp;' : ',</u> ') : '</u> ';
+      //  $output .= ($node->biblio_issue) ? '('. check_plain($node->biblio_issue).')' :'';
+      $output .= ($node->biblio_pages) ? check_plain($node->biblio_pages) . '.' : '';
+      break; // generic
+  }
+  /*  if ($node->biblio_date) $output .= ', '. check_plain($node->biblio_date);
+    if ($node->biblio_number) $output .= ', Number '. check_plain($node->biblio_number);
+
+    if ($node->biblio_place_published) $output .= ', '. check_plain($node->biblio_place_published);
+  */
+  return filter_xss($output, biblio_get_allowed_tags());
+}
+/**
+ *
+ */
+function _apa_format_author($author) {
+  $format = $author['prefix'] . ' ' . $author['lastname'];
+  $format .= !empty ($author['firstname']) ? ' ' . drupal_substr($author['firstname'], 0, 1) . '.' : '';
+  $format .= !empty ($author['initials']) ? $author['initials'] . '.' : '';
+  return $format;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/styles/biblio_style_chicago.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,473 @@
+<?php
+// Original File:       ./cite/styles/cite_Chicago.php
+// Original Author(s):  Matthias Steffens <mailto:refbase@extracts.de> and
+//                      Richard Karnesky <mailto:karnesky@gmail.com>
+//
+
+// This is a citation style file (which must reside within the 'cite/styles/' sub-directory of your refbase root directory). It contains a
+// version of the 'citeRecord()' function that outputs a reference list from selected records according to the citation style documented
+// in the "Chicago Manual of Style" (2003), and Kate Turabian's "Manual for Writer's of Term Papers, Theses, and Dissertations" (1996)
+
+// Modified for use in biblio by Ron Jerome
+//
+/**
+ * Get the style information
+ *
+ * @return
+ *   The name of the style
+ */
+function biblio_style_chicago_info() {
+  return array(
+    'chicago' => 'Chicago'
+    );
+}
+function biblio_style_chicago_author_options() {
+  $author_options = array(
+    'BetweenAuthorsDelimStandard' =>', ',         //4
+    'BetweenAuthorsDelimLastAuthor' => ', and ',  //5
+    'AuthorsInitialsDelimFirstAuthor' => ', ',     //7
+    'AuthorsInitialsDelimStandard' => ' ',         //8
+    'betweenInitialsDelim' => '. ',               //9
+    'initialsBeforeAuthorFirstAuthor' => FALSE,   //10
+    'initialsBeforeAuthorStandard' => TRUE,       //11
+    'shortenGivenNames' => FALSE,                 //12
+    'numberOfAuthorsTriggeringEtAl' => 10,         //13
+    'includeNumberOfAuthors' => 10,                //14
+    'customStringAfterFirstAuthors' => ' et al.',//15
+    'encodeHTML' => TRUE
+  );
+
+  return $author_options;
+}
+/**
+ * Apply a bibliographic style to the node
+ *
+ *
+ * @param $node
+ *   An object containing the node data to render
+ * @return
+ *   The styled biblio entry
+ */
+function biblio_style_chicago($node) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $output = '';
+  $markupPatternsArray = array("italic-prefix" => '<i>',
+                               "italic-suffix" => '<\/i>',
+                               "endash" => '-');
+  $author_options = biblio_style_chicago_author_options();
+  $authors = $editor = '';
+  $primary_authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  $editors = biblio_get_contributor_category($node->biblio_contributors, 2);
+  if (!empty($primary_authors)) {
+    $authors = theme('biblio_format_authors', array('contributors' => $primary_authors, 'options' => $author_options));
+  }
+  //$editors = theme('biblio_format_authors', array('contributors' => $node->biblio_contributors[2], 'options' => $author_options, 'inline' => $inline));
+  //if (empty($authors)) $authors = theme('biblio_authors', $node->biblio_contributors[5], 'mla', 5, $inline);  // if no authors substitute corp author if available
+  //if (empty($authors)) $authors = '[' . t('Anonymous') . ']';  // use anonymous if we still have nothing.
+  //$output .= '<span class="biblio-authors">' . $authors . "</span>.&nbsp; \n";
+  if (!empty ($node->biblio_citekey)&&(variable_get('biblio_display_citation_key',0))) {
+    $output .= '[' . check_plain($node->biblio_citekey) . '] ';
+  }
+
+  switch ($node->biblio_type) {
+    case 102: //Journal Article
+    case 105: //Newspaper Article
+    case 106: //Magazine Article
+      if (!empty($authors)) {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors)) $output .= " ";
+        $output .= '"' ;
+        $output .= '<span class="biblio-title-chicago">';
+        $url = biblio_get_title_url_info($node);
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+        $output .= '"';
+      }
+
+      // From here on we'll assume that at least either the 'author' or the 'title' field did contain some contents
+      // if this is not the case, the output string will begin with a space. However, any preceding/trailing whitespace will be removed at the cleanup stage (see below)
+
+      if (!empty($node->biblio_secondary_title))      // publication (= journal) name
+      $output .= " <i>$node->biblio_secondary_title</i>";
+
+      // if there's no full journal name, we'll use the abbreviated journal name
+      elseif (!empty($node->biblio_alternate_title))      // abbreviated journal name
+      $output .= " <i>$node->biblio_alternate_title</i>";
+
+      if (!empty($node->biblio_volume))      // volume
+      $output .= " " . $node->biblio_volume;
+
+      if (!empty($node->biblio_issue))      // issue
+      $output .=  ", no. " . $node->biblio_issue;
+
+      if (!empty($node->biblio_year))      // year
+      $output .= " (" . $node->biblio_year . ")";
+
+      if (!empty($node->biblio_pages))      // pages
+      {
+        if (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)) // only add ": " if either year, volume, issue, abbrev_journal or publication isn't empty
+        $output .= ": ";
+
+        $output .= theme('biblio_page_number', array('orig_page_info' => $node->biblio_pages)); // function 'formatPageInfo()' is defined in 'cite.inc.php'
+      }
+
+      if (isset($node->online_publication)) // this record refers to an online article
+      {
+        // append an optional string (given in 'online_citation') plus the current date and the DOI (or URL):
+
+        $today = date("F j, Y");
+
+        if (!empty($node->online_citation))      // online_citation
+        {
+          if (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)) // only add "," if either year, volume, issue, abbrev_journal or publication isn't empty
+          {
+            if (empty($node->biblio_pages))
+            $output .= ":"; // print instead of pages
+            else
+            $output .= ","; // append to pages
+          }
+
+          $output .= " " . $node->online_citation;
+        }
+
+        if (!empty($node->doi))      // doi
+        {
+          if (!empty($node->online_citation) OR (empty($node->online_citation) AND (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)))) // only add "." if online_citation isn't empty, or else if either year, volume, issue, abbrev_journal or publication isn't empty
+          $output .= "."; // NOTE: some Chicago examples (e.g. <http://www.lib.berkeley.edu/instruct/guides/chicago-turabianstyle.pdf>) use a comma here (not sure what's correct)
+
+          if ($encodeHTML)
+          $output .= " " . encodeHTML("http://dx.doi.org/" . $node->doi) . " (accessed " . $today . ")";
+          else
+          $output .= " " . "http://dx.doi.org/" . $node->doi . " (accessed " . $today . ")";
+        }
+        elseif (!empty($node->biblio_url))      // url
+        {
+          if (!empty($node->online_citation) OR (empty($node->online_citation) AND (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)))) // only add "." if online_citation isn't empty, or else if either year, volume, issue, abbrev_journal or publication isn't empty
+          $output .= "."; // see note for doi
+
+          if ($encodeHTML)
+          $output .= " " . encodeHTML($node->biblio_url) . " (accessed " . $today . ")";
+          else
+          $output .= " " . $node->biblio_url . " (accessed " . $today . ")";
+        }
+
+      }
+
+      if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+      break;
+    case 101: //Book Chapter
+    case 103: //Conference Paper
+      if (!empty($authors)) {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors))  $output .= " ";
+
+        $output .= '"<i>' ;
+        $output .= '<span class="biblio-title-chicago">';
+        $url = biblio_get_title_url_info($node);
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        $output .= '</i>';
+        if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+        $output .= '"';
+      }
+
+      $publication = preg_replace("/[ \r\n]*\(Eds?:[^\)\r\n]*\)/", "", $node->biblio_secondary_title);
+      if (!empty($publication))      // publication
+      $output .= " In <i>$publication</i>";
+
+
+      // From here on we'll assume that at least either the 'author' or the 'title' field did contain some contents
+      // if this is not the case, the output string will begin with a space. However, any preceding/trailing whitespace will be removed at the cleanup stage (see below)
+
+      if (!empty($editors))      // editor
+      {
+        $editor_options = array(
+          'BetweenAuthorsDelimStandard'     => ', ',
+          'BetweenAuthorsDelimLastAuthor'   => ' and ',
+          'AuthorsInitialsDelimFirstAuthor' => ' ',
+          'AuthorsInitialsDelimStandard'    => ' ',
+          'betweenInitialsDelim'            => '. ',
+          'initialsBeforeAuthorFirstAuthor' => TRUE,
+          'initialsBeforeAuthorStandard'    => TRUE,
+          'shortenGivenNames'               => FALSE,
+          'numberOfAuthorsTriggeringEtAl'   => 10,
+          'includeNumberOfAuthors'          => 10,
+          'customStringAfterFirstAuthors'   => ' et al.',
+          'encodeHTML'                      => TRUE
+        );
+
+        $editor = theme('biblio_format_authors', array('contributors' => $editors, 'options' => $editor_options));
+
+        $output .= ", edited by " . $editor;
+      }
+
+      if (!empty($node->biblio_pages))      // pages
+      $output .= ", " . theme('biblio_page_number', array('orig_page_info' => $node->biblio_pages)); // function 'formatPageInfo()' is defined in 'cite.inc.php'
+
+      if (!empty($node->biblio_edition) && !preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $node->biblio_edition))      // edition
+      {
+        if (!preg_match("/[?!.][ \"<i>]*$/", $output)) $output .= ".";
+
+        if (preg_match("/^\d{1,3}$/", $node->biblio_edition)) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
+        {
+          if ($node->biblio_edition == "2")
+          $editionSuffix = "nd";
+          elseif ($node->biblio_edition == "3")
+          $editionSuffix = "rd";
+          else
+          $editionSuffix = "th";
+        }
+        else
+        $editionSuffix = "";
+
+        if (!preg_match("/( ed\.?| edition)$/i", $node->biblio_edition))
+        $editionSuffix .= " ed.";
+
+        $output .= " " . $node->biblio_edition . $editionSuffix;
+      }
+
+      if (!empty($node->biblio_volume))      // volume
+      {
+        if (!preg_match("/[?!.][ \"<i>]*$/", $output)) $output .= ".";
+
+        $output .= " Vol. " . $node->biblio_volume;
+      }
+
+      if (!empty($node->biblio_alternate_title) OR !empty($node->biblio_tertiary_title)) // if there's either a full or an abbreviated series title
+      {
+        if (!preg_match("/[?!.][ \"<i>]*$/", $output))  $output .= ".";
+
+        $output .= " ";
+
+        if (!empty($node->biblio_alternate_title))
+        $output .= $node->biblio_alternate_title;      // abbreviated series title
+
+        // if there's no abbreviated series title, we'll use the full series title instead:
+        elseif (!empty($node->biblio_tertiary_title))
+        $output .= $node->biblio_tertiary_title;      // full series title
+
+        if (!empty($node->biblio_volume)||!empty($node->biblio_issue))
+        $output .= " ";
+
+        if (!empty($node->biblio_volume))      // series volume
+        $output .= $node->biblio_volume;
+
+ //       if (!empty($node->biblio_issue))      // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
+ //       $output .= ", no. " . $node->biblio_issue; // is it correct to format series issues similar to journal article issues?
+      }
+
+      if (!preg_match("/[?!.][ \"<i>]*$/", $output)) $output .= ".";
+
+      if (!empty($node->biblio_place_published))      // place
+      $output .= " " . $node->biblio_place_published;
+
+      if (!empty($node->biblio_publisher))      // publisher
+      {
+        if (!empty($node->biblio_place_published))
+        $output .= ":";
+
+        $output .= " " . $node->biblio_publisher;
+      }
+
+      if (!empty($node->biblio_year))      // year
+      $output .= ", " . $node->biblio_year;
+
+      if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+      break;
+
+    default : // all other types
+      //TODO
+      //        if (preg_match("[ \r\n]*\(ed\)", $node->author)) // single editor
+      //          $author = $author . ", ed";
+      //        elseif (preg_match("[ \r\n]*\(eds\)", $node->author)) // multiple editors
+      //          $author = $author . ", eds";
+
+      if (!empty($authors))      // author
+      {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+
+      if (!empty($node->title))      // title
+      {
+        $url = biblio_get_title_url_info($node);
+        if (!empty($authors))
+        $output .= " ";
+
+        if (!empty($node->thesis))      // thesis
+        {
+          $output .= '<span class="biblio-title-chicago">';
+          $output .= '"' . l($node->title, $url['link'], $url['options']);
+          $output .= "</span>";
+          if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+          $output .= '"';
+        }
+        else // not a thesis
+        $output .= '<i>';
+        $output .= '<span class="biblio-title-chicago">';
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        $output .= '</i>';
+      }
+      $publication = preg_replace("/[ \r\n]*\(Eds?:[^\)\r\n]*\)/", "", $node->biblio_secondary_title);
+      if (!empty($publication))      // publication
+      $output .= " In <i>$publication</i>";
+
+      if (!empty($editors))      // editor (if different from author, see note above regarding the check for ' (ed)' or ' (eds)')
+      {
+
+        $editor_options = array(
+          'BetweenAuthorsDelimStandard'     => ', ',
+          'BetweenAuthorsDelimLastAuthor'   => ' and ',
+          'AuthorsInitialsDelimFirstAuthor' => ' ',
+          'AuthorsInitialsDelimStandard'    => ' ',
+          'betweenInitialsDelim'            => '. ',
+          'initialsBeforeAuthorFirstAuthor' => TRUE,
+          'initialsBeforeAuthorStandard'    => TRUE,
+          'shortenGivenNames'               => FALSE,
+          'numberOfAuthorsTriggeringEtAl'   => 10,
+          'includeNumberOfAuthors'          => 10,
+          'customStringAfterFirstAuthors'   => ' et al.',
+          'encodeHTML'                      => TRUE
+        );
+
+        $editor = theme('biblio_format_authors', array('contributors' => $editors, 'options' => $editor_options));
+        $output .= ", Edited by " . $editor;
+      }
+
+      if (!empty($node->biblio_edition) && !preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $node->biblio_edition))      // edition
+      {
+        if (!preg_match("/[?!.][ \"<i>]*$/", $output)) $output .= ".";
+
+        if (preg_match("/^\d{1,3}$/", $node->biblio_edition)) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
+        {
+          if ($node->biblio_edition == "2")
+          $editionSuffix = "nd";
+          elseif ($node->biblio_edition == "3")
+          $editionSuffix = "rd";
+          else
+          $editionSuffix = "th";
+        }
+        else
+        $editionSuffix = "";
+
+        if (!preg_match("/( ed\.?| edition)$/i", $node->biblio_edition)) $editionSuffix .= " ed.";
+
+        $output .= " " . $node->biblio_edition . $editionSuffix;
+      }
+
+      if (!empty($node->biblio_volume))      // volume
+      {
+        if (!preg_match("/[?!.][ \"<i>]*$/", $output)) $output .= ".";
+
+        $output .= " Vol. " . $node->biblio_volume;
+      }
+
+      if (!empty($node->biblio_alternate_title) OR !empty($node->biblio_tertiary_title)) // if there's either a full or an abbreviated series title
+      {
+        if (!preg_match("/[?!.][ \"<i>]*$/", $output)) $output .= ".";
+
+        $output .= " ";
+
+        if (!empty($node->biblio_alternate_title))
+        $output .= $node->biblio_alternate_title;      // abbreviated series title
+
+        // if there's no abbreviated series title, we'll use the full series title instead:
+        elseif (!empty($node->biblio_tertiary_title))
+        $output .= $node->biblio_tertiary_title;      // full series title
+
+        if (!empty($node->biblio_volume)||!empty($node->biblio_issue))
+        $output .= " ";
+
+        if (!empty($node->biblio_volume))      // series volume
+        $output .= $node->biblio_volume;
+
+ //       if (!empty($node->biblio_issue))      // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
+ //       $output .= ", no. " . $node->biblio_issue; // is it correct to format series issues similar to journal article issues?
+      }
+
+      if (!empty($node->thesis))      // thesis
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+        $output .= " " . $node->thesis;
+        $output .= ", " . $node->biblio_publisher;
+      }
+      else // not a thesis
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output)) $output .= ".";
+
+        if (!empty($node->biblio_place_published))      // place
+        $output .= " " . $node->biblio_place_published;
+
+        if (!empty($node->biblio_publisher))      // publisher
+        {
+          if (!empty($node->biblio_place_published))
+          $output .= ":";
+
+          $output .= " " . $node->biblio_publisher;
+        }
+      }
+
+      if (!empty($node->biblio_year))      // year
+      $output .= ", ".$node->biblio_year;
+
+//      if ($node->online_publication == "yes") // this record refers to an online article
+//      {
+//        // append an optional string (given in 'online_citation') plus the current date and the DOI (or URL):
+//
+//        $today = date("F j, Y");
+//
+//        if (!empty($node->online_citation))      // online_citation
+//        {
+//          if (!preg_match("/\. *$/", $output))  $output .= ".";
+//
+//          $output .= " " . $node->online_citation;
+//        }
+//
+//        if (!empty($node->doi))      // doi
+//        {
+//          if (!preg_match("/\. *$/", $output)) $output .= ".";
+//
+//          if ($encodeHTML)
+//          $output .= " " . encodeHTML("http://dx.doi.org/" . $node->doi) . " (accessed " . $today . ")";
+//          else
+//          $output .= " " . "http://dx.doi.org/" . $node->doi . " (accessed " . $today . ")";
+//        }
+//        elseif (!empty($node->biblio_url))      // url
+//        {
+//          if (!preg_match("/\. *$/", $output)) $output .= ".";
+//
+//          if ($encodeHTML)
+//          $output .= " " . encodeHTML($node->biblio_url) . " (accessed " . $today . ")";
+//          else
+//          $output .= " " . $node->biblio_url . " (accessed " . $today . ")";
+//        }
+//
+//      }
+
+      if (!preg_match("/\. *$/", $output)) $output .= ".";
+      break;
+  }
+
+  return filter_xss($output, biblio_get_allowed_tags());
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/styles/biblio_style_classic.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,85 @@
+<?php
+
+/**
+ * Get the style information
+ *
+ * @return
+ *   The name of the style
+ */
+function biblio_style_classic_info() {
+  return array(
+    'classic' => 'Classic - This is the original biblio style'
+  );
+}
+function biblio_style_classic_author_options() {
+  $author_options = array(
+    'BetweenAuthorsDelimStandard'     =>  ', ',      //4
+    'BetweenAuthorsDelimLastAuthor'   =>  ', and ',    //5
+    'AuthorsInitialsDelimFirstAuthor' =>  ', ',      //7
+    'AuthorsInitialsDelimStandard'    =>  ' ',       //8
+    'betweenInitialsDelim'            =>  '. ',      //9
+    'initialsBeforeAuthorFirstAuthor' =>  FALSE,     //10
+    'initialsBeforeAuthorStandard'    =>  FALSE,      //11
+    'shortenGivenNames'               =>  FALSE,      //12
+    'numberOfAuthorsTriggeringEtAl'   =>  10,        //13
+    'includeNumberOfAuthors'          =>  10,        //14
+    'customStringAfterFirstAuthors'   =>  ', et al.',//15
+    'encodeHTML'                      =>  TRUE
+  );
+  return $author_options;
+}
+
+/**
+ * Apply a bibliographic style to the node
+ *
+ *
+ * @param $node
+ *   An object containing the node data to render
+ * @return
+ *   The styled biblio entry
+ */
+function biblio_style_classic($node) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $output = '';
+  $author_options = biblio_style_classic_author_options();
+  $authors = $editor = '';
+  $primary_authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  if(!empty($primary_authors)) {
+    $authors = theme('biblio_format_authors', array('contributors' => $primary_authors, 'options' => $author_options));
+  }
+  if (!empty ($node->biblio_citekey)&&(variable_get('biblio_display_citation_key',0))) {
+    $output .= '[' . check_plain($node->biblio_citekey) . '] ';
+  }
+  $output .= '<span class="biblio-title">';
+  $url = biblio_get_title_url_info($node);
+  $output .= l($node->title, $url['link'], $url['options']);
+  $output .= "</span>, \n";
+  $output .= '<span class="biblio-authors">' . $authors . "</span> \n";
+  if ($node->biblio_secondary_title) {
+    $output .= ', ' . check_plain($node->biblio_secondary_title);
+  }
+  if ($node->biblio_date)
+    $output .= ', ' . check_plain($node->biblio_date);
+  if ($node->biblio_volume)
+    $output .= ', Volume ' . check_plain($node->biblio_volume);
+  if ($node->biblio_issue)
+    $output .= ', Issue ' . check_plain($node->biblio_issue);
+  if ($node->biblio_number)
+    $output .= ', Number ' . check_plain($node->biblio_number);
+  if ($node->biblio_place_published)
+    $output .= ', ' . check_plain($node->biblio_place_published);
+  if ($node->biblio_pages)
+    $output .= ', p.' . check_plain($node->biblio_pages);
+  if (isset ($node->biblio_year)) {
+    $output .= ', (' . check_plain($node->biblio_year) . ")\n";
+  }
+  return filter_xss($output, biblio_get_allowed_tags());
+
+}
+
+function _classic_format_author($author) {
+  $format = $author['prefix'] . ' ' . $author['lastname'] . ' ';
+  $format .= !empty ($author['firstname']) ? ' ' . drupal_substr($author['firstname'], 0, 1) : '';
+  $format .= !empty ($author['initials']) ? str_replace(' ', '', $author['initials']) : '';
+  return $format;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/styles/biblio_style_cse.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * Get the style information
+ *
+ * @return
+ *   The name of the style
+ */
+function biblio_style_cse_info() {
+  return array(
+    'cse' => 'Council of Science Editors (CSE)'
+  );
+}
+/**
+ * Apply a bibliographic style to the node
+ *
+ *
+ * @param $node
+ *   An object containing the node data to render
+ * @return
+ *   The styled biblio entry
+ */
+function biblio_style_cse_author_options() {
+  $author_options = array(
+    'BetweenAuthorsDelimStandard'     =>', ',      //4
+    'BetweenAuthorsDelimLastAuthor'   => ', ', //5
+    'AuthorsInitialsDelimFirstAuthor' => ' ',     //7
+    'AuthorsInitialsDelimStandard'    => ' ',      //8
+    'betweenInitialsDelim'            => '',     //9
+    'initialsBeforeAuthorFirstAuthor' => FALSE,    //10
+    'initialsBeforeAuthorStandard'    => FALSE,     //11
+    'shortenGivenNames'               => TRUE,    //12
+    'numberOfAuthorsTriggeringEtAl'   => 10,       //13
+    'includeNumberOfAuthors'          => 10,       //14
+    'customStringAfterFirstAuthors'   => ' et al.',//15
+    'encodeHTML'                      => TRUE
+  );
+  return $author_options;
+}
+
+function biblio_style_cse($node) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $output = $authors = '';
+  if (!empty($node->biblio_contributors)) {
+  $author_options = biblio_style_cse_author_options();
+  $primary_authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  $editors = biblio_get_contributor_category($node->biblio_contributors, 2);
+  $corp_authors = biblio_get_contributor_category($node->biblio_contributors, 5);
+  if (!empty($primary_authors)) {
+    $authors = theme('biblio_format_authors', array('contributors' => $primary_authors, 'options' => $author_options));
+  }
+  if (empty($authors) && !empty($corp_authors)) {// if no authors substitute corp author if available
+    foreach ($corp_authors as $rank => $author) {
+      $authors .= (empty($authors)) ? '' : ', ';
+      $authors .= (variable_get('biblio_author_links', 1)) ?  theme('biblio_author_link', array('author' => $author)) : $author['name'];
+
+    }
+  }
+  }
+  if (empty($authors)) $authors = '[' . t('Anonymous') . ']';  // use anonymous if we still have nothing.
+  if (!empty ($node->biblio_citekey)&&(variable_get('biblio_display_citation_key',0))) {
+    $output .= '[' . check_plain($node->biblio_citekey) . '] ';
+  }
+  $output .= '<span class="biblio-authors">' . $authors . "</span>.&nbsp; \n";
+
+  switch ($node->biblio_type) {
+
+    default :
+      if (isset ($node->biblio_year)) {
+        $output .= check_plain($node->biblio_year) . ".&nbsp;&nbsp;";
+      }
+      $output .= '<span class="biblio-title">';
+      $url = biblio_get_title_url_info($node);
+      $output .= l($node->title, $url['link'], $url['options']);
+      $output .= (strpos($node->title, '?'))? " </span>" : ". </span>";  // if the title ends in a question mark, don't put a period after it.
+      $output .= (!empty ($node->biblio_secondary_title)) ? check_plain($node->biblio_secondary_title) . '. ' : '';
+      $output .= (!empty ($node->biblio_volume))          ? check_plain($node->biblio_volume) : '';
+      $output .= (!empty ($node->biblio_issue))           ? '(' . check_plain($node->biblio_issue) . ')' : '';
+      $output .= (!empty ($node->biblio_pages))           ? ':' . str_replace(" ", "", check_plain($node->biblio_pages)) . '.' : '';
+      break; // generic
+  }
+  /*  if ($node->biblio_date) $output .= ', '. check_plain($node->biblio_date);
+    if ($node->biblio_number) $output .= ', Number '. check_plain($node->biblio_number);
+
+    if ($node->biblio_place_published) $output .= ', '. check_plain($node->biblio_place_published);
+  */
+
+  return filter_xss($output, biblio_get_allowed_tags());
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/styles/biblio_style_ieee.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,111 @@
+<?php
+
+// by Jeffrey Dwoskin
+// A style closer to IEEE format
+// see http://standards.ieee.org/guides/style/section7.html#992
+/**
+ * Get the style information
+ *
+ * @return
+ *   The name of the style
+ */
+function biblio_style_ieee_info() {
+  return array(
+    'ieee' => 'Institute of Electrical and Electronics Engineers (IEEE)'
+  );
+}
+function biblio_style_ieee_author_options() {
+  $author_options = array(
+    'BetweenAuthorsDelimStandard'     =>  ', ',      //4
+    'BetweenAuthorsDelimLastAuthor'   =>  ', and ',    //5
+    'AuthorsInitialsDelimFirstAuthor' =>  ', ',      //7
+    'AuthorsInitialsDelimStandard'    =>  ' ',       //8
+    'betweenInitialsDelim'            =>  '. ',      //9
+    'initialsBeforeAuthorFirstAuthor' =>  FALSE,     //10
+    'initialsBeforeAuthorStandard'    =>  TRUE,      //11
+    'shortenGivenNames'               =>  TRUE,      //12
+    'numberOfAuthorsTriggeringEtAl'   =>  10,        //13
+    'includeNumberOfAuthors'          =>  10,        //14
+    'customStringAfterFirstAuthors'   =>  ', et al.',//15
+    'encodeHTML'                      =>  TRUE
+  );
+  return $author_options;
+}
+
+/**
+ * Apply a bibliographic style to the node
+ *
+ *
+ * @param $node
+ *   An object containing the node data to render
+ * @return
+ *   The styled biblio entry
+ */
+function biblio_style_ieee($node) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $output = '';
+  $author_options = biblio_style_ieee_author_options();
+  $primary_authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  if (!empty($primary_authors)) {
+    $authors = theme('biblio_format_authors', array('contributors' => $primary_authors, 'options' => $author_options));
+  }
+  if (!empty ($node->biblio_citekey)&&(variable_get('biblio_display_citation_key',0))) {
+    $output .= '[' . check_plain($node->biblio_citekey) . '] ';
+  }
+
+  $output .= isset($authors) ? '<span class="biblio-authors">' . $authors . ", </span> \n" : '';
+  switch ($node->biblio_type) {
+    default :
+      $url = biblio_get_title_url_info($node);
+      if (!empty ($node->biblio_secondary_title)) {
+        $output .= '<span class="biblio-title">&quot;';
+        $output .= l($node->title, $url['link'], $url['options']);
+          //$output .= $inline ? l("$node->title", "$base/viewinline/$node->nid") : l("$node->title", "node/$node->nid");
+        $output .= "&quot;, </span> \n";
+        $output .= '<i>' . check_plain($node->biblio_secondary_title) . '</i>';
+      } else {
+        $output .= '<span class="biblio-title"><i>';
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= ", </i></span> \n";
+      }
+      if (!empty ($node->biblio_edition))
+        $output .= ', ' . check_plain($node->biblio_edition);
+      if (!empty ($node->biblio_volume))
+        $output .= ', vol. ' . check_plain($node->biblio_volume);
+      if (!empty ($node->biblio_issue))
+        $output .= ', issue ' . check_plain($node->biblio_issue);
+      if (!empty ($node->biblio_number))
+        $output .= ', no. ' . check_plain($node->biblio_number);
+      if (!empty ($node->biblio_place_published))
+        $output .= ', ' . check_plain($node->biblio_place_published);
+      if (!empty ($node->biblio_publisher)) {
+        $output .= (check_plain($node->biblio_place_published)) ? ', ' : ': ';
+        $output .= check_plain($node->biblio_publisher);
+      }
+      // if a single page instead of a range, should use 'p.' instead of 'pp.'  -- ignoring
+      if (!empty ($node->biblio_pages))
+        $output .= ', pp. ' . check_plain($node->biblio_pages);
+      // if it is a book, year should go before pages instead -- ignoring
+      // for non-books, should also include month of publication (e.g. "Mar. 2006") -- use date instead of year if available
+      if (!empty ($node->biblio_date)) {
+        $output .= ', ' . check_plain($node->biblio_date);
+      }
+      if ((!empty ($node->biblio_year) && !empty ($node->biblio_date) && !strstr($node->biblio_date, $node->biblio_year)) || (!empty ($node->biblio_year) && empty ($node->biblio_date))) {
+        $output .= ', ' . check_plain($node->biblio_year);
+      }
+      $output .= ".\n";
+      break; // generic
+  }
+  /*  if ($node->biblio_date) $output .= ', '. check_plain($node->biblio_date);
+
+  */
+  return filter_xss($output, biblio_get_allowed_tags());
+
+}
+function _ieee_format_author($author) {
+  $format = $author['prefix'];
+  $format .= !empty ($format) ? ' ' . $author['lastname'] . ' ' : $author['lastname'] . ' ';
+  $format .= !empty ($author['firstname']) ? drupal_substr($author['firstname'], 0, 1) . '.' : '';
+  $format .= !empty ($author['initials']) ? $author['initials'] . '.' : '';
+  return $format;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/styles/biblio_style_mla.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,507 @@
+<?php
+// Original File:       ./cite/styles/cite_MLA.php
+// Original Repository: https://refbase.svn.sourceforge.net/svnroot/refbase/trunk/cite/styles/cite_MLA.php $
+// Original Author(s):  Richard Karnesky <mailto:karnesky@gmail.com> and
+//                      Matthias Steffens <mailto:refbase@extracts.de>
+//
+// Modified for use in biblio by Ron Jerome
+//
+/**
+ * Get the style information
+ *
+ * @return
+ *   The name of the style
+ */
+function biblio_style_mla_info() {
+  return array(
+    'mla' => 'Modern Language Association (MLA)'
+    );
+}
+function biblio_style_mla_author_options() {
+  $author_options = array(
+    'BetweenAuthorsDelimStandard' =>', ',         //4
+    'BetweenAuthorsDelimLastAuthor' => ', and ',  //5
+    'AuthorsInitialsDelimFirstAuthor' => ', ',     //7
+    'AuthorsInitialsDelimStandard' => ' ',         //8
+    'betweenInitialsDelim' => '. ',               //9
+    'initialsBeforeAuthorFirstAuthor' => FALSE,   //10
+    'initialsBeforeAuthorStandard' => TRUE,       //11
+    'shortenGivenNames' => FALSE,                 //12
+    'numberOfAuthorsTriggeringEtAl' => 3,         //13
+    'includeNumberOfAuthors' => 1,                //14
+    'customStringAfterFirstAuthors' => ', et al.',//15
+    'encodeHTML' => TRUE
+  );
+
+  return $author_options;
+}
+
+/**
+ * Apply a bibliographic style to the node
+ *
+ *
+ * @param $node
+ *   An object containing the node data to render
+ * @return
+ *   The styled biblio entry
+ */
+function biblio_style_mla($node) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $output = $authors = $editor = '';
+  $author_options = biblio_style_mla_author_options();
+  $primary_authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  $editors = biblio_get_contributor_category($node->biblio_contributors, 2);
+ // $corp_authors = biblio_get_contributor_category($node->biblio_contributors, 5);
+
+  if (!empty($primary_authors)) {
+    $authors = theme('biblio_format_authors', array('contributors' => $primary_authors, 'options' => $author_options));
+  }
+  //if (empty($authors)) $authors = theme('biblio_authors', $node->biblio_contributors->get_category(5), 'mla', 5, $inline);  // if no authors substitute corp author if available
+  //if (empty($authors)) $authors = '[' . t('Anonymous') . ']';  // use anonymous if we still have nothing.
+  //$output .= '<span class="biblio-authors">' . $authors . "</span>.&nbsp; \n";
+  if (!empty ($node->biblio_citekey)&&(variable_get('biblio_display_citation_key',0))) {
+    $output .= '[' . check_plain($node->biblio_citekey) . '] ';
+  }
+
+  switch ($node->biblio_type) {
+    case 102: //Journal Article
+    case 105: //Newspaper Article
+    case 106: //Magazine Article
+      if (!empty($authors)) {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors)) $output .= " ";
+        $output .= '"' ;
+        $output .= '<span class="biblio-title-mla">';
+        $url = biblio_get_title_url_info($node);
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+        $output .= '"';
+      }
+
+      // From here on we'll assume that at least either the 'author' or the 'title' field did contain some contents
+      // if this is not the case, the output string will begin with a space. However, any preceding/trailing whitespace will be removed at the cleanup stage (see below)
+
+      if (!empty($node->biblio_alternate_title)) {      // abbreviated journal name
+        $output .= " " . '<i>' . $node->biblio_alternate_title . '</i>';
+
+        // if there's no abbreviated journal name, we'll use the full journal name
+      }
+      elseif (!empty($node->biblio_secondary_title)) {      // publication (= journal) name
+        $output .= " " . '<i>' . $node->biblio_secondary_title . '</i>';
+      }
+      if (!empty($node->biblio_volume)) {     // volume
+        if (!empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)) {
+          $output .= ".";
+        }
+        $output .= " " . $node->biblio_volume;
+      }
+      if (!empty($node->biblio_issue)) {     // issue
+        $output .=  "." . $node->biblio_issue;
+      }
+      if (!empty($node->biblio_year))      // year
+      {
+        $output .= " (".$node->biblio_year . ")";
+      }
+      // FIXME do something with the online pubs section
+      if (FALSE /*$node->online_publication == "yes"*/) // this record refers to an online article
+      {
+        // instead of any pages info (which normally doesn't exist for online publications) we append
+        // an optional string (given in 'online_citation') plus the current date and the DOI (or URL):
+
+        $today = date("j M. Y");
+
+        if (!empty($node->online_citation))      // online_citation
+        {
+          if (!empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)) // only add ":" if either volume, issue, abbrev_journal or publication isn't empty
+          $output .= ":";
+
+          $output .= " " . $node->online_citation;
+        }
+
+        if (!empty($node->doi))      // doi
+        {
+          if (!empty($node->online_citation) OR (empty($node->online_citation) AND (!empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)))) // only add "." if online_citation isn't empty, or else if either volume, issue, abbrev_journal or publication isn't empty
+          $output .= ".";
+
+          if ($encodeHTML)
+          $output .= " " . $today . encodeHTML(" <http://dx.doi.org/" . $node->doi . ">");
+          else
+          $output .= " " . $today . " <http://dx.doi.org/" . $node->doi . ">";
+        }
+        elseif (!empty($node->url))      // url
+        {
+          if (!empty($node->online_citation) OR (empty($node->online_citation) AND (!empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)))) // only add "." if online_citation isn't empty, or else if either volume, issue, abbrev_journal or publication isn't empty
+          $output .= ".";
+
+          if ($encodeHTML)
+          $output .= " " . $today . encodeHTML(" <" . $node->url . ">");
+          else
+          $output .= " " . $today . " <" . $node->url . ">";
+        }
+
+      }
+      else // $node->online_publication == "no" -> this record refers to a printed article, so we append any pages info instead:
+      {
+        if (!empty($node->biblio_pages))      // pages
+        {
+          if (!empty($node->biblio_year) ||
+          !empty($node->biblio_volume) ||
+          !empty($node->biblio_issue) ||
+          !empty($$node->biblio_alternate_title) ||
+          !empty($node->biblio_secondary_title)) {  // only add ": " if either volume, issue, abbrev_journal or publication isn't empty
+            $output .= ": ";
+          }
+          // TODO: FIXME $output .= formatPageInfo($node->biblio_pages, $markupPatternsArray["endash"]); // function 'formatPageInfo()' is defined in 'cite.inc.php'
+          $output .= theme('biblio_page_number', array('orig_page_info' => $node->biblio_pages));
+        }
+      }
+
+      if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+      break;
+    case 101: //Book Chapter
+    case 103: //Conference Paper
+      if (!empty($authors)) {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+        if (!empty($node->title))      // title
+        {
+          if (!empty($authors))  $output .= " ";
+
+          //$output .= '"<i>' ;
+          $output .= '<span class="biblio-title-mla">';
+          $url = biblio_get_title_url_info($node);
+          $output .= l($node->title, $url['link'], $url['options']);
+          $output .= "</span>";
+         // $output .= '</i>';
+          if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+          $output .= '"';
+        }
+
+        $publication = preg_replace("/[ \r\n]*\(Eds?:[^\)\r\n]*\)/", "", $node->biblio_secondary_title);
+        if (!empty($publication))      // publication
+        $output .= " <i>$publication</i>";
+
+
+        // From here on we'll assume that at least either the 'author' or the 'title' field did contain some contents
+        // if this is not the case, the output string will begin with a space. However, any preceding/trailing whitespace will be removed at the cleanup stage (see below)
+
+        if (!empty($editors))      // editor
+        {
+          $editor_options = array(
+            'BetweenAuthorsDelimStandard' =>', ',         //4
+            'BetweenAuthorsDelimLastAuthor' => ', and ',  //5
+            'AuthorsInitialsDelimFirstAuthor' => ' ',     //7
+            'AuthorsInitialsDelimStandard' => ' ',         //8
+            'betweenInitialsDelim' => '. ',               //9
+            'initialsBeforeAuthorFirstAuthor' => TRUE,   //10
+            'initialsBeforeAuthorStandard' => TRUE,       //11
+            'shortenGivenNames' => FALSE,                 //12
+            'numberOfAuthorsTriggeringEtAl' => 3,         //13
+            'includeNumberOfAuthors' => 1,                //14
+            'customStringAfterFirstAuthors' => ', et al.',//15
+            'encodeHTML' => TRUE
+          );
+          $editor = theme('biblio_format_authors', array('contributors' => $editors, 'options' => $editor_options));
+          _period_if_needed($output);
+
+          if (count($editors) > 1) { // there are at least two editors (separated by ';')
+            $output .= " Eds. " . $editor;
+          }
+          else { // there's only one editor (or the editor field is malformed with multiple editors but missing ';' separator[s])
+            $output .= " Ed. " . $editor;
+          }
+        }
+
+        if (!empty($node->biblio_edition) && !preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $node->biblio_edition))      // edition
+        {
+          _period_if_needed($output);
+
+          if (preg_match("/^\d{1,3}$/", $node->biblio_edition)) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
+          {
+            if ($node->biblio_edition == "2") {
+              $editionSuffix = "nd";
+            }
+            elseif ($node->biblio_edition == "3") {
+              $editionSuffix = "rd";
+            }
+            else {
+              $editionSuffix = "th";
+            }
+          }
+          else {
+            $editionSuffix = "";
+          }
+
+          if (preg_match("/^(Rev\.?|Revised)( ed\.?| edition)?$/i", $node->biblio_edition)) {
+            $node->biblio_edition = "Rev.";
+          }
+          elseif (preg_match("/^(Abr\.?|Abridged)( ed\.?| edition)?$/i", $node->biblio_edition)) {
+            $node->biblio_edition = "Abr.";
+          }
+          if (!preg_match("/( ed\.?| edition)$/i", $node->biblio_edition)) {
+            $editionSuffix .= " ed.";
+          }
+          $output .= " " . $node->biblio_edition . $editionSuffix;
+        }
+
+        if (!empty($node->biblio_volume))      // volume
+        {
+          _period_if_needed($output);
+          $output .= " Vol. " . $node->biblio_volume;
+        }
+
+        if (!empty($node->biblio_alternate_title) || !empty($node->biblio_tertiary_title)) // if there's either a full or an abbreviated series title
+        {
+          _period_if_needed($output);
+          $output .= " ";
+
+          if (!empty($node->biblio_alternate_title)) {
+            $output .= $node->biblio_alternate_title;      // abbreviated series title
+          }
+          // if there's no abbreviated series title, we'll use the full series title instead:
+          elseif (!empty($node->biblio_tertiary_title)) {
+            $output .= $node->biblio_tertiary_title;      // full series title
+          }
+          if (!empty($node->biblio_volume)||!empty($node->biblio_issue)) {
+            $output .= ", ";
+          }
+          if (!empty($node->biblio_volume)) {      // series volume
+            $output .= $node->biblio_volume;
+          }
+          if (!empty($node->biblio_issue)) {      // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
+            $output .= "." . $node->biblio_issue; // is it correct to format series issues similar to journal article issues?
+          }
+        }
+
+        _period_if_needed($output);
+        if (!empty($node->biblio_place_published)) {     // place
+          $output .= " " . $node->biblio_place_published;
+        }
+        if (!empty($node->biblio_publisher))      // publisher
+        {
+          if (!empty($node->biblio_place_published))  $output .= ":";
+          $output .= " " . $node->biblio_publisher. ", " ;
+        }
+
+        if (!empty($node->biblio_year))      // year
+        {
+          $output .= " " . $node->biblio_year .". ";
+        }
+        _period_if_needed($output);
+        if (!empty($node->biblio_pages)) {     // pages
+          $output .= theme('biblio_page_number', array('orig_page_info' => $node->biblio_pages));
+        }
+        _period_if_needed($output);
+        //if (!preg_match("/\. *$/", $output))  $output .= ".";
+
+      break;
+
+    default: // all other types
+
+      if (!empty($authors))      // author
+      {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\.*$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+
+      if (!empty($node->title))      // title
+      {
+        $url = biblio_get_title_url_info($node);
+        if (!empty($authors))
+        $output .= " ";
+
+        if (!empty($node->thesis))      // thesis
+        {
+          $output .= '<span class="biblio-title-mla">';
+          $output .= '"' . l($node->title, $url['link'], $url['options']);
+          $output .= '</span>';
+          if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+          $output .= '"';
+        }
+        else // not a thesis
+        $output .= '<i>';
+        $output .= '<span class="biblio-title-mla">';
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= '</span>';
+        $output .= '</i>';
+      }
+
+      if (!empty($editors))      // editor (if different from author, see note above regarding the check for ' (ed)' or ' (eds)')
+      {
+
+        $editor_options = array(
+          'BetweenAuthorsDelimStandard' =>', ',         //4
+          'BetweenAuthorsDelimLastAuthor' => ', and ',  //5
+          'AuthorsInitialsDelimFirstAuthor' => ' ',     //7
+          'AuthorsInitialsDelimStandard' => ' ',         //8
+          'betweenInitialsDelim' => '. ',               //9
+          'initialsBeforeAuthorFirstAuthor' => TRUE,   //10
+          'initialsBeforeAuthorStandard' => TRUE,       //11
+          'shortenGivenNames' => FALSE,                 //12
+          'numberOfAuthorsTriggeringEtAl' => 3,         //13
+          'includeNumberOfAuthors' => 1,                //14
+          'customStringAfterFirstAuthors' => ', et al.',//15
+          'encodeHTML' => TRUE
+        );
+        $editor = theme('biblio_format_authors', array('contributors' => $editors, 'options' => $editor_options));
+        _period_if_needed($output);
+
+        if (count($editors) > 1) {// there are at least two editors (separated by ';')
+          $output .= " Eds. " . $editor;
+        }
+        else {// there's only one editor (or the editor field is malformed with multiple editors but missing ';' separator[s])
+          $output .= " Ed. " . $editor;
+        }
+      }
+
+      if (!empty($node->biblio_edition) && !preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $node->biblio_edition))      // edition
+      {
+        _period_if_needed($output);
+
+        if (preg_match("/^\d{1,3}$/", $node->biblio_edition)) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
+        {
+          if ($node->biblio_edition == "2") {
+            $editionSuffix = "nd";
+          }
+          elseif ($node->biblio_edition == "3") {
+            $editionSuffix = "rd";
+          }
+          else {
+            $editionSuffix = "th";
+          }
+        }
+        else {
+          $editionSuffix = "";
+        }
+
+        if (preg_match("/^(Rev\.?|Revised)( ed\.?| edition)?$/i", $node->biblio_edition)) {
+          $node->biblio_edition = "Rev.";
+        }
+        elseif (preg_match("/^(Abr\.?|Abridged)( ed\.?| edition)?$/i", $node->biblio_edition)) {
+          $node->biblio_edition = "Abr.";
+        }
+        if (!preg_match("/( ed\.?| edition)$/i", $node->biblio_edition)) {
+          $editionSuffix .= " ed.";
+        }
+        $output .= " " . $node->biblio_edition . $editionSuffix;
+      }
+
+      if (!empty($node->biblio_volume))      // volume
+      {
+        _period_if_needed($output);
+        $output .= " Vol. " . $node->biblio_volume;
+      }
+
+      if (!empty($node->biblio_alternate_title) OR !empty($node->biblio_secondary_title)) // if there's either a full or an abbreviated series title
+      {
+        _period_if_needed($output);
+        $output .= " ";
+
+        if (!empty($node->biblio_alternate_title)) {
+          $output .= $node->biblio_alternate_title;      // abbreviated series title
+        }
+        // if there's no abbreviated series title, we'll use the full series title instead:
+        elseif (!empty($node->biblio_secondary_title)) {
+          $output .= $node->biblio_secondary_title;      // full series title
+        }
+        if (!empty($node->biblio_volume)||!empty($node->biblio_issue)) {
+          $output .= ", ";
+        }
+        if (!empty($node->biblio_volume)) {     // series volume
+          $output .= $node->biblio_volume;
+        }
+        if (!empty($node->biblio_issue)) {     // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
+          $output .= "." . $node->biblio_issue; // is it correct to format series issues similar to journal article issues?
+        }
+      }
+
+      if (!empty($node->thesis))      // thesis (unpublished dissertation)
+      {
+        // TODO: a published dissertation needs to be formatted differently!
+        //       see e.g. example at: <http://web.csustan.edu/english/reuben/pal/append/AXI.HTML>
+
+        _period_if_needed($output);
+
+        // TODO: I've also seen MLA examples that separate thesis name, name of institution and year by dots. ?:-|
+        //       Also, do we need to use the abbreviation "Diss." instead of "Ph.D. thesis"? What about other thesis types then?
+        //       see e.g. <http://www.english.uiuc.edu/cws/wworkshop/writer_resources/citation_styles/mla/unpublished_diss.htm>
+        $output .= " " . $node->thesis;
+        $output .= ", " . $node->biblio_publisher;
+      }
+      else // not a thesis
+      {
+        _period_if_needed($output);
+
+        if (!empty($node->biblio_place_published)) {     // place
+          $output .= " " . $node->biblio_place_published;
+        }
+        if (!empty($node->biblio_publisher))      // publisher
+        {
+          if (!empty($node->biblio_place_published))  $output .= ":";
+          $output .= " " . $node->biblio_publisher;
+        }
+      }
+
+      if (!empty($node->biblio_year)) {     // year
+        $output .= ", ".$node->biblio_year;
+      }
+
+      if (isset($node->online_publication) && $node->online_publication == "yes") // this record refers to an online article
+      {
+        $today = date("j M. Y");
+
+        if (!empty($node->online_citation))      // online_citation
+        {
+          if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+          $output .= " " . $node->online_citation;
+        }
+
+        if (!empty($node->doi))      // doi
+        {
+          if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+          if ($encodeHTML) {
+            $output .= " " . $today . encodeHTML(" <http://dx.doi.org/" . $node->doi . ">");
+          }
+          else {
+            $output .= " " . $today . " <http://dx.doi.org/" . $node->doi . ">";
+          }
+        }
+        elseif (!empty($node->url))      // url
+        {
+          if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+          if ($encodeHTML) {
+            $output .= " " . $today . encodeHTML(" <" . $node->url . ">");
+          }
+          else {
+            $output .= " " . $today . " <" . $node->url . ">";
+          }
+        }
+      }
+
+      if (!preg_match("/\. *$/", $output)) $output .= ".";
+      break;
+  }
+
+  return filter_xss($output, biblio_get_allowed_tags());
+}
+
+function _period_if_needed(&$output) {
+  if (!preg_match("/[?!.][ \"" . '<\/i>' . "]*$/", $output)) $output .= ".";
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/styles/biblio_style_vancouver.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,537 @@
+<?php
+  // Original File:       ./cite/styles/cite_Vancouver.php
+  // Original Author(s):  Matthias Steffens <mailto:refbase@extracts.de>
+
+  // This Vancouver style was modeled after these resources:
+  // <http://www.library.uq.edu.au/training/citation/vancouv.pdf>
+  // <http://library.curtin.edu.au/research_and_information_skills/referencing/vancouver.pdf>
+  // <http://www.icmje.org/index.html> citing: <http://www.nlm.nih.gov/citingmedicine/>
+  // <http://www.nlm.nih.gov/bsd/uniform_requirements.html>
+  // <http://library.sun.ac.za//eng/help/infolit2002/bibvancouver.htm>
+
+  // based on 'cite_AMA.php'
+
+  // NOTES: - In the Vancouver style, the reference list is arranged numerically in the order in which references are cited in the text.
+  //          This isn't currently handled by this style
+  //        - For conference proceedings, you'll currently need to add the place & date of the conference in the proceedings title field
+  //          (e.g. "Proceedings of the 5th Germ Cell Tumour Conference; 2001 Sep 13-15; Leeds, UK").
+
+  // TODO: - abstracts, newspaper/magazine articles, patents & reports?
+  //       - arrange references numerically
+  //       - for newspaper articles, only the beginning page number of an article should be included (see: <http://www.ncbi.nlm.nih.gov/books/bv.fcgi?rid=citmed.section.41496#41607>)
+  //       - where to put (and how to format) editors of whole books that also have an author?
+  //       - see also inline comments labeled with TODO (and NOTE)
+
+
+// Modified for use in biblio by Ron Jerome
+//
+/**
+ * Get the style information
+ *
+ * @return
+ *   The name of the style
+ */
+function biblio_style_vancouver_info() {
+  return array(
+    'vancouver' => 'Vancouver'
+    );
+}
+function biblio_style_vancouver_author_options() {
+  $author_options = array(
+    'BetweenAuthorsDelimStandard'       => ', ',
+    'BetweenAuthorsDelimLastAuthor'     => ', ',
+    'AuthorsInitialsDelimFirstAuthor'   => ' ',
+    'AuthorsInitialsDelimStandard'      => ' ',
+    'betweenInitialsDelim'              => '',
+    'initialsBeforeAuthorFirstAuthor'   => FALSE,
+    'initialsBeforeAuthorStandard'      => FALSE,
+    'numberOfInitialsToKeep'            => 2,
+    'shortenGivenNames'                 => TRUE,
+    'numberOfAuthorsTriggeringEtAl'     => 6,
+    'includeNumberOfAuthors'            => 6,
+    'customStringAfterFirstAuthors'     => ', et al.',
+    'encodeHTML'                        => TRUE
+  );
+
+  return $author_options;
+}
+
+function biblio_style_vancouver($node) {
+  module_load_include('inc', 'biblio', '/includes/biblio.contributors');
+  $output = $authors = $editor = '';
+  $markupPatternsArray = array("italic-prefix" => '<i>',
+                               "italic-suffix" => '<\/i>',
+                               "endash" => '-');
+  $author_options = biblio_style_vancouver_author_options();
+  $primary_authors = biblio_get_contributor_category($node->biblio_contributors, 1);
+  $editors = biblio_get_contributor_category($node->biblio_contributors, 2);
+ // $corp_authors = biblio_get_contributor_category($node->biblio_contributors, 5);
+  if (!empty($primary_authors)) {
+    $authors = theme('biblio_format_authors', array('contributors' => $primary_authors, 'options' => $author_options));
+  }
+  //$editors = theme('biblio_format_authors', array('contributors' => $node->biblio_contributors->get_category(2), 'options' => $author_options, 'inline' => $inline));
+  //if (empty($authors)) $authors = theme('biblio_authors', $node->biblio_contributors->get_category(5), 'mla', 5, $inline);  // if no authors substitute corp author if available
+  //if (empty($authors)) $authors = '[' . t('Anonymous') . ']';  // use anonymous if we still have nothing.
+  //$output .= '<span class="biblio-authors">' . $authors . "</span>.&nbsp; \n";
+  if (!empty ($node->biblio_citekey)&&(variable_get('biblio_display_citation_key',0))) {
+    $output .= '[' . check_plain($node->biblio_citekey) . '] ';
+  }
+
+  switch ($node->biblio_type) {
+    case 102: //Journal Article
+    case 105: //Newspaper Article
+    case 106: //Magazine Article
+      if (!empty($authors)) {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .=  "</span>";
+      }
+
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors)) $output .= " ";
+        $output .= '<span class="biblio-title-vancouver">';
+        $url = biblio_get_title_url_info($node);
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+      }
+
+      // From here on we'll assume that at least either the 'author' or the 'title' field did contain some contents
+      // if this is not the case, the output string will begin with a space. However, any preceding/trailing whitespace will be removed at the cleanup stage (see below)
+
+      if (!empty($node->biblio_alternate_title))      // abbreviated journal name
+        $output .= " " . preg_replace("/\./", "", $node->biblio_alternate_title); // no punctuation marks are used in the abbreviated journal name, just spaces (TODO: smarten regex pattern)
+
+      // if there's no abbreviated journal name, we'll use the full journal name instead:
+      elseif (!empty($node->biblio_secondary_title))      // publication (= journal) name
+        $output .= " " . $node->biblio_secondary_title;
+
+      if (isset($node->online_publication)) // this record refers to an online publication
+        $output .= " [Internet]"; // NOTE: some of the above mentioned resources use "[serial online]", "[serial on the Internet]" or just "[online]" instead
+
+      // NOTE: the formatting of year/volume/issue is meant for journal articles (TODO: newspaper/magazine articles)
+      if (!empty($node->biblio_year))      // year
+        $output .= ". " . $node->biblio_year;
+
+      if (isset($node->online_publication)) // append the current date if this record refers to an online publication
+        $output .= " [cited " . date("Y M j") . "]";
+
+      if (!empty($node->biblio_volume) || !empty($node->biblio_issue))
+        $output .= ";";
+
+      if (!empty($node->biblio_volume))      // volume (=month)
+        $output .= $node->biblio_volume;
+
+      if (!empty($node->biblio_issue))      // issue (=day)
+        $output .=  "(" . $node->biblio_issue . ")";
+
+      if (!empty($node->biblio_pages))      // pages
+      {
+        if (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)) // only add ": " if either year, volume, issue, abbrev_journal or publication isn't empty
+          $output .= ":";
+
+        $output .= theme('biblio_page_number', array('orig_page_info' => $node->biblio_pages,
+                                                     'page_range_delim' => $markupPatternsArray["endash"],
+                                                     'shorten_page_range_end' => TRUE)); // function 'formatPageInfo()' is defined in 'cite.inc.php'
+      }
+
+      if (isset($node->online_publication)) // this record refers to an online publication
+      {
+        // append an optional string (given in 'online_citation') plus the DOI (or URL):
+
+        if (!empty($node->online_citation))      // online_citation
+        {
+          if (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)) // only add ":" or "," if either year, volume, issue, abbrev_journal or publication isn't empty
+          {
+            if (empty($node->biblio_pages))
+              $output .= ":"; // print instead of pages
+            else
+              $output .= ";"; // append to pages (TODO: not sure whether this is correct)
+          }
+
+          $output .= $node->online_citation;
+        }
+
+        if (!empty($node->doi) || !empty($node->url))      // doi OR url
+        {
+          if (!empty($node->online_citation) OR (empty($node->online_citation) AND (!empty($node->biblio_year) || !empty($node->biblio_volume) || !empty($node->biblio_issue) || !empty($node->biblio_alternate_title) || !empty($node->biblio_secondary_title)))) // only add "." if online_citation isn't empty, or else if either year, volume, issue, abbrev_journal or publication isn't empty
+            $output .= ".";
+
+          $output .= " Available from: " . $markupPatternsArray["underline-prefix"]; // NOTE: some of the above mentioned resources use "Available from: URL:http://..." instead
+
+          if (!empty($node->doi))      // doi
+            $uri = "http://dx.doi.org/" . $node->doi;
+          else      // url
+            $uri = $node->url;
+
+          if ($encodeHTML)
+            $output .= encodeHTML($uri);
+          else
+            $output .= $uri;
+
+          $output .= $markupPatternsArray["underline-suffix"];
+        }
+      }
+
+      if (!preg_match("/\. *$/", $output) AND (!isset($node->online_publication)))
+        $output .= "."; // NOTE: the examples in the above mentioned resources differ wildly w.r.t. whether the closing period should be omitted for online publications
+      break;
+    case 101: //Book Chapter
+    case 103: //Conference Paper
+      if (!empty($authors)) {
+        $output .= '<span class="biblio-authors">';
+        $output .= $authors;
+        if (!preg_match("/\. *$/", $authors)) $output .= ".";
+        $output .= '</span>';
+      }
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors))  $output .= " ";
+        $output .= '<span class="biblio-title-vancouver">';
+        $url = biblio_get_title_url_info($node);
+        $output .= l($node->title, $url['link'], $url['options']);
+        $output .= "</span>";
+        if (!preg_match("/[?!.]$/", $node->title)) $output .= ".";
+      }
+
+
+      if (!empty($editors))      // editor
+      {
+        $editor_options = array(
+          'BetweenAuthorsDelimStandard'       => ', ',
+          'BetweenAuthorsDelimLastAuthor'     => ', ',
+          'AuthorsInitialsDelimFirstAuthor'   => ' ',
+          'AuthorsInitialsDelimStandard'      => ' ',
+          'betweenInitialsDelim'              => '',
+          'initialsBeforeAuthorFirstAuthor'   => FALSE,
+          'initialsBeforeAuthorStandard'      => FALSE,
+          'shortenGivenNames'                 => TRUE,
+          'numberOfAuthorsTriggeringEtAl'     => 6,
+          'includeNumberOfAuthors'            => 6,
+          'customStringAfterFirstAuthors'     => ' et al.',
+          'encodeHTML'                        => TRUE
+        );
+
+        $editor = theme('biblio_format_authors', array('contributors' => $editors, 'options' => $editor_options));
+
+        $output .= " In: " . $editor . ", ";
+        if (count($editors) > 1) // there are at least two editors (separated by ';')
+        $output .= "editors";
+        else // there's only one editor (or the editor field is malformed with multiple editors but missing ';' separator[s])
+        $output .= "editor";
+      }
+
+      $publication = preg_replace("/[ \r\n]*\(Eds?:[^\)\r\n]*\)/", "", $node->biblio_secondary_title);
+      if (!empty($publication))      // publication
+      {
+        if (!preg_match("/[?!.] *$/", $output)) $output .= ".";
+
+        if (empty($editor)) $output .= " In:";
+
+        $output .= " " . $publication;
+      }
+
+      if (!empty($node->biblio_volume))      // volume
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output)) $output .= ".";
+
+        $output .= " Vol " . $node->biblio_volume; // TODO: not sure whether this is correct
+      }
+
+      if (!empty($node->biblio_edition) && !preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $node->biblio_edition))      // edition
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+        if (preg_match("/^\d{1,3}$/", $node->biblio_edition)) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
+        {
+          if ($node->biblio_edition == "2")
+            $editionSuffix = "nd";
+          elseif ($node->biblio_edition == "3")
+            $editionSuffix = "rd";
+          else
+            $editionSuffix = "th";
+        }
+        else
+          $editionSuffix = "";
+
+        if (!preg_match("/( ed\.?| edition)$/i", $node->biblio_edition))
+          $editionSuffix .= " ed.";
+
+        $output .= " " . $node->biblio_edition . $editionSuffix;
+      }
+
+      if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+      if (!empty($node->biblio_place_published))      // place
+      {
+//        // for places in the USA, format any two-letter postal code for the state (i.e. ensure upper case & wrap in parens, eg. "Boca Raton (FL)"):
+//        if (preg_match("/(.+?)[$punct$space]+($uspsStateAbbreviations)[$punct$space]*$/i$patternModifiers", $node->biblio_place_published))
+//          $output .= " " . preg_replace("/(.+?)[$punct$space]+($uspsStateAbbreviations)[$punct$space]*$/ie$patternModifiers", "'\\1 ('.strtoupper('\\2').')'", $node->biblio_place_published);
+//        else
+          $output .= " " . $node->biblio_place_published;
+      }
+
+      if (!empty($node->biblio_publisher))      // publisher
+      {
+        if (!empty($node->biblio_place_published))
+          $output .= ":";
+
+        $output .= " " . $node->biblio_publisher;
+      }
+
+      if (!empty($node->biblio_year))      // year
+        $output .= "; " . $node->biblio_year;
+
+      if (!empty($node->biblio_pages))      // pages
+        $output .= ". " . theme_biblio_page_number($node->biblio_pages, $markupPatternsArray["endash"], "p. ", "p. ", "", "", "", "", TRUE); // function 'formatPageInfo()' is defined in 'cite.inc.php'
+        $output .= ". " . theme('biblio_page_number', array('orig_page_info' => $node->biblio_pages,
+                                                     'page_range_delim' => $markupPatternsArray["endash"],
+                                                     'single_page_prefix' => "p. ",
+                                                     'page_range_prefix' => "p. ",
+                                                     'shorten_page_range_end' => TRUE)); // function 'formatPageInfo()' is defined in 'cite.inc.php'
+
+      if (!empty($node->biblio_alternate_title) OR !empty($node->biblio_tertiary_title)) // if there's either a full or an abbreviated series title
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output)) $output .= ".";
+
+        $output .= " (";
+
+        if (!empty($node->biblio_alternate_title))      // abbreviated series title
+          $output .= preg_replace("/\./", "", $node->biblio_alternate_title); // no punctuation marks are used in the abbreviated series title, just spaces (TODO: smarten regex pattern)
+
+        // if there's no abbreviated series title, we'll use the full series title instead:
+        elseif (!empty($node->biblio_tertiary_title))      // full series title
+          $output .= $node->biblio_tertiary_title;
+
+        if (!empty($node->biblio_volume)||!empty($node->biblio_issue))
+          $output .= "; ";
+
+        if (!empty($node->biblio_volume))      // series volume
+          $output .= "vol " . $node->biblio_volume;
+
+        if (!empty($node->biblio_volume) && !empty($node->biblio_issue))
+          $output .= "; "; // TODO: not sure whether this is correct
+
+        if (!empty($node->biblio_issue))      // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
+          $output .= "no " . $node->biblio_issue; // since a series volume should be prefixed with "vol", is it correct to prefix series issues with "no"?
+
+        $output .= ")";
+      }
+
+      if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+      break;
+
+    default : // all other types
+      //TODO
+      //        if (preg_match("[ \r\n]*\(ed\)", $node->author)) // single editor
+      //          $author = $author . ", ed";
+      //        elseif (preg_match("[ \r\n]*\(eds\)", $node->author)) // multiple editors
+      //          $author = $author . ", eds";
+
+      if (!empty($authors))      // author
+      {
+        $output .= '<span class="biblio-authors">';
+          $output .= $authors;
+          if (!preg_match("/\. *$/", $authors))  $output .= ".";
+        $output .= '</span>';
+      }
+
+      if (!empty($node->title))      // title
+      {
+        if (!empty($authors))
+        $output .= " ";
+
+        // TODO: book/volume/report/etc titles should be formatted in heading caps, however, this doesn't yet work correctly if the publication title contains HTML entities
+          $output .= '<span class="biblio-title-vancouver">';
+          $url = biblio_get_title_url_info($node);
+          $output .= l($node->title, $url['link'], $url['options']);
+          $output .= "</span>";
+       }
+      if ($node->type == "Software") // for software, add software label
+        $output .= " [computer program]";
+
+      if (isset($node->online_publication) AND empty($node->thesis)) // this record refers to an online publication (online theses will be handled further down below)
+        $output .= " [Internet]"; // NOTE: some of the above mentioned resources use "[monograph online]", "[monograph on the Internet]" or just "[online]" instead
+
+      if (!empty($node->biblio_volume) AND ($node->type != "Software"))      // volume
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+        $output .= " Vol " . $node->biblio_volume; // TODO: not sure whether this is correct
+      }
+
+      if (!empty($node->biblio_edition))      // edition
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+        if ($node->type == "Software")      // software edition (=version)
+        {
+          $output .= " Version " . $node->biblio_edition;
+        }
+        elseif (!preg_match("/^(1|1st|first|one)( ed\.?| edition)?$/i", $node->biblio_edition))      // edition
+        {
+          if (preg_match("/^\d{1,3}$/", $node->biblio_edition)) // if the edition field contains a number of up to three digits, we assume it's an edition number (such as "2nd ed.")
+          {
+            if ($node->biblio_edition == "2")
+              $editionSuffix = "nd";
+            elseif ($node->biblio_edition == "3")
+              $editionSuffix = "rd";
+            else
+              $editionSuffix = "th";
+          }
+          else
+            $editionSuffix = "";
+
+          if (!preg_match("/( ed\.?| edition)$/i", $node->biblio_edition))
+            $editionSuffix .= " ed.";
+
+          $output .= " " . $node->biblio_edition . $editionSuffix;
+        }
+      }
+
+      if (!empty($editors))      // editor (if different from author, see note above regarding the check for ' (ed)' or ' (eds)')
+      {
+
+        $editor_options = array(
+          'BetweenAuthorsDelimStandard'     => ', ',
+          'BetweenAuthorsDelimLastAuthor'   => ', ',
+          'AuthorsInitialsDelimFirstAuthor' => ' ',
+          'AuthorsInitialsDelimStandard'    => ' ',
+          'betweenInitialsDelim'            => '',
+          'initialsBeforeAuthorFirstAuthor' => FALSE,
+          'initialsBeforeAuthorStandard'    => FALSE,
+          'shortenGivenNames'               => TRUE,
+          'numberOfAuthorsTriggeringEtAl'   => 6,
+          'includeNumberOfAuthors'          => 3,
+          'customStringAfterFirstAuthors'   => ' et al.',
+          'encodeHTML'                      => TRUE
+        );
+
+        $editor = theme('biblio_format_authors', array('contributors' => $editors, 'options' => $editor_options));
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))
+        $output .= ".";
+
+        $output .= " " . $editor;
+        if (count($editors) > 1) // there are at least two editors (separated by ';')
+        $output .= ", editors";
+        else // there's only one editor (or the editor field is malformed with multiple editors but missing ';' separator[s])
+        $output .= ", editor";
+      }
+
+      if (!empty($node->thesis))      // thesis
+      {
+        // TODO: do we need to use the term "[dissertation]" instead of "[Ph.D. thesis]", etc? What about other thesis types then?
+        $output .= " [" . $node->thesis;
+
+        if (isset($node->online_publication)) // this record refers to an online thesis
+          $output .= " on the Internet]";
+        else
+          $output .= "]";
+      }
+
+      if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output))  $output .= ".";
+
+      if (!empty($node->biblio_place_published))      // place
+      {
+//        // for places in the USA, format any two-letter postal code for the state (i.e. ensure upper case & wrap in parentheses, eg. "Boca Raton (FL)"):
+//        if (preg_match("/(.+?)[$punct$space]+($uspsStateAbbreviations)[$punct$space]*$/i$patternModifiers", $node->biblio_place_published))
+//          $output .= " " . preg_replace("/(.+?)[$punct$space]+($uspsStateAbbreviations)[$punct$space]*$/ie$patternModifiers", "'\\1 ('.strtoupper('\\2').')'", $node->biblio_place_published);
+//        else
+          $output .= " " . $node->biblio_place_published;
+      }
+
+      if (!empty($node->biblio_publisher))      // publisher
+      {
+        if (!empty($node->biblio_place_published))
+          $output .= ":";
+
+        $output .= " " . $node->biblio_publisher;
+      }
+
+      $output .= ";";
+
+      if (!empty($node->biblio_year))      // year
+        $output .= " " . $node->biblio_year;
+
+      if ($node->type == "Software")      // for software, volume (=month) and issue (=day) information is printed after the year (TODO: not sure whether this is correct)
+      {
+        if (!empty($node->biblio_volume))      // volume (=month)
+          $output .= " " . $node->biblio_volume;
+
+        if (!empty($node->biblio_issue))      // issue (=day)
+          $output .= " " . $node->biblio_issue;
+      }
+
+      if (isset($node->online_publication)) // append the current date if this record refers to an online publication
+        $output .= " [cited " . date("Y M j") . "]";
+
+      if (!empty($node->biblio_alternate_title) OR !empty($node->biblio_tertiary_title)) // if there's either a full or an abbreviated series title
+      {
+        if (!preg_match("/[?!.][ \"" . $markupPatternsArray["italic-suffix"] . "]*$/", $output)) $output .= ".";
+
+        $output .= " (";
+
+        if (!empty($node->biblio_alternate_title))      // abbreviated series title
+          $output .= preg_replace("/\./", "", $node->biblio_alternate_title); // no punctuation marks are used in the abbreviated series title, just spaces (TODO: smarten regex pattern)
+
+        // if there's no abbreviated series title, we'll use the full series title instead:
+        elseif (!empty($node->biblio_tertiary_title))      // full series title
+          $output .= $node->biblio_tertiary_title;
+
+        if (!empty($node->biblio_volume)||!empty($node->biblio_issue))
+          $output .= "; ";
+
+        if (!empty($node->biblio_volume))      // series volume
+          $output .= "vol " . $node->biblio_volume;
+
+        if (!empty($node->biblio_volume) && !empty($node->biblio_issue))
+          $output .= "; "; // TODO: not sure whether this is correct
+
+        if (!empty($node->biblio_issue))      // series issue (I'm not really sure if -- for this cite style -- the series issue should be rather omitted here)
+          $output .= "no " . $node->biblio_issue; // since a series volume should be prefixed with "vol", is it correct to prefix series issues with "no"?
+
+        $output .= ")";
+      }
+
+      if (isset($node->online_publication) || $node->type == "Software") // this record refers to an online publication, or a computer program/software
+      {
+        // append an optional string (given in 'online_citation') plus the DOI (or URL):
+
+        if (!empty($node->online_citation))      // online_citation
+        {
+          if (!preg_match("/\. *$/", $output)) $output .= ".";
+
+          $output .= $node->online_citation;
+        }
+
+        if (!empty($node->doi) || !empty($node->url))      // doi OR url
+        {
+          if (!preg_match("/\. *$/", $output))  $output .= ".";
+
+          $output .= " Available from: " . $markupPatternsArray["underline-prefix"]; // NOTE: some of the above mentioned resources use "Available from: URL:http://..." instead
+
+          if (!empty($node->doi))      // doi
+            $uri = "http://dx.doi.org/" . $node->doi;
+          else      // url
+            $uri = $node->url;
+
+          if ($encodeHTML)
+            $output .= encodeHTML($uri);
+          else
+            $output .= $uri;
+
+          $output .= $markupPatternsArray["underline-suffix"];
+        }
+      }
+
+      if (!preg_match("/\. *$/", $output) AND (!isset($node->online_publication)) AND ($node->type != "Software"))
+        $output .= "."; // NOTE: the examples in the above mentioned resources differ wildly w.r.t. whether the closing period should be omitted for online publications
+      break;
+  }
+
+  return filter_xss($output, biblio_get_allowed_tags());
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/tests/biblio.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,192 @@
+<?php
+/*
+ * @file
+ * Base class for all biblio tests
+ */
+class BiblioWebTestCase extends DrupalWebTestCase {
+  protected $kids = array();  //keep a list of all keyword id's created
+  protected $cids = array();  //keep a list of all contributor id's created
+  protected $nids = array();  //keep a list of all node id's created
+  protected $admin_user;
+
+//  function tearDown() {
+//    if (!empty($this->kids)) {
+//      db_delete('biblio_keyword')
+//      ->condition('kid', $this->kids, 'IN')
+//      ->execute();
+//
+//      db_delete('biblio_keyword_data')
+//      ->condition('kid', $this->kids, 'IN')
+//      ->execute();
+//
+//    }
+//
+//    foreach ($this->nids as $nid) {
+//      node_delete($nid);
+//    }
+//
+//    if (!empty($this->cids)) {
+//      db_delete('biblio_contributor')
+//      ->condition('cid', $this->cids, 'IN')
+//      ->execute();
+//
+//      db_delete('biblio_contributor_data')
+//      ->condition('cid', $this->cids, 'IN')
+//      ->execute();
+//
+//    }
+//    $this->cids = array();
+//  }
+
+
+  function createNode($type = 100) {
+    $schema = drupal_get_schema('biblio');
+    foreach ($schema['fields'] as $name => $values) {
+      if ($values['type'] == 'int') continue;
+      switch ($values['type']) {
+        case 'varchar':
+          $length = $values['length'];
+          break;
+        case 'text':
+          $length = 1000;
+          break;
+      }
+      $biblio_fields["$name"] = $name;
+    }
+    $settings = array(
+      'title' => 'Biblio Title',
+      'type' => 'biblio', // This replaces the default type
+      'biblio_type' => $type, // This appends a new field.
+      'biblio_year' => 2009,
+      'biblio_contributors' => array(0 => array('name' => 'Ron J. Jeromezzzzzz',  'auth_type' => 1, 'auth_category' => 1),
+                                     1 => array('name' => 'John Smithzzzzzz',  'auth_type' => 1, 'auth_category' => 1),
+                                     2 => array('name' => 'George W. Bushzzzzzz',  'auth_type' => 1, 'auth_category' => 1)),
+      'biblio_keywords' => array('biblio_keywords')
+    );
+    $settings = array_merge($biblio_fields, $settings);
+
+    $node = $this->drupalCreateNode($settings);
+    $node = node_load($node->nid, NULL, TRUE);
+    foreach ($node->biblio_contributors as $author) {
+      $this->cids[] = $author['cid'];
+    }
+
+    $this->nids[] = $node->nid;
+
+    return $node;
+
+  }
+  function assertBiblioFields($node1, $node2, $fields = array()) {
+    $count = 0;
+    foreach ($fields as $field) {
+      if ($field == 'biblio_contributors') {
+        foreach ($node1->{$field} as $key => $auth) {
+          unset($node1->{$field}[$key]['nid']);
+          unset($node1->{$field}[$key]['vid']);
+        }
+        foreach ($node2->{$field} as $key => $auth) {
+          unset($node2->{$field}[$key]['nid']);
+          unset($node2->{$field}[$key]['vid']);
+        }
+      }
+      if ($node1->$field != $node2->$field) {
+        $this->assertIdentical($node1->$field, $node2->$field);
+        $count++;
+      }
+    }
+    $this->assertEqual($count, 0, "There were $count differences between the two nodes");
+  }
+}
+
+class BiblioNodeCreationTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Biblio node creation',
+      'description' => 'Create a biblio node and test saving it.',
+      'group' => 'Biblio',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('biblio');
+    $web_user = $this->drupalCreateUser(array('create biblio content'));
+    $this->drupalLogin($web_user);
+  }
+
+  /**
+   * Create a biblio node and verify its consistency in the database.
+   */
+  function testBiblioNodeCreation() {
+    // Create a node.
+    $edit = array();
+    $edit["biblio_type"] = '101';
+    $this->drupalPost('node/add/biblio', $edit, t('Next'));
+
+    // Check that the next step of the form appears.
+    $this->assertOptionSelected('edit-biblio-type', '101');
+    $this->assertFieldById('edit-title');
+    $this->assertFieldById('edit-biblio-year');
+
+    $edit = array(
+      'title' => $this->randomString(32),
+      'biblio_year' => '2009',
+      'biblio_contributors[0][name]' => 'Kevin Brown',
+      'biblio_contributors[1][name]' => 'Martin Clark',
+      'biblio_contributors[2][name]' => 'George Wei',
+      'biblio_keywords' => 'architecture, building, wood',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Check that the Basic page has been created.
+    $this->assertRaw(t('!post %title has been created.', array('!post' => 'Biblio', '%title' => $edit["title"])), t('Biblio entry created.'));
+    // Check that the node exists in the database.
+    $node = $this->drupalGetNodeByTitle($edit['title']);
+
+    $keywordstring = implode(', ', $node->biblio_keywords);
+    $this->assertIdentical($keywordstring, 'architecture, building, wood', t('Keywords are present on the biblio node.'));
+    $this->assertTrue($node, t('Node found in database.'));
+  }
+}
+
+class BiblioPageViewTestCase extends BiblioWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Biblio node view and edit permissions',
+      'description' => 'Create a biblio node and test view / edit permissions.',
+      'group' => 'Biblio',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('biblio');
+  }
+
+  /**
+   * Creates a node and then an anonymous and unpermissioned user attempt to edit the node.
+   */
+  function testBiblioPageView() {
+    // Create a node to view.
+    $node = $this->createNode('101');
+    $this->assertTrue(node_load($node->nid), t('Node created.'));
+
+    // Try to edit with anonymous user.
+    $html = $this->drupalGet("node/$node->nid/edit");
+    $this->assertResponse(403);
+
+    // Create a user without permission to edit node.
+    $web_user = $this->drupalCreateUser(array('access content'));
+    $this->drupalLogin($web_user);
+
+    // Attempt to access edit page.
+    $this->drupalGet("node/$node->nid/edit");
+    $this->assertResponse(403);
+
+    // Create user with permission to edit node.
+    $web_user = $this->drupalCreateUser(array('edit any biblio content'));
+    $this->drupalLogin($web_user);
+
+    // Attempt to access edit page.
+    $this->drupalGet("node/$node->nid/edit");
+    $this->assertResponse(200);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/tests/contributor.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,129 @@
+<?php
+/*
+ * @file
+ * Tests for contributor handling in the Biblio module
+ *
+ */
+
+class BiblioContributorWebTestCase extends BiblioWebTestCase {
+  function setUp() {
+    parent::setUp('biblio');
+    require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.contributors.inc');
+  }
+
+
+}
+
+class BiblioContributorUnitTest extends BiblioContributorWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Biblio contributor unit tests',
+      'description' => 'Unit tests for contributor functions.',
+      'group' => 'Biblio',
+    );
+  }
+
+  function testGrabSurname() {
+
+    $surname = 'van der Plus';
+    list ($surname, $prefix) = _grabSurname($surname);
+    $this->assertIdentical($surname, 'Plus' );
+    $this->assertIdentical($prefix, 'van der' );
+    $surname = 'Van den Bussche';
+    list ($surname, $prefix) = _grabSurname($surname);
+    $this->assertIdentical($surname, 'Van den Bussche' );
+    $this->assertIdentical($prefix, FALSE );
+  }
+  function testGrabFirstnameInitials() {
+
+    $string = "Ron";
+    list($firstname, $initials, $prefix) = _grabFirstnameInitials($string);
+    $this->assertIdentical($firstname, 'Ron' );
+    $this->assertIdentical($initials, '' );
+    $string = "Ron J.";
+    list($firstname, $initials, $prefix) = _grabFirstnameInitials($string);
+    $this->assertIdentical($firstname, 'Ron' );
+    $this->assertIdentical($initials, 'J' );
+    $string = "sir Ron J.";
+    list($firstname, $initials, $prefix) = _grabFirstnameInitials($string);
+    $this->assertIdentical($firstname, 'Ron' );
+    $this->assertIdentical($initials, 'J' );
+    $this->assertIdentical($prefix, 'sir' );
+    $string = "R J";
+    list($firstname, $initials, $prefix) = _grabFirstnameInitials($string);
+    $this->assertIdentical($firstname, '' );
+    $this->assertIdentical($initials, 'R J' );
+    $string = "R. J.";
+    list($firstname, $initials, $prefix) = _grabFirstnameInitials($string);
+    $this->assertIdentical($firstname, '' );
+    $this->assertIdentical($initials, 'R J' );
+    $string = "R.J.";
+    list($firstname, $initials, $prefix) = _grabFirstnameInitials($string);
+    $this->assertIdentical($firstname, '' );
+    $this->assertIdentical($initials, 'R J' );
+
+  }
+
+  function testBiblioParseAuthor() {
+
+    $author['name'] = 'Bush, Jr. III, George W';
+    $author['auth_category'] = 1;
+    $author = biblio_parse_author($author);
+    $this->assertIdentical($author['firstname'], 'George', 'Test biblio_parse_author($author), firstname' );
+    $this->assertIdentical($author['lastname'], 'Bush', 'Test biblio_parse_author($author), lastname');
+    $this->assertIdentical($author['initials'], 'W', 'Test biblio_parse_author($author), initials' );
+    $this->assertIdentical($author['suffix'], 'Jr. III', 'Test biblio_parse_author($author), suffix' );
+
+  }
+
+  function testBiblioUpdateContributors() {
+
+    $node = $this->createNode();
+    $nid = $node->nid;
+    $vid1 = $node->vid;
+    $this->assertIdentical($node->biblio_contributors[2]['firstname'], 'George', 'Test biblio_insert_contributors($node), firstname');
+    $this->assertIdentical($node->biblio_contributors[2]['lastname'], 'Bushzzzzzz', 'Test biblio_insert_contributors($node), lastname' );
+    unset($node->biblio_contributors[2]);
+    $node->revision = TRUE;
+    node_save($node);
+
+    $node = node_load($nid, NULL, TRUE);
+    $this->assertFalse(isset($node->biblio_contributors[2]), 'Test removing an author and updating the node');
+
+    biblio_delete_contributor_revision($node->biblio_contributors[1]['cid'], $node->vid);
+    $node = node_load($nid, NULL, TRUE);
+    $this->assertEqual(count($node->biblio_contributors), 1, 'Test biblio_delete_contributor_revision($cid, $vid)');
+
+    $node = node_load($nid, $vid1, TRUE);
+
+    $this->assertEqual(count($node->biblio_contributors), 3, 'Test load original vid, still three authors');
+
+    biblio_delete_contributors($node);
+    $node = node_load($nid, NULL, TRUE);
+    $this->assertFalse(count($node->biblio_contributors), 'Test biblio_delete_contributors($node), should be zero authors on reload');
+
+  }
+
+  function testBiblioDeleteOrphanAuthors() {
+    $orphan_authors = array();
+    $orphan_authors = biblio_get_orphan_authors(); // first save any existing orphans so we can put them back
+    $orphan_count = biblio_count_orphan_authors();
+    $author = array('name' => 'Ron J. Jeromezzzzzz',  'auth_type' => 1);
+    biblio_save_contributor($author);  // create a new orphan so we will have at least one
+    $before_count = biblio_count_orphan_authors();
+    $this->assertTrue($before_count != 0, "There are $before_count orphans to delete");
+    biblio_delete_orphan_authors(TRUE);
+    $after_count = biblio_count_orphan_authors();
+    $this->assertEqual($after_count, 0, "There are now $after_count orphans");
+
+
+    foreach ($orphan_authors as $author) {
+      biblio_save_contributor($author);
+    }
+    $restored_count = biblio_count_orphan_authors();
+    $this->assertEqual($orphan_count, $restored_count, "Restored $restored_count of $orphan_count original orphans");
+
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/tests/import.export.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,119 @@
+<?php
+class BiblioImportExportWebTestCase extends BiblioWebTestCase {
+  function setUp() {
+    parent::setUp('biblio', 'biblio_ris', 'biblio_bibtex', 'biblio_tagged', 'biblio_xml', 'biblio_crossref');
+    require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.import.export.inc');
+  }
+}
+
+class BiblioImportExportUnitTest extends BiblioImportExportWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Biblio import/export unit tests',
+      'description' => 'Unit tests for import/export functions.',
+      'group' => 'Biblio',
+    );
+  }
+  function getTaggedString() {
+    return  "%0 Book\r\n%B biblio_secondary_title\r\n%D 2009\r\n%T Biblio Title\r\n%A Ron J. Jeromezzzzzz\r\n%A John Smithzzzzzz\r\n%A George W. Bushzzzzzz\r\n%K biblio_keywords\r\n%X biblio_abst_e\r\n%B biblio_secondary_title\r\n%S biblio_tertiary_title\r\n%7 biblio_edition\r\n%I biblio_publisher\r\n%C biblio_place_published\r\n%V biblio_volume\r\n%P biblio_pages\r\n%8 biblio_date\r\n%@ biblio_isbn\r\n%G biblio_lang\r\n%U biblio_url\r\n%N biblio_issue\r\n%9 biblio_type_of_work\r\n%M biblio_accession_number\r\n%L biblio_call_number\r\n%1 biblio_custom1\r\n%2 biblio_custom2\r\n%3 biblio_custom3\r\n%4 biblio_custom4\r\n%# biblio_custom5\r\n%$ biblio_custom6\r\n%] biblio_custom7\r\n%< biblio_research_notes\r\n%6 biblio_number_of_volumes\r\n%! biblio_short_title\r\n%( biblio_original_publication\r\n%) biblio_reprint_edition\r\n%& biblio_section\r\n%R biblio_doi\r\n%F biblio_label\r\n\r\n";
+  }
+
+  function getBibTexString() {
+    return "@book {biblio_citekey,\n\ttitle = {Biblio Title},\n\tseries = {biblio_secondary_title},\n\tvolume = {biblio_volume},\n\tnumber = {biblio_number},\n\tyear = {2009},\n\tnote = {biblio_notes},\n\tmonth = {biblio_date},\n\tpages = {biblio_pages},\n\tpublisher = {biblio_publisher},\n\torganization = {biblio_publisher},\n\ttype = {biblio_type_of_work},\n\tedition = {biblio_edition},\n\tchapter = {biblio_section},\n\taddress = {biblio_place_published},\n\tabstract = {biblio_abst_e},\n\tkeywords = {biblio_keywords},\n\tisbn = {biblio_isbn},\n\tissn = {biblio_issn},\n\tdoi = {biblio_doi},\n\turl = {biblio_url},\n\tauthor = {Ron J. Jeromezzzzzz and John Smithzzzzzz and George W. Bushzzzzzz}\n}\n";
+  }
+
+  function getXMLString() {
+    return '<?xml version="1.0" encoding="UTF-8"?><xml><records><record><source-app name="Biblio" version="7.x">Drupal-Biblio</source-app><ref-type>6</ref-type><contributors><authors><author><style face="normal" font="default" size="100%">Ron J. Jeromezzzzzz</style></author><author><style face="normal" font="default" size="100%">John Smithzzzzzz</style></author><author><style face="normal" font="default" size="100%">George W. Bushzzzzzz</style></author></authors></contributors><titles><title><style face="normal" font="default" size="100%">Biblio Title</style></title><secondary-title><style face="normal" font="default" size="100%">biblio_secondary_title</style></secondary-title><tertiary-title><style face="normal" font="default" size="100%">biblio_tertiary_title</style></tertiary-title><alt-title><style face="normal" font="default" size="100%">biblio_alternate_title</style></alt-title><short-title><style face="normal" font="default" size="100%">biblio_short_title</style></short-title><translated-title><style face="normal" font="default" size="100%">biblio_translated_title</style></translated-title></titles><keywords><keyword><style  face="normal" font="default" size="100%">biblio_keywords</style></keyword></keywords><dates><year><style  face="normal" font="default" size="100%">2009</style></year><pub-dates><date><style  face="normal" font="default" size="100%">biblio_date</style></date></pub-dates></dates><urls><web-urls><url><style face="normal" font="default" size="100%">biblio_url</style></url></web-urls></urls><number><style face="normal" font="default" size="100%">biblio_number</style></number><edition><style face="normal" font="default" size="100%">biblio_edition</style></edition><publisher><style face="normal" font="default" size="100%">biblio_publisher</style></publisher><pub-location><style face="normal" font="default" size="100%">biblio_place_published</style></pub-location><volume><style face="normal" font="default" size="100%">biblio_volume</style></volume><pages><style face="normal" font="default" size="100%">biblio_pages</style></pages><isbn><style face="normal" font="default" size="100%">biblio_isbn</style></isbn><language><style face="normal" font="default" size="100%">biblio_lang</style></language><abstract><style face="normal" font="default" size="100%">biblio_abst_e</style></abstract><issue><style face="normal" font="default" size="100%">biblio_issue</style></issue><work-type><style face="normal" font="default" size="100%">biblio_type_of_work</style></work-type><accession-num><style face="normal" font="default" size="100%">biblio_accession_number</style></accession-num><call-num><style face="normal" font="default" size="100%">biblio_call_number</style></call-num><notes><style face="normal" font="default" size="100%">biblio_notes</style></notes><custom1><style face="normal" font="default" size="100%">biblio_custom1</style></custom1><custom2><style face="normal" font="default" size="100%">biblio_custom2</style></custom2><custom3><style face="normal" font="default" size="100%">biblio_custom3</style></custom3><custom4><style face="normal" font="default" size="100%">biblio_custom4</style></custom4><custom5><style face="normal" font="default" size="100%">biblio_custom5</style></custom5><custom6><style face="normal" font="default" size="100%">biblio_custom6</style></custom6><custom7><style face="normal" font="default" size="100%">biblio_custom7</style></custom7><research-notes><style face="normal" font="default" size="100%">biblio_research_notes</style></research-notes><num-vols><style face="normal" font="default" size="100%">biblio_number_of_volumes</style></num-vols><orig-pub><style face="normal" font="default" size="100%">biblio_original_publication</style></orig-pub><reprint-edition><style face="normal" font="default" size="100%">biblio_reprint_edition</style></reprint-edition><section><style face="normal" font="default" size="100%">biblio_section</style></section><auth-address><style face="normal" font="default" size="100%">biblio_auth_address</style></auth-address><remote-database-name><style face="normal" font="default" size="100%">biblio_remote_db_name</style></remote-database-name><remote-database-provider><style face="normal" font="default" size="100%">biblio_remote_db_provider</style></remote-database-provider><label><style face="normal" font="default" size="100%">biblio_label</style></label><access-date><style face="normal" font="default" size="100%">biblio_access_date</style></access-date></record></records></xml>';
+  }
+
+  function getRISString() {
+    return "TY  - BOOK\r\nTI  - Biblio Title\r\nY1  - 2009\r\nN1  - biblio_notes\r\nAU  - Ron J. Jeromezzzzzz\r\nAU  - John Smithzzzzzz\r\nAU  - George W. Bushzzzzzz\r\nKW  - biblio_keywords\r\nSP  - 1\r\nEP  - 2\r\nJO  - biblio_short_title\r\nVL  - biblio_volume\r\nIS  - biblio_issue\r\nT2  - biblio_secondary_title\r\nCY  - biblio_place_published\r\nPB  - biblio_publisher\r\nU1  - biblio_custom1\r\nU2  - biblio_custom2\r\nU3  - biblio_custom3\r\nU4  - biblio_custom4\r\nU5  - biblio_custom5\r\nT3  - biblio_tertiary_title\r\nAB  - biblio_abst_e\r\nSN  - biblio_isbn\r\nUR  - biblio_url\r\nER  - \r\n\r\n";
+  }
+
+  function testBiblioNodeExport() {
+    module_load_include('inc', 'biblio_xml', 'endnote8_export');
+    $node = $this->createNode();
+    $this->assertEqual(_biblio_tagged_export($node), $this->getTaggedString());//, 'Export a node in EndNote Tagged format');
+    $this->assertEqual(_biblio_bibtex_export($node), $this->getBibTexString(), 'Export a node in BibTex format');
+    $xml = _endnote8_XML_export('', 'begin');
+    $xml .= _endnote8_XML_export($node);
+    $xml .= _endnote8_XML_export('', 'end');
+    $this->assertEqual($xml, $this->getXMLString());//, 'Export a node in EndNote XML format');
+
+  }
+
+  function testBiblioRISFileImport() {
+    $file = file_save_data($this->getRISString());
+    $context = array();
+    biblio_import($file, 'biblio_ris', 1, NULL, FALSE, NULL, $context);
+    $nids = $context['results']['nids'];
+    array_merge($this->nids, $nids);
+    $this->assertEqual(count($nids), 1, 'Imported 1 RIS entry');
+    file_delete($file);
+    $node = $this->createNode();
+    $fields = array_unique(array_filter(biblio_get_map('field_map', 'ris')));
+    $fields += array('title', 'biblio_contributors');
+    foreach ($nids as $nid) {
+      $this->nids[] = $nid;
+      $imported_node = node_load($nid);
+      $this->assertBiblioFields($node, $imported_node, $fields);
+    }
+  }
+
+  function testBiblioXMLFileImport() {
+    $file = file_save_data($this->getXMLString());
+    $context = array();
+    biblio_import($file, 'biblio_xml', 1, NULL, FALSE, NULL, $context);
+    $nids = $context['results']['nids'];
+    array_merge($this->nids, $nids);
+    $this->assertEqual(count($nids), 1, 'Imported 1 EndNote XML entry');
+    file_delete($file);
+    $node = $this->createNode();
+    $fields = array_filter(biblio_get_map('field_map', 'endnote8'));
+    $fields += array('title', 'biblio_contributors', 'biblio_keywords');
+    foreach ($nids as $nid) {
+      $this->nids[] = $nid;
+      $imported_node = node_load($nid);
+      $this->assertBiblioFields($node, $imported_node, $fields);
+    }
+  }
+
+  function testBiblioTaggedFileImport() {
+    $file = file_save_data($this->getTaggedString());
+    $context = array();
+    biblio_import($file, 'biblio_tagged', 1, NULL, FALSE, NULL, $context);
+    $nids = $context['results']['nids'];
+    array_merge($this->nids, $nids);
+    $this->assertEqual(count($nids), 1, 'Imported 1 Tagged entry');
+    file_delete($file);
+    $node = $this->createNode();
+    $fields = array_filter(biblio_get_map('field_map', 'tagged'));
+    $fields += array('title', 'biblio_contributors', 'biblio_keywords');
+    foreach ($nids as $nid) {
+      $this->nids[] = $nid;
+      $imported_node = node_load($nid);
+      $this->assertBiblioFields($node, $imported_node, $fields);
+    }
+  }
+
+  function testBiblioBibtexFileImport() {
+    $file = file_save_data($this->getBibTexString());
+    $context = array();
+    biblio_import($file, 'biblio_bibtex', 1, NULL, FALSE, NULL, $context);
+    $nids = $context['results']['nids'];
+    array_merge($this->nids, $nids);
+    $this->assertEqual(count($nids), 1, 'Imported 1 Bibtex entry');
+    file_delete($file);
+    $node = $this->createNode();
+    $fields = array_filter(biblio_get_map('field_map', 'bibtex'));
+    $fields += array('title', 'biblio_contributors');
+    foreach ($nids as $nid) {
+      $this->nids[] = $nid;
+      $imported_node = node_load($nid);
+      $this->assertBiblioFields($node, $imported_node, $fields);
+    }
+  }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/tests/keyword.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * @file
+ * Tests for keyword functions.
+ */
+
+/**
+* Class with common helper methods.
+*/
+class BiblioKeywordWebTestCase extends BiblioWebTestCase {
+
+  function setUp() {
+    parent::setUp('biblio');
+    require_once(drupal_get_path('module', 'biblio') . '/includes/biblio.keywords.inc');
+  }
+
+  /**
+   * Returns a new keyword with random properties.
+   */
+  function createKeyword() {
+    $keyword = array();
+    $keyword['word'] = $this->randomName();
+    biblio_save_keyword($keyword);
+    $this->kids[] = $keyword['kid'];
+    return $keyword;
+  }
+
+}
+
+/**
+ * Unit tests for keyword functions.
+ */
+class BiblioKeywordUnitTest extends BiblioKeywordWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Biblio keyword unit tests',
+      'description' => 'Unit tests for keyword functions.',
+      'group' => 'Biblio',
+    );
+  }
+  function testBiblioSaveKeyword() {
+    $keyword = $this->createKeyword();
+    $this->assertTrue($keyword['kid'], t('Created and saved a single keyword'));
+  }
+  function testBiblioDeleteKeyword() {
+    $keyword = $this->createKeyword();
+    $num_deleted = biblio_delete_keyword($keyword['kid']);
+    $this->assertEqual($num_deleted, 1, t('Deleted a single keyword'));
+  }
+  function testBiblioGetKeywordById() {
+    $keyword = $this->createKeyword();
+    $word = (array) biblio_get_keyword_by_id($keyword['kid']);
+    $this->assertEqual($keyword, $word, 'Get keyword by ID');
+  }
+  function testBiblioGetKeywordByName() {
+    $keyword = $this->createKeyword();
+
+    // Load the term with the exact name.
+    $word = biblio_get_keyword_by_name($keyword['word']);
+    $this->assertEqual($word->word, $keyword['word'], t('Keyword loaded using exact name.'));
+
+    // Load the term with space concatenated.
+    $word  = biblio_get_keyword_by_name('  ' . $keyword['word'] . '   ');
+    $this->assertEqual($word->word, trim('  ' . $keyword['word'] . '   '), t('Keyword loaded with extra whitespace.'));
+
+    // Load the term with name uppercased.
+    $word = biblio_get_keyword_by_name(strtoupper($keyword['word']));
+    $this->assertEqual($word->word, $keyword['word'], t('Keyword loaded with uppercased name.'));
+
+    // Load the term with name lowercased.
+    $word = biblio_get_keyword_by_name(strtolower($keyword['word']));
+    $this->assertEqual($word->word, $keyword['word'], t('Keyword loaded with lowercased name.'));
+
+    // Try to load an invalid term name.
+    $word = biblio_get_keyword_by_name('Banana');
+    $this->assertFalse($word, t('Tried to load an invalid keyword'));
+
+    // Try to load the term using a substring of the name.
+    $word = biblio_get_keyword_by_name(drupal_substr($keyword['word'], 2));
+    $this->assertFalse($word, t('Tried to load a keyword using a substring of the word'));
+  }
+
+
+  function testBiblioUpdateKeywords() {
+    $term1 = $this->createKeyword();
+    $node = $this->createNode();
+
+    $node->biblio_keywords = array($term1['word']);
+    $old_vid = $node->vid;
+
+    $node->biblio_keywords[0] .= 'xxx';
+    $node->revision = TRUE;
+    node_save($node);
+
+    $node = node_load($node->nid, NULL, TRUE);
+
+    foreach ($node->biblio_keywords as $kid => $value) {
+      $this->assertEqual($value, $term1['word'] . 'xxx', 'Loaded updated keyword');
+      $this->kids[] = $kid; // add the new kids to the global array so we can delete them on tear down.
+    }
+    $node = node_load($node->nid, $old_vid, TRUE);
+    foreach ($node->biblio_keywords as $kid => $value) {
+      $this->assertEqual($value, 'biblio_keywords', 'Loaded previous revision prior to update');
+      $this->kids[] = $kid; // add the new kids to the global array so we can delete them on tear down.
+    }
+    biblio_delete_keywords($node);
+
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertFalse(count($node->biblio_keywords), "Loaded node which no longer has any keywords");
+  }
+
+  function testBiblioDeleteOrphanKeywords() {
+    $this->createKeyword();
+    $this->createKeyword();
+ //   $count = count($this->kids);
+    $num_records_before = db_query('SELECT COUNT(*) FROM {biblio_keyword_data} WHERE kid NOT IN (SELECT DISTINCT(kid) FROM {biblio_keyword})')->fetchField();
+    biblio_delete_orphan_keywords(TRUE);
+    $num_records_after = db_query('SELECT COUNT(*) FROM {biblio_keyword_data} WHERE kid NOT IN (SELECT DISTINCT(kid) FROM {biblio_keyword})')->fetchField();
+    $this->assertEqual($num_records_before, $num_records_after+$num_records_before, "Deleted $num_records_before orphan keywords");
+  }
+
+  function testBiblioExplodeKeywords() {
+    $keywords = array();
+    $exploded = array();
+    $words = array();
+    $sep = variable_get('biblio_keyword_sep', ',');
+    $wrong_sep = ($sep == ',') ? ';' : ',';
+    for ($i=0; $i < 4; $i++) {
+      $words[] = $this->randomName();
+    }
+    $string = implode($sep, $words);
+    $exploded = biblio_explode_keywords($string);
+    $this->assertIdentical($words, $exploded, 'Exploded keyword string with correct separator');
+    $string = implode($wrong_sep, $words);
+    $exploded = biblio_explode_keywords($string);
+    $this->assertNotIdentical($words, $exploded, 'Tried to explode keyword string with incorrect separator');
+    $words[] = '"' . 'word1' . $sep . ' word2' . '"';
+    $string = implode($sep, $words);
+    $exploded = biblio_explode_keywords($string);
+    $words[4] =   trim(str_replace('""', '"', preg_replace('/^"(.*)"$/', '\1', $words[4]))); // strip the quotes becuase that's the way it comes back
+
+    $this->assertEqual($words, $exploded, "Exploded a keyword string which contains and escaped separator");
+  }
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/tests/test.bib	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+@book {biblio_citekey,
+  title = {Biblio Title},
+  series = {biblio_secondary_title},
+  volume = {biblio_volume},
+  number = {biblio_number},
+  year = {2009},
+  note = {biblio_notes},
+  month = {biblio_date},
+  pages = {biblio_pages},
+  publisher = {biblio_publisher},
+  organization = {biblio_publisher},
+  type = {biblio_type_of_work},
+  edition = {biblio_edition},
+  chapter = {biblio_section},
+  address = {biblio_place_published},
+  abstract = {biblio_abst_e},
+  keywords = {biblio_keywords},
+  isbn = {biblio_isbn},
+  issn = {biblio_issn},
+  doi = {biblio_doi},
+  url = {biblio_url},
+  author = {Ron J. Jeromezzzzzz and John Smithzzzzzz and George W. Bushzzzzzz}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/tests/test.ens	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+%0 Book
+%B biblio_secondary_title
+%D 2009
+%T Biblio Title
+%A Ron J. Jeromezzzzzz
+%A John Smithzzzzzz
+%A George W. Bushzzzzzz
+%K biblio_keywords
+%X biblio_abst_e
+%B biblio_secondary_title
+%S biblio_tertiary_title
+%7 biblio_edition
+%I biblio_publisher
+%C biblio_place_published
+%V biblio_volume
+%P biblio_pages
+%8 biblio_date
+%@ biblio_isbn
+%G biblio_lang
+%U biblio_url
+%N biblio_issue
+%9 biblio_type_of_work
+%M biblio_accession_number
+%L biblio_call_number
+%1 biblio_custom1
+%2 biblio_custom2
+%3 biblio_custom3
+%4 biblio_custom4
+%# biblio_custom5
+%$ biblio_custom6
+%] biblio_custom7
+%< biblio_research_notes
+%6 biblio_number_of_volumes
+%R biblio_doi
+%F biblio_label
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/tests/test.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1 @@
+<?xml version="1.0" encoding="UTF-8"?><xml><records><record><source-app name="Biblio" version="6.x">Drupal-Biblio</source-app><ref-type>6</ref-type><contributors><authors><author><style face="normal" font="default" size="100%">Ron J. Jeromezzzzzz</style></author><author><style face="normal" font="default" size="100%">John Smithzzzzzz</style></author><author><style face="normal" font="default" size="100%">George W. Bushzzzzzz</style></author></authors></contributors><titles><title><style face="normal" font="default" size="100%">Biblio Title</style></title><secondary-title><style face="normal" font="default" size="100%">biblio_secondary_title</style></secondary-title><tertiary-title><style face="normal" font="default" size="100%">biblio_tertiary_title</style></tertiary-title><alt-title><style face="normal" font="default" size="100%">biblio_alternate_title</style></alt-title><short-title><style face="normal" font="default" size="100%">biblio_short_title</style></short-title><translated-title><style face="normal" font="default" size="100%">biblio_translated_title</style></translated-title></titles><keywords><keyword><style  face="normal" font="default" size="100%">biblio_keywords</style></keyword></keywords><dates><year><style  face="normal" font="default" size="100%">2009</style></year><pub-dates><date><style  face="normal" font="default" size="100%">biblio_date</style></date></pub-dates></dates><urls><web-urls><url><style face="normal" font="default" size="100%">biblio_url</style></url></web-urls></urls><number><style face="normal" font="default" size="100%">biblio_number</style></number><edition><style face="normal" font="default" size="100%">biblio_edition</style></edition><publisher><style face="normal" font="default" size="100%">biblio_publisher</style></publisher><pub-location><style face="normal" font="default" size="100%">biblio_place_published</style></pub-location><volume><style face="normal" font="default" size="100%">biblio_volume</style></volume><pages><style face="normal" font="default" size="100%">biblio_pages</style></pages><isbn><style face="normal" font="default" size="100%">biblio_isbn</style></isbn><language><style face="normal" font="default" size="100%">biblio_lang</style></language><abstract><style face="normal" font="default" size="100%">biblio_abst_e</style></abstract><issue><style face="normal" font="default" size="100%">biblio_issue</style></issue><work-type><style face="normal" font="default" size="100%">biblio_type_of_work</style></work-type><accession-num><style face="normal" font="default" size="100%">biblio_accession_number</style></accession-num><call-num><style face="normal" font="default" size="100%">biblio_call_number</style></call-num><notes><style face="normal" font="default" size="100%">biblio_notes</style></notes><custom1><style face="normal" font="default" size="100%">biblio_custom1</style></custom1><custom2><style face="normal" font="default" size="100%">biblio_custom2</style></custom2><custom3><style face="normal" font="default" size="100%">biblio_custom3</style></custom3><custom4><style face="normal" font="default" size="100%">biblio_custom4</style></custom4><custom5><style face="normal" font="default" size="100%">biblio_custom5</style></custom5><custom6><style face="normal" font="default" size="100%">biblio_custom6</style></custom6><custom7><style face="normal" font="default" size="100%">biblio_custom7</style></custom7><research-notes><style face="normal" font="default" size="100%">biblio_research_notes</style></research-notes><num-vols><style face="normal" font="default" size="100%">biblio_number_of_volumes</style></num-vols><orig-pub><style face="normal" font="default" size="100%">biblio_original_publication</style></orig-pub><reprint-edition><style face="normal" font="default" size="100%">biblio_reprint_edition</style></reprint-edition><section><style face="normal" font="default" size="100%">biblio_section</style></section><auth-address><style face="normal" font="default" size="100%">biblio_auth_address</style></auth-address><remote-database-name><style face="normal" font="default" size="100%">biblio_remote_db_name</style></remote-database-name><remote-database-provider><style face="normal" font="default" size="100%">biblio_remote_db_provider</style></remote-database-provider><label><style face="normal" font="default" size="100%">biblio_label</style></label><access-date><style face="normal" font="default" size="100%">biblio_access_date</style></access-date></record></records></xml>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/todo.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+ todo list (no particular order)
+
+* check if upgrade from 5.x is clobbering other biblio related taxonomy http://drupal.org/node/361589
+* add sorting to the argument list you can pass to biblio_db_search() http://drupal.org/node/360624
+* put titles in body text to avoid long title problems http://drupal.org/node/358286
+* check author parsing on names containing UTF-8 chars.
+* look at validating the DOI input http://drupal.org/node/359318
+* add descriptions to publication types (http://drupal.org/node/358158)
+* add the option to change subsorts (i.e. sort by year then within year sort by...)
+* fix display when sorting by author 
+* bibtex handeling of curly braces  http://drupal.org/node/314488
+* add image field http://drupal.org/node/314249
+* check assignment of taxonomy terms  http://drupal.org/node/336344
+* check BOM breaking RIS parsing  http://drupal.org/node/330901
+* create "author editor" UI to find and combine duplcate authors (variations on a name who are actually the same person) 
+* add UNICODE to LATEX conversion to bibtex export http://drupal.org/node/183517
+* fix Biblio user warning: empty (sub)expression' from regexp query http://drupal.org/node/349777
+* ubercart integration...  http://drupal.org/node/354373
+* Footnote repetition handling http://drupal.org/comment/reply/134748
+(DONE) add pathAuto support http://drupal.org/node/89038
+(DONE) fix author handeling (in contributor widget) http://drupal.org/node/313264
+(DONE) make citekey database field longer (varchar 255) http://drupal.org/node/282896
+(DONE) display attachment description rather than file name http://drupal.org/node/314395
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,441 @@
+<?php
+//function biblio_views_plugins() {
+//  return array(
+//    'display' => array(
+//      'biblio' => array(
+//        'title' => t('Biblio Page'),
+//        'help' => t(''),
+//        'handler' => 'views_plugin_display_page_biblio',
+//        'path' => drupal_get_path('module', 'biblio') . '/views', // not necessary for most modules
+////        'theme' => 'views_view_row_node',
+//        'base' => array('node'), // only works with 'node' as base.
+//        'uses options' => TRUE,
+//        'type' => 'normal',
+//        ),
+//      ),
+//    'style' => array(
+//      // ... list of style plugins,
+//      ),
+//    'row' => array(
+//      // ... list of row style plugins,
+//      ),
+//    'argument default' => array(
+//      // ... list of argument default plugins,
+//      ),
+//    'argument validator' => array(
+//      // ... list of argument validator plugins,
+//      ),
+//    'access' => array(
+//      // ... list of access plugins,
+//      ),
+//   );
+//}
+
+/**
+ * Implementation of hook_views_data().
+ *
+ * Exposes all fields to the views system.
+ */
+function biblio_views_data() {
+  $viewsdata = array();
+
+  /**************** biblio table **************/
+  $data = array();
+  // everything belongs to the Biblio group
+  $data['table']['group'] = t('Biblio');
+
+  $data['citation'] = array(
+    'title' => t('Biblio Citation'),
+    'help'  => t("Display the complete citation for a given node"),
+    'field' => array(
+      'handler' => 'biblio_handler_citation',
+    ),
+  );
+  $result = db_query('SELECT f.name,f.type,ftd.title,ft.ftdid FROM {biblio_fields} f
+                      INNER JOIN {biblio_field_type} AS ft ON ft.fid = f.fid
+                      INNER JOIN {biblio_field_type_data} ftd ON ft.ftdid = ftd.ftdid
+                      WHERE ft.tid = 0');
+
+  foreach ($result as $field) {
+    $data[$field->name] = array(
+      'title'     => $field->title,
+      'help'      => "Display the " . $field->title,
+      'field'     => array('handler' => 'biblio_handler_field'),
+      'sort'      => array('handler' => 'views_handler_sort'),
+      'filter'    => array('handler' => 'views_handler_filter_string'),
+      'argument'  => array('handler' => 'views_handler_argument_string')
+    );
+
+    // for contrib_widgets we use a special handler:
+    if ($field->type == 'contrib_widget') {
+      $data[$field->name]['field'] = array(
+        'handler' => 'biblio_handler_field_contributor',
+        'auth_category' => $field->ftdid,
+      );
+      unset($data[$field->name]['sort']);
+      unset($data[$field->name]['filter']);
+      unset($data[$field->name]['argument']);
+    }
+    if ($field->type == 'text_format') {
+      $data[$field->name]['field']['handler'] = 'biblio_handler_field_markup';
+    }
+  }
+  $data['biblio_year']['argument']  = array('handler' => 'views_handler_argument_numeric');  // biblio_year is an int
+  $data['biblio_year']['filter']    = array('handler' => 'views_handler_filter_numeric');  // biblio_year is an int
+
+  $data['biblio_keywords']['field'] = array('handler' => 'biblio_handler_field_keyword');
+  $data['biblio_keywords']['title'] = 'Keywords';
+  $data['biblio_keywords']['help']  = t('All Keywords associated with the biblio node');
+
+
+  $data['biblio_sort_title'] = array(
+      'title'     => 'Sort Title',
+      'help'      => t('Sort Title is a normalized version of the Title with leading special characters and stop words removed, use for sorting only.'),
+      'field'     => array('handler' => 'biblio_handler_field'),
+      'sort'      => array('handler' => 'views_handler_sort'),
+      'filter'    => array('handler' => 'views_handler_filter_string'),
+      'argument'  => array('handler' => 'views_handler_argument_string')
+  );
+
+  $data['table']['join'] = array(
+    'node' => array(
+      // links directly to node via vid
+      'left_field' => 'vid',
+      'field'      => 'vid',
+      'type'       => 'left',
+    ),
+    'node_revision' => array(
+      'left_field' => 'vid',
+      'field'      => 'vid',
+      'type'       => 'left',
+    ),
+    );
+
+  $viewsdata['biblio'] = $data;
+
+  /**************** biblio_types table *********************/
+
+  $data = array();
+  $data['table']['group'] = t('Biblio');
+  $data['table']['join'] = array(
+    'node' => array(
+      'left_table' => 'biblio',
+      'left_field' => 'biblio_type',
+      'field' => 'tid',
+    ),
+    'node_revision' => array(
+      'left_table' => 'biblio',
+      'left_field' => 'biblio_type',
+      'field' => 'tid',
+    ),
+  );
+  $data['name'] =  array(
+    'field'   => array('handler' => 'views_handler_field'),
+    'sort'    => array('handler' => 'views_handler_sort'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'title'   => t('Type of Publication'),
+    'help'    => t('The type of publication: Journal, Book, Conference Paper, etc.')
+  );
+  $data['tid'] =  array(
+    'argument' => array(
+      'handler' => 'biblio_handler_argument_many_to_one',
+      'name table' => 'biblio_types',
+      'name field' => 'name',
+      'empty name field' => t('No Type'),
+      'numeric' => TRUE,
+    ),
+    'filter'  => array('handler' => 'biblio_handler_filter_biblio_type'),
+    'title'   => t('Type of Publication'),
+    'help'    => t('The type of publication: Journal, Book, Conference Paper, etc.')
+  );
+
+  $viewsdata['biblio_types'] = $data;
+
+  /**************** biblio contributors table **************/
+
+  $data = array();
+  $data['table']['group'] = t('Biblio');
+  $data['table']['join'] = array(
+    'node' => array(
+      'left_field' => 'vid',
+      'field' => 'vid',
+      'type'       => 'inner',
+    ),
+    'node_revision' => array(
+      'left_field' => 'vid',
+      'field' => 'vid',
+    ),
+    // This is provided for many_to_one argument
+    'biblio' => array(
+      'field' => 'vid',
+      'left_field' => 'vid',
+      'type'       => 'inner',
+    ),
+    'users' => array(
+      'left_table' => 'biblio_contributor_data',
+      'field' => 'cid',
+      'left_field' => 'cid',
+    ),
+  );
+  $data['cid'] = array(
+    'title' => t('Author ID'),
+    'help' => t('Filter by author id.'),
+    'argument' => array(
+      'handler'    => 'biblio_handler_argument_many_to_one',
+      'name table' => 'biblio_contributor_data',
+      'name field' => 'lastname',
+      'empty name field' => t('No Author'),
+      'numeric' => TRUE,
+    ),
+  'filter' => array(
+      'handler' => 'biblio_handler_filter_contributor',
+    )
+  );
+  $data['rank'] = array(
+    'title' => t('Author Rank'),
+    'help' => t('Rank defines the author order "0" being the first author, "1" the second and so on.'),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    )
+  );
+  $data['auth_type'] = array(
+    'title' => t('Author Type'),
+    'help' => t('Rank defines the type of author Author, Editor, Translator and so on.'),
+    'filter' => array(
+      'handler' => 'biblio_handler_filter_biblio_contributor_auth_type',
+    )
+  );
+
+  $viewsdata['biblio_contributor'] = $data;
+
+/**************** biblio_contributor_data table ***********/
+  $data = array();
+  $data['table']['group'] = t('Biblio');
+  $data['table']['base'] = array(
+    'field' => 'cid',
+    'title' => t('Biblio Authors'),
+  );
+  $data['table']['join'] = array(
+    'biblio_contributor' => array(
+      'left_field' => 'cid',
+      'field' => 'cid',
+    ),
+    'node' => array(
+      'left_table' => 'biblio_contributor',
+      'left_field' => 'cid',
+      'field' => 'cid',
+    ),
+    'users' => array(
+      'left_field' => 'uid',
+      'field' => 'drupal_uid',
+    ),
+    );
+  $data['drupal_uid'] =  array(
+    'field'     => array('handler' => 'views_handler_field'),
+    'filter'    => array('handler' => 'biblio_handler_filter_contributor_uid'),
+    'argument'  => array('handler' => 'views_handler_argument_numeric'),
+    'relationship' => array(
+      'handler' => 'views_handler_relationship',
+      'base' => 'users',
+      'base field' => 'uid',
+      'label' => t('user'),
+    ),
+
+    'title'     => t('Drupal UserID'),
+    'help'      => t('This is the Drupal user associated with the Biblio Author.')
+  );
+  $data['cid'] =  array(
+    'field'     => array('handler' => 'views_handler_field'),
+    'sort'      => array('handler' => 'biblio_handler_sort_contributor_lastname'),
+    'filter'    => array('handler' => 'biblio_handler_filter_contributor_lastname'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'title'     => t('Author id'),
+    'help'      => t('Author id')
+  );
+  $data['lastname'] =  array(
+    'field'     => array('handler' => 'views_handler_field'),
+    'sort'      => array('handler' => 'biblio_handler_sort_contributor_lastname'),
+    'filter'    => array('handler' => 'biblio_handler_filter_contributor_lastname'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'title'     => t('Author last name'),
+    'help'      => t('Author last name')
+  );
+  $data['firstname'] =  array(
+    'field'     => array('handler' => 'views_handler_field'),
+    'sort'      => array('handler' => 'views_handler_sort'),
+    'filter'    => array('handler' => 'views_handler_filter'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'title'     => t('Author first name'),
+    'help'      => t('Author first name')
+  );
+  $data['name'] =  array(
+    'field'     => array('handler' => 'views_handler_field'),
+    'sort'      => array('handler' => 'views_handler_sort'),
+    'filter'    => array('handler' => 'views_handler_filter'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'title'     => t('Author full name'),
+    'help'      => t('Author full name')
+  );
+  $data['prefix'] =  array(
+    'field'     => array('handler' => 'views_handler_field'),
+    'sort'      => array('handler' => 'views_handler_sort'),
+    'filter'    => array('handler' => 'views_handler_filter'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'title'     => t('Author preix'),
+    'help'      => t('Attributes which typically proceed the authors first name')
+  );
+  $data['suffix'] =  array(
+    'field'     => array('handler' => 'views_handler_field'),
+    'sort'      => array('handler' => 'views_handler_sort'),
+    'filter'    => array('handler' => 'views_handler_filter'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'title'     => t('Author suffix'),
+    'help'      => t('Attributes which typically follow the authors last name.')
+  );
+  $data['affiliation'] =  array(
+    'field'     => array('handler' => 'views_handler_field'),
+    'sort'      => array('handler' => 'views_handler_sort'),
+    'filter'    => array('handler' => 'views_handler_filter'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'title'     => t('Author affiliation'),
+    'help'      => t('Organization the author is affiliated with')
+  );
+
+  $viewsdata['biblio_contributor_data'] = $data;
+
+
+
+/***************** Describe the keyword table *************/
+
+  $data = array();
+  $data['table']['group'] = t('Biblio');
+  $data['table']['join'] = array(
+    'node' => array(
+      'left_field' => 'vid',
+      'field' => 'vid',
+    ),
+    'node_revision' => array(
+      'left_field' => 'vid',
+      'field' => 'vid',
+    ),
+    'biblio_keyword_data' => array(
+      'field' => 'kid',
+      'left_field' => 'kid',
+    ),
+  );
+  $data['kid'] = array(
+    'title' => t('Keyword ID'),
+    'help' => t('The Biblio keyword ID'),
+    'field' => array(
+      'title' => t('All keywords'),
+      'help' => t('Display all keywords associated with a node.'),
+      'handler' => 'biblio_handler_field_biblio_keyword_kid',
+    ),
+    'argument' => array(
+      'handler' => 'biblio_handler_argument_many_to_one',
+      'name table' => 'biblio_keyword_data',
+      'name field' => 'word',
+      'empty name field' => t('No Keyword'),
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'title' => t('Keyword ID'),
+      'handler' => 'biblio_handler_filter_biblio_keyword_kid',
+      'numeric' => TRUE,
+    ),
+    'skip base' => array('node', 'node_revision'),
+    );
+
+  $viewsdata['biblio_keyword'] = $data;
+
+  $viewsdata['biblio_keyword']['nid'] = array(
+    'title' => t('Node'),
+    'help' => t('Get all nodes tagged with a keyword.'),
+    'relationship' => array(
+      'handler' => 'views_handler_relationship',
+      'base' => 'node',
+      'base field' => 'nid',
+      'label' => t('node'),
+    ),
+  );
+
+
+/***************** Describe the keyword_data table ***********/
+
+  $data = array();
+  $data['table']['group'] = t('Biblio');
+  $data['table']['base'] = array(
+    'field' => 'kid',
+    'title' => t('Biblio Keywords'),
+  );
+
+  $data['table']['join'] = array(
+    'biblio_keyword' => array(
+      'left_field' => 'kid',
+      'field' => 'kid',
+    ),
+    'node' => array(
+      'left_table' => 'biblio_keyword',
+      'left_field' => 'kid',
+      'field' => 'kid',
+    ),
+    'biblio' => array(
+      'left_table' => 'biblio_keyword',
+      'left_field' => 'kid',
+      'field' => 'kid',
+    ),
+    );
+  $data['word'] =  array(
+    'field'     => array('handler' => 'biblio_handler_field_biblio_keyword_data_word'),
+    'filter'    => array('handler' => 'views_handler_filter_string'),
+    'argument'  => array('handler' => 'views_handler_argument_string'),
+    'sort'      => array('handler' => 'views_handler_sort'),
+    'title'     => t('Keyword'),
+    'help'      => t('A single keyword related to a biblio node'),
+    //'skip base' => array('node', 'node_revision'),
+  );
+  $data['kid'] =  array(
+    'field'     => array('handler' => 'views_handler_field_numeric'),
+ //   'filter'    => array('handler' => 'views_handler_filter'),
+ //   'argument'  => array('handler' => 'views_handler_argument'),
+    'title'     => t('Keyword ID'),
+    'skip base' => array('node', 'node_revision'),
+  );
+
+
+  $viewsdata['biblio_keyword_data'] = $data;
+
+  $export_links = module_invoke_all('biblio_export_options');
+  foreach ($export_links as $type => $name) {
+    $viewsdata['biblio'][$type.'_export'] = array(
+        'title' => t('Export link - ' . $name),
+        'help'  => t("Provides a link to export the data in ") . $name . t(" format"),
+        'field' => array(
+          'handler' => 'biblio_handler_field_export_link',
+          'group' => t('Biblio'),
+          'format' => $type,
+          'format name' => $name,
+       ),
+    );
+
+  }
+
+  return $viewsdata;
+}
+
+function template_preprocess_views_view_unformatted__biblio_year(&$vars) {
+  $view     = $vars['view'];
+  $rows     = $vars['rows'];
+
+  $vars['classes'] = array();
+  // Set up striping values.
+  foreach ($rows as $id => $row) {
+    $vars['classes'][$id] = 'views-row';
+    $vars['classes'][$id] .= ' views-row-' . ($id + 1);
+    $vars['classes'][$id] .= ' views-row-' . ($id % 2 ? 'even' : 'odd');
+    if ($id == 0) {
+      $vars['classes'][$id] .= ' views-row-first';
+    }
+  }
+  $vars['classes'][$id] .= ' views-row-last';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio.views_default.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,642 @@
+<?php
+/**
+ * @file
+ * Contains default views on behalf of the biblio module.
+ */
+
+/**
+ * Implementation of hook_default_view_views().
+ */
+function biblio_views_default_views() {
+  $view = new view;
+  $view->name = 'biblio_views';
+  $view->description = '';
+  $view->tag = '';
+  $view->view_php = '';
+  $view->base_table = 'node';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = TRUE; /* Edit this to TRUE to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('fields', array(
+  'citation' => array(
+    'label' => '',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'style_name' => 'vancouver',
+    'exclude' => 0,
+    'id' => 'citation',
+    'table' => 'biblio',
+    'field' => 'citation',
+    'relationship' => 'none',
+  ),
+  ));
+  $handler->override_option('sorts', array(
+  'biblio_year' => array(
+    'order' => 'DESC',
+    'id' => 'biblio_year',
+    'table' => 'biblio',
+    'field' => 'biblio_year',
+    'relationship' => 'none',
+  ),
+  'name' => array(
+    'id' => 'name',
+    'table' => 'biblio_types',
+    'field' => 'name',
+  ),
+  ));
+  $handler->override_option('arguments', array(
+  'biblio_year' => array(
+    'id' => 'biblio_year',
+    'table' => 'biblio',
+    'field' => 'biblio_year',
+  ),
+  ));
+  $handler->override_option('filters', array(
+  'status' => array(
+    'operator' => '=',
+    'value' => '1',
+    'group' => '0',
+    'exposed' => FALSE,
+    'expose' => array(
+      'operator' => FALSE,
+      'label' => '',
+  ),
+    'id' => 'status',
+    'table' => 'node',
+    'field' => 'status',
+    'relationship' => 'none',
+  ),
+  'type' => array(
+    'operator' => 'in',
+    'value' => array(
+      'biblio' => 'biblio',
+  ),
+    'group' => '0',
+    'exposed' => FALSE,
+    'expose' => array(
+      'operator' => FALSE,
+      'label' => '',
+  ),
+    'id' => 'type',
+    'table' => 'node',
+    'field' => 'type',
+    'relationship' => 'none',
+  ),
+  ));
+  $handler->override_option('access', array(
+  'type' => 'none',
+  ));
+  $handler->override_option('cache', array(
+  'type' => 'none',
+  ));
+  $handler->override_option('header_format', '1');
+  $handler->override_option('header_empty', 0);
+  $handler->override_option('empty', 'Nothing found');
+  $handler->override_option('empty_format', '1');
+  $handler->override_option('use_pager', '1');
+  $handler->override_option('style_options', array(
+  'grouping' => 'name',
+  ));
+  $handler->override_option('row_options', array(
+  'inline' => array(),
+  'separator' => '',
+  ));
+  $handler = $view->new_display('page', 'Group by Year', 'page_1');
+  $handler->override_option('fields', array(
+  'citation' => array(
+    'label' => '',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'style_name' => 'vancouver',
+    'exclude' => 0,
+    'id' => 'citation',
+    'table' => 'biblio',
+    'field' => 'citation',
+    'relationship' => 'none',
+  ),
+  'biblio_year' => array(
+    'label' => '',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'biblio_label' => 0,
+    'exclude' => 1,
+    'id' => 'biblio_year',
+    'table' => 'biblio',
+    'field' => 'biblio_year',
+    'override' => array(
+      'button' => 'Override',
+  ),
+    'relationship' => 'none',
+  ),
+  ));
+  $handler->override_option('arguments', array(
+  'biblio_year' => array(
+    'default_action' => 'ignore',
+    'style_plugin' => 'default_summary',
+    'style_options' => array(),
+    'wildcard' => 'all',
+    'wildcard_substitution' => 'All',
+    'title' => '',
+    'breadcrumb' => '',
+    'default_argument_type' => 'fixed',
+    'default_argument' => '',
+    'validate_type' => 'none',
+    'validate_fail' => 'not found',
+    'glossary' => 0,
+    'limit' => '0',
+    'case' => 'none',
+    'path_case' => 'none',
+    'transform_dash' => 0,
+    'id' => 'biblio_year',
+    'table' => 'biblio',
+    'field' => 'biblio_year',
+    'validate_user_argument_type' => 'uid',
+    'validate_user_roles' => array(
+      '2' => 0,
+  ),
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+    'default_options_div_prefix' => '',
+    'default_argument_user' => 0,
+    'default_argument_fixed' => '',
+    'default_argument_php' => '',
+    'validate_argument_node_type' => array(
+      'image' => 0,
+      'biblio' => 0,
+      'book' => 0,
+      'feed' => 0,
+      'page' => 0,
+      'story' => 0,
+      'test' => 0,
+  ),
+    'validate_argument_node_access' => 0,
+    'validate_argument_nid_type' => 'nid',
+    'validate_argument_vocabulary' => array(
+      '2' => 0,
+      '3' => 0,
+      '4' => 0,
+  ),
+    'validate_argument_type' => 'tid',
+    'validate_argument_transform' => 0,
+    'validate_user_restrict_roles' => 0,
+    'image_size' => array(
+      '_original' => '_original',
+      'thumbnail' => 'thumbnail',
+      'preview' => 'preview',
+  ),
+    'validate_argument_php' => '',
+  ),
+  ));
+  $handler->override_option('style_options', array(
+  'grouping' => 'biblio_year',
+  ));
+  $handler->override_option('path', 'view/biblio/year');
+  $handler->override_option('menu', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  ));
+  $handler = $view->new_display('page', 'Group by Type', 'page_2');
+  $handler->override_option('fields', array(
+  'citation' => array(
+    'label' => '',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'style_name' => 'vancouver',
+    'exclude' => 0,
+    'id' => 'citation',
+    'table' => 'biblio',
+    'field' => 'citation',
+    'relationship' => 'none',
+  ),
+  'name' => array(
+    'label' => '',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'exclude' => 1,
+    'id' => 'name',
+    'table' => 'biblio_types',
+    'field' => 'name',
+    'relationship' => 'none',
+  ),
+  ));
+  $handler->override_option('sorts', array(
+  'name' => array(
+    'order' => 'ASC',
+    'id' => 'name',
+    'table' => 'biblio_types',
+    'field' => 'name',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  'biblio_year' => array(
+    'order' => 'DESC',
+    'id' => 'biblio_year',
+    'table' => 'biblio',
+    'field' => 'biblio_year',
+    'relationship' => 'none',
+  ),
+  ));
+  $handler->override_option('path', 'view/biblio/type');
+  $handler->override_option('menu', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  ));
+  $handler = $view->new_display('page', 'Group by Title', 'page_3');
+  $handler->override_option('fields', array(
+  'citation' => array(
+    'label' => '',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'style_name' => 'vancouver',
+    'exclude' => 0,
+    'id' => 'citation',
+    'table' => 'biblio',
+    'field' => 'citation',
+    'relationship' => 'none',
+  ),
+  'biblio_year' => array(
+    'label' => 'Year of Publication',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'biblio_label' => 1,
+    'exclude' => 1,
+    'id' => 'biblio_year',
+    'table' => 'biblio',
+    'field' => 'biblio_year',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  ));
+  $handler->override_option('sorts', array(
+  'biblio_year' => array(
+    'order' => 'DESC',
+    'id' => 'biblio_year',
+    'table' => 'biblio',
+    'field' => 'biblio_year',
+    'relationship' => 'none',
+  ),
+  'title' => array(
+    'order' => 'ASC',
+    'id' => 'title',
+    'table' => 'node',
+    'field' => 'title',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  ));
+  $handler->override_option('style_options', array(
+  'grouping' => 'biblio_year',
+  ));
+  $handler->override_option('path', 'view/biblio/title');
+  $handler->override_option('menu', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  ));
+  $handler = $view->new_display('page', 'Filter by Keyword ID', 'page_4');
+  $handler->override_option('arguments', array(
+  'kid' => array(
+    'default_action' => 'ignore',
+    'style_plugin' => 'default_summary',
+    'style_options' => array(),
+    'wildcard' => 'all',
+    'wildcard_substitution' => 'All',
+    'title' => 'Contains the keyword %1',
+    'breadcrumb' => '',
+    'default_argument_type' => 'fixed',
+    'default_argument' => '',
+    'validate_type' => 'none',
+    'validate_fail' => 'not found',
+    'break_phrase' => 1,
+    'add_table' => 0,
+    'require_value' => 0,
+    'reduce_duplicates' => 0,
+    'id' => 'kid',
+    'table' => 'biblio_keyword',
+    'field' => 'kid',
+    'validate_user_argument_type' => 'uid',
+    'validate_user_roles' => array(
+      '2' => 0,
+  ),
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+    'default_options_div_prefix' => '',
+    'default_argument_user' => 0,
+    'default_argument_fixed' => '',
+    'default_argument_php' => '',
+    'validate_argument_node_type' => array(
+      'image' => 0,
+      'biblio' => 0,
+      'book' => 0,
+      'feed' => 0,
+      'page' => 0,
+      'story' => 0,
+      'test' => 0,
+  ),
+    'validate_argument_node_access' => 0,
+    'validate_argument_nid_type' => 'nid',
+    'validate_argument_vocabulary' => array(
+      '2' => 0,
+      '3' => 0,
+      '4' => 0,
+  ),
+    'validate_argument_type' => 'tid',
+    'validate_argument_transform' => 0,
+    'validate_user_restrict_roles' => 0,
+    'image_size' => array(
+      '_original' => '_original',
+      'thumbnail' => 'thumbnail',
+      'preview' => 'preview',
+  ),
+    'validate_argument_php' => '',
+  ),
+  ));
+  $handler->override_option('path', 'view/biblio/keyword');
+  $handler->override_option('menu', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  ));
+  $handler = $view->new_display('page', 'Filter by Author ID', 'page_5');
+  $handler->override_option('arguments', array(
+  'cid' => array(
+    'default_action' => 'ignore',
+    'style_plugin' => 'default_summary',
+    'style_options' => array(),
+    'wildcard' => 'all',
+    'wildcard_substitution' => 'All',
+    'title' => '',
+    'breadcrumb' => '',
+    'default_argument_type' => 'fixed',
+    'default_argument' => '',
+    'validate_type' => 'none',
+    'validate_fail' => 'not found',
+    'break_phrase' => 1,
+    'add_table' => 0,
+    'require_value' => 0,
+    'reduce_duplicates' => 0,
+    'id' => 'cid',
+    'table' => 'biblio_contributor',
+    'field' => 'cid',
+    'validate_user_argument_type' => 'uid',
+    'validate_user_roles' => array(
+      '2' => 0,
+  ),
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+    'default_options_div_prefix' => '',
+    'default_argument_user' => 0,
+    'default_argument_fixed' => '',
+    'default_argument_php' => '',
+    'validate_argument_node_type' => array(
+      'image' => 0,
+      'biblio' => 0,
+      'book' => 0,
+      'feed' => 0,
+      'page' => 0,
+      'story' => 0,
+      'test' => 0,
+  ),
+    'validate_argument_node_access' => 0,
+    'validate_argument_nid_type' => 'nid',
+    'validate_argument_vocabulary' => array(
+      '2' => 0,
+      '3' => 0,
+      '4' => 0,
+  ),
+    'validate_argument_type' => 'tid',
+    'validate_argument_transform' => 0,
+    'validate_user_restrict_roles' => 0,
+    'image_size' => array(
+      '_original' => '_original',
+      'thumbnail' => 'thumbnail',
+      'preview' => 'preview',
+  ),
+    'validate_argument_php' => '',
+  ),
+  ));
+  $handler->override_option('path', 'view/biblio/author');
+  $handler->override_option('menu', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  ));
+  $handler = $view->new_display('page', 'Browse by Year', 'page_6');
+  $handler->override_option('fields', array(
+  'biblio_year' => array(
+    'label' => '',
+    'alter' => array(
+      'alter_text' => 0,
+      'text' => '',
+      'make_link' => 0,
+      'path' => '',
+      'link_class' => '',
+      'alt' => '',
+      'prefix' => '',
+      'suffix' => '',
+      'help' => '',
+      'trim' => 0,
+      'max_length' => '',
+      'word_boundary' => 1,
+      'ellipsis' => 1,
+      'strip_tags' => 0,
+      'html' => 0,
+  ),
+    'biblio_label' => 0,
+    'exclude' => 0,
+    'id' => 'biblio_year',
+    'table' => 'biblio',
+    'field' => 'biblio_year',
+    'override' => array(
+      'button' => 'Use default',
+  ),
+    'relationship' => 'none',
+  ),
+  ));
+  $handler->override_option('sorts', array());
+  $handler->override_option('arguments', array());
+  $handler->override_option('distinct', 0);
+  $handler->override_option('style_plugin', 'grid');
+  $handler->override_option('style_options', array(
+  'grouping' => '',
+  'columns' => '4',
+  'alignment' => 'horizontal',
+  ));
+  $handler->override_option('path', 'view/biblio/years');
+  $handler->override_option('menu', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+  'type' => 'none',
+  'title' => '',
+  'description' => '',
+  'weight' => 0,
+  ));
+
+  $views[$view->name] = $view;
+  return $views;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_argument_many_to_one.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * Argument handler for 'associated tables'. (Used for types, authors, keywords)
+ */
+class biblio_handler_argument_many_to_one extends views_handler_argument_many_to_one {
+
+  /**
+   * Override the behavior of title_query(). Get the corresponding names (instead of the ID values).
+   */
+  function title_query() {
+    $names = array();
+    $result = db_query('SELECT ' . $this->name_field . ' FROM {' . $this->name_table
+      . '} WHERE ' . $this->real_field . ' IN (:vids)',  array(':vids' => implode(', ', $this->value)));
+    foreach ($result as $row) {
+      $names[] = $row->{$this->name_field};
+    }
+    return !empty($names) ? $names : array(t('Invalid input'));
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_citation.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,128 @@
+<?php
+class biblio_handler_citation extends views_handler_field {
+  function init(&$view, &$options) {
+    parent::init($view, $options);
+    $this->additional_fields['nid'] = array('table' => 'node', 'field' => 'nid');
+  }
+
+  function query() {
+    $this->field_alias = 'nid';
+    $this->add_additional_fields();
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['style_name'] = array('default' => biblio_get_style());
+    $options['export_links'] = array('default' => 1);
+    $options['file_attachments'] = array('default' => 1);
+    $options['open_url_link'] = array('default' => 1);
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['style_name'] = array(
+      '#type' => 'select',
+      '#title' => t('Style'),
+      '#default_value' => $this->options['style_name'],
+      '#options' => biblio_get_styles(),
+      '#description' => t('Define the layout of citation.')
+    );
+    $form['export_links'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show export links'),
+      '#default_value' => $this->options['export_links'],
+      '#description' => t('This will add a set of links to export the entry in various file formats such as Bibtex or RIS.')
+    );
+    $form['file_attachments'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show download links for file attachments'),
+      '#default_value' => $this->options['file_attachments'],
+      '#description' => t('If there are files attached to the entry, this will add a download link for each file attached.')
+    );
+    $form['open_url_link'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show OpenURL links'),
+      '#default_value' => $this->options['open_url_link'],
+      '#description' => t('This will add an !openurl link to the entry, assuming you have competed the OpenURL configuration on the Biblio !settings page.', array('!openurl' => l('OpenURL', "http://en.wikipedia.org/wiki/OpenURL"), '!settings' => l('settings', 'admin/config/content/biblio') )),
+    );
+  }
+
+  function pre_render(&$values) {
+    $nids  = array();
+    $nodes = array();
+
+    foreach ($values as $result) {
+      if (!empty($result->{$this->aliases['nid']})) {
+        $nids[] = $result->{$this->aliases['nid']};
+      }
+    }
+
+    if ($nids) {
+      $langcode = $GLOBALS['language_content']->language;
+      $nodes = node_load_multiple($nids);
+      if (!empty($nodes)) {
+        field_attach_prepare_view('node', $nodes, 'full', $langcode);
+        entity_prepare_view('node',  $nodes, $langcode);
+
+        foreach ($values as $key => $result) {
+          if (isset($result->{$this->aliases['nid']})) {
+            $values[$key]->node = $nodes[$result->{$this->aliases['nid']}];
+          }
+        }
+      }
+    }
+  }
+
+  function render($values) {
+    $output = '';
+
+    if (!isset($values->node) || $values->node->type != 'biblio') {
+      return;
+    }
+
+    if (empty($this->biblio_base)) {
+      $this->biblio_base = variable_get('biblio_base', 'biblio');
+    }
+
+    $item = $values->node;
+
+    if (isset($item->biblio_year)) $item->biblio_year = _biblio_text_year($item->biblio_year);
+    if (variable_get('biblio_hide_bibtex_braces', 0)) {
+      $item->title = biblio_remove_brace($item->title);
+    }
+
+    if (!$item->status) {
+      $output .= '<div id="node-' . $item->nid . '" class="node node-unpublished">';
+    }
+
+    // first add the styled entry...
+    $output .= theme('biblio_style', array('node' => $item, 'style_name' => $this->options['style_name']));
+
+    $annotation_field = variable_get('biblio_annotations', 'none');
+    if ($annotation_field != 'none' && $item-> $annotation_field) {
+      $output .= '<div class="biblio-annotation">';
+      $output .= filter_xss($item->$annotation_field, biblio_get_allowed_tags());
+      $output .= '</div>';
+    }
+
+    $openurl_base = variable_get('biblio_baseopenurl', '');
+    if (!empty($openurl_base) && $this->options['open_url_link']) {
+      $output .= theme('biblio_openurl', array('openURL' => biblio_openurl($item)));
+    }
+
+    if (biblio_access('export') && $this->options['export_links']) {
+      $output .= theme('biblio_export_links', array('node' => $item));
+    }
+
+    if (biblio_access('download', $item) && $this->options['file_attachments']) {
+      $output .= theme('biblio_download_links', array('node' => $item));
+    }
+    if (!$item->status) {
+      $output .= '</div>';
+    }
+
+    return $output;
+   }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,71 @@
+<?php
+
+class biblio_handler_field extends views_handler_field {
+
+  function init(&$view, &$options) {
+    parent::init($view, $options);
+
+    if (!$this->options['biblio_label']) return;
+    $this->definition['click sortable'] = array('default' => TRUE);
+
+    $result = db_query("SELECT bft.tid, bftd.title FROM {biblio_field_type} bft
+            INNER JOIN {biblio_fields} bf ON bft.fid=bf.fid AND bf.name = :name
+            INNER JOIN {biblio_field_type_data} bftd ON bftd.ftdid=bft.ftdid",
+                        array(':name' => $options['field']))
+                        ;
+    foreach ($result as $label) {
+      $this->labels[$label->tid] = $label->title;
+    }
+  }
+
+  function query() {
+    // add the biblio_type field as tid
+    $this->ensure_my_table();
+    if ($this->options['biblio_label']) {
+      $this->query->add_field($this->table_alias, 'biblio_type', 'biblio_tid');
+    }
+    parent::query();
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['biblio_label'] = array('default' => TRUE);
+
+    return $options;
+  }
+  function options_form(&$form, &$form_state) {
+    $form['biblio_label'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Use label specific to biblio type'),
+      '#description' => 'Check this option to use the type-specific field labels as defined in '
+      . l(t('biblio settings'), 'admin/config/content/biblio/fields/type'),
+      '#default_value' => $this->options['biblio_label'],
+    );
+    parent::options_form($form, $form_state);
+    $form['label'] += array(
+      '#process' => array('ctools_dependent_process'),
+      '#dependency' => array(
+        'edit-options-biblio-label' => array(0),
+      ),
+    );
+  }
+  function set_label(&$values) {
+    if (!$this->options['biblio_label']) return;
+    $tid = $values->biblio_tid;
+    $this->options['label'] = isset($this->labels[$tid]) ? $this->labels[$tid] : $this->labels[0];
+  }
+
+  function pre_render(&$values) {
+    foreach ($values as $result) {
+      if (!empty($result->biblio_biblio_year)) { // this converts values like 9999 or 9998 to "Submitted" and "In Press"
+        $result->biblio_biblio_year = _biblio_text_year($result->biblio_biblio_year);
+      }
+    }
+    return $values;
+  }
+
+  function render($values) {
+   $this->set_label($values);
+   return parent::render($values);
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_field_biblio_keyword_data_word.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,60 @@
+<?php
+class biblio_handler_field_biblio_keyword_data_word extends views_handler_field {
+  /**
+   * Constructor to provide additional field to add.
+   *
+   * This constructer assumes the term_data table. If using another
+   * table, we'll need to be more specific.
+   */
+  function construct() {
+    parent::construct();
+    $this->additional_fields['kid'] = 'kid';
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link_to_keyword'] = array(
+    	'default' => FALSE
+    );
+    $options['multi_type'] = array(
+      'default' => 'separator'
+    );
+    $options['separator'] = array(
+      'default' => ', '
+    );
+
+    return $options;
+  }
+
+  /**
+   * Provide link to taxonomy option
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['link_to_keyword'] = array(
+      '#title' => t('Link this field to its keyword page'),
+      '#description' => t('This will override any other link you have set.'),
+      '#type' => 'checkbox',
+      '#default_value' => !empty($this->options['link_to_keyword']),
+    );
+  }
+  /**
+   * Render whatever the data is as a link to the taxonomy.
+   *
+   * Data should be made XSS safe prior to calling this function.
+   */
+  function render_link($data, $values) {
+    if (!empty($this->options['link_to_keyword']) && !empty($values->{$this->aliases['kid']}) && $data !== NULL && $data !== '') {
+      $kid = $values->{$this->aliases['kid']};
+      $base = variable_get('biblio_base', 'biblio');
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = $base .'/keyword/' . $kid;
+    }
+    return $data;
+  }
+
+  function render($values) {
+    return $this->render_link(check_plain($values->{$this->field_alias}), $values);
+
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_field_biblio_keyword_kid.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,40 @@
+<?php
+
+class biblio_handler_field_biblio_keyword_kid extends views_handler_field_prerender_list {
+  function init(&$view, $options) {
+    parent::init($view, $options);
+    $this->multiple = TRUE;
+    if ($view->base_table == 'node_revision') {
+      $this->additional_fields['vid'] = array('table' => 'node_revision', 'field' => 'vid');
+    }
+    else {
+      $this->additional_fields['vid'] = array('table' => 'node', 'field' => 'vid');
+    }
+  }
+
+
+  function pre_render($values) {
+    $this->field_alias = $this->aliases['vid'];
+    $vids = array();
+    foreach ($values as $result) {
+      if (!empty($result->{$this->aliases['vid']})) {
+        $vids[] = $result->{$this->aliases['vid']};
+      }
+    }
+    if ($vids) {
+      $query = db_select('biblio_keyword_data', 'bkd');
+      $query->innerJoin('biblio_keyword', 'bk', 'bkd.kid = bk.kid');
+      $query->fields('bkd');
+      $query->addField('bk', 'vid', 'node_vid');
+      $query->orderby('bkd.word');
+      $query->condition('bk.vid', $vids);
+      $query->addMetaData('base_table', 'biblio_keyword');
+      $query->addTag('node_access');
+      $result = $query->execute();
+
+      foreach ($result as $term) {
+        $this->items[$term->node_vid][$term->kid] = check_plain($term->word);
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_field_biblio_type.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,41 @@
+<?php
+
+class biblio_handler_field_biblio_type extends views_handler_field {
+  function init(&$view, $options) {
+    parent::init($view, $options);
+    if ($view->base_table == 'node_revision') {
+      $this->additional_fields['vid'] = array('table' => 'node_revision', 'field' => 'vid');
+    }
+    else {
+      $this->additional_fields['vid'] = array('table' => 'node', 'field' => 'vid');
+    }
+  }
+
+
+  function pre_render($values) {
+    $this->field_alias = $this->aliases['vid'];
+    $vids = array();
+    foreach ($values as $result) {
+      if (!empty($result->{$this->aliases['vid']})) {
+        $vids[] = $result->{$this->aliases['vid']};
+      }
+    }
+    //print_r($values);
+    if ($vids) {
+
+      //$result = db_query("SELECT bt.name AS node_vid, bkd.* FROM {biblio_keyword_data} bkd INNER JOIN {biblio_keyword} bk ON bkd.kid = bk.kid WHERE bk.vid IN (" . implode(', ', $vids) . ") ORDER BY  bkd.word");
+      $result = db_query("SELECT name, tid
+                          FROM {biblio_types} t
+                          WHERE IN (:vids)", array(':vids' => implode(', ', $vids)));
+
+      foreach ($result as $term) {
+//        if (empty($this->options['link_to_taxonomy'])) {
+          $this->items[$term->node_vid][$term->kid] = check_plain($term->word);
+//        }
+//        else {
+//          $this->items[$term->node_vid][$term->kid] = l($term->word, taxonomy_term_path($term));
+//        }
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_field_contributor.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,279 @@
+<?php
+class biblio_handler_field_contributor extends biblio_handler_field {
+  function init(&$view, &$options) {
+    module_load_include('inc', 'biblio', 'includes/biblio.contributors');
+    parent::init($view, $options);
+    $this->multiple = TRUE;
+    $this->additional_fields['vid'] = array('table' => 'biblio', 'field' => 'vid');
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['auth_category'] = array('default' => 1);
+    $options['auth_links'] = array('default' => 0);
+    $options['initialize'] = array('default' => TRUE);
+    $options['initialize_with'] = array('default' => '.');
+    $options['initialize_with_hyphen'] = array('default' => FALSE);
+    $options['separator'] = array('default' => '; ');
+    $options['sort_separator'] = array('default' => ', ');
+    $options['short_form'] = array('default' => 0);
+    $options['name_order'] = array('default' => 'first-last');
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    $form['auth_category'] = array(
+      '#type' => 'select',
+      '#title' => t('Category of Author'),
+      '#default_value' => $this->options['auth_category'],
+      '#options' => array(
+        0 => t('All categories'),
+        1 => t('Primary'),
+        2 => t('Secondary'),
+        3 => t('Tertiary'),
+        4 => t('Subsidiary'),
+        5 => t('Corporate/Institutional')
+      ),
+
+    );
+    $form['formatting'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Author format'),
+      '#collapsible' => TRUE,
+    );
+    $form['name_order'] = array(
+      '#type' => 'select',
+      '#title' => t('Name order'),
+      '#default_value' => $this->options['name_order'],
+      '#options' => array(
+        'first-last' => t('First name first'),
+        'last-first' => t('Last name first'),
+      ),
+      '#description' => t('The order that first and last names appear for each author.'),
+      '#fieldset' => 'formatting',
+    );
+    $form['initialize'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Shorten given names'),
+      '#default_value' => $this->options['initialize'],
+      '#description' => t('Shorten given names to single initial each.'),
+    	'#fieldset' => 'formatting',
+    );
+    $form['short_form'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show only "family" names'),
+      '#default_value' => $this->options['short_form'],
+      '#description' => t('Show only family name, no first name or initials.'),
+      '#fieldset' => 'formatting',
+    );
+    $form['separators'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Separators'),
+      '#collapsible' => TRUE,
+    );
+    $form['initialize_with'] = array(
+      '#type' => 'textfield',
+      '#size' => 5,
+      '#title' => t('Initial separator'),
+      '#default_value' => $this->options['initialize_with'],
+      '#description' => t('Enter the character (if any) which will be used to separate the initials.'),
+      '#fieldset' => 'separators',
+    );
+    $form['sort_separator'] = array(
+      '#type' => 'textfield',
+      '#size' => 5,
+      '#title' => t('Sort separator'),
+      '#default_value' => $this->options['sort_separator'],
+      '#description' => t('Enter the character which will be used to separate the last name from the first name (or initials) when displayed last name first (Smith, John).'),
+      '#fieldset' => 'separators',
+    );
+    $form['separator'] = array(
+      '#type' => 'textfield',
+      '#size' => 5,
+      '#title' => t('Author separator'),
+      '#default_value' => $this->options['separator'],
+      '#required' => TRUE,
+      '#description' => t('Enter the character which will be used to separate the authors (Smith, John; Doe, Jane).'),
+      '#fieldset' => 'separators',
+    );
+    parent::options_form($form, $form_state);
+
+  }
+
+  function query() {
+    $this->add_additional_fields();
+    $this->field_alias = $this->aliases['vid'];
+  }
+
+  function post_execute(&$values) {
+    $vids = array();
+    $this->items = array();
+    $filter = '';
+
+    foreach ($values as $result) {
+      // Don't add empty results to the array.
+      if (isset($this->aliases['vid']) && !empty($result->{$this->aliases['vid']})) {
+        $vids[] = $result->{$this->aliases['vid']};
+      }
+    }
+
+    if (count($vids)) {
+      $this->items = biblio_load_contributors_multiple($vids, $this->options['auth_category']);
+    }
+  }
+
+  function render($values) {
+    parent::set_label($values);
+    $vid = $values->{$this->field_alias};
+    if (!isset($this->items[$vid])) return NULL;
+    return $this->render_contriubutors($this->items[$vid]);
+  }
+
+  function render_contriubutors($contributors) {
+    $authors = array();
+    if (!isset($this->alnum)) {
+      list($this->alnum, $this->alpha, $this->cntrl, $this->dash,
+          $this->digit, $this->graph, $this->lower, $this->print,
+          $this->punct, $this->space, $this->upper, $this->word,
+          $this->patternModifiers) = $this->get_regex_patterns();
+    }
+
+    foreach ($contributors as $rank => $author) {
+      $author = (object)$author;
+      if ($author->literal == 1) {
+        $authors[] = $author->name;
+      }
+      else {
+        if (!empty($author->firstname) && $this->options['initialize'] == 1) {
+          $author->firstname = preg_replace("/([$this->upper])[$this->lower]+/$this->patternModifiers", '\\1', $author->firstname);
+          $author->firstname = preg_replace("/(?<=[-$this->upper]) +(?=[-$this->upper])/$this->patternModifiers", "", $author->firstname);
+          $author->initials = $author->firstname . $author->initials;
+        }
+        if (isset($author->initials)) {
+          // within initials, remove any dots:
+          $author->initials = preg_replace("/([$this->upper])\.+/$this->patternModifiers", "\\1", $author->initials);
+          // within initials, remove any spaces *between* initials:
+          $author->initials = preg_replace("/(?<=[-$this->upper]) +(?=[-$this->upper])/$this->patternModifiers", "", $author->initials);
+          if ($this->options['initialize_with_hyphen'] === FALSE) {
+            $author->initials = preg_replace("/-/", '', $author->initials);
+          }
+          // within initials, add a space after a hyphen, but only if ...
+          if (preg_match("/ $/", $this->options['initialize_with'])) {// ... the delimiter that separates initials ends with a space
+            $author->initials = preg_replace("/-(?=[$this->upper])/$this->patternModifiers", "- ", $author->initials);
+          }
+          // then, separate initials with the specified delimiter:
+          $init_sep = $this->options['initialize_with'];
+          $author->initials = preg_replace("/([$this->upper])(?=[^$this->lower]+|$)/$this->patternModifiers", "\\1$init_sep", $author->initials);
+
+          //      $shortenInitials = (isset($options['numberOfInitialsToKeep)) ? $options['numberOfInitialsToKeep : FALSE;
+          //      if ($shortenInitials) $given = drupal_substr($given, 0, $shortenInitials);
+
+          if ($this->options['initialize'] == 1) {
+            $author->firstname = $author->initials;
+            // if ($shortenInitials) $author->firstname = drupal_substr($author->firstname, 0, $shortenInitials);
+          }
+          elseif (!empty($author->firstname)) {
+            $author->firstname = $author->firstname . ' ' . $author->initials;
+          }
+          elseif (empty($author->firstname)) {
+            $author->firstname = $author->initials;
+          }
+        }
+
+        if (isset($author->lastname)) {
+          if ($this->options['short_form'] == 1) {
+            $authors[] = $author->lastname;
+          }
+          else {
+            switch ($this->options['name_order']) {
+              case 'last-first':
+                $authors[] = $author->lastname . $this->options['sort_separator'] . $author->firstname;
+                break;
+              default:
+                $authors[] = $author->firstname . ' ' . $author->lastname ;
+            }
+          }
+        }
+      }
+    }
+
+    return implode($this->options['separator'], $authors);
+  }
+  function get_regex_patterns() {
+    // Checks if PCRE is compiled with UTF-8 and Unicode support
+    if (!@preg_match('/\pL/u', 'a')) {
+      // probably a broken PCRE library
+      return $this->get_latin1_regex();
+    }
+    else {
+      // Unicode safe filter for the value
+      return $this->get_utf8_regex();
+    }
+  }
+
+  function get_latin1_regex() {
+    $alnum = "[:alnum:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 letters:
+    $alpha = "[:alpha:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 control characters:
+    $cntrl = "[:cntrl:]";
+    // Matches ISO-8859-1 dashes & hyphens:
+    $dash = "-–";
+    // Matches ISO-8859-1 digits:
+    $digit = "[\d]";
+    // Matches ISO-8859-1 printing characters (excluding space):
+    $graph = "[:graph:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 lower case letters:
+    $lower = "[:lower:]äåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 printing characters (including space):
+    $print = "[:print:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Matches ISO-8859-1 punctuation:
+    $punct = "[:punct:]";
+    // Matches ISO-8859-1 whitespace (separating characters with no visual representation):
+    $space = "[\s]";
+    // Matches ISO-8859-1 upper case letters:
+    $upper = "[:upper:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆ";
+    // Matches ISO-8859-1 "word" characters:
+    $word = "_[:alnum:]ÄÅÃÀÂÃÇÉÈÊËÑÖØÓÒÔÕÜÚÙÛÃÌÎÃÆäåáàâãçéèêëñöøóòôõüúùûíìîïæÿß";
+    // Defines the PCRE pattern modifier(s) to be used in conjunction with the above variables:
+    // More info: <http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php>
+    $patternModifiers = "";
+
+    return array($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
+    $print, $punct, $space, $upper, $word, $patternModifiers);
+
+  }
+  function get_utf8_regex() {
+    // Matches Unicode letters & digits:
+    $alnum = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}"; // Unicode-aware equivalent of "[:alnum:]"
+    // Matches Unicode letters:
+    $alpha = "\p{Ll}\p{Lu}\p{Lt}\p{Lo}"; // Unicode-aware equivalent of "[:alpha:]"
+    // Matches Unicode control codes & characters not in other categories:
+    $cntrl = "\p{C}"; // Unicode-aware equivalent of "[:cntrl:]"
+    // Matches Unicode dashes & hyphens:
+    $dash = "\p{Pd}";
+    // Matches Unicode digits:
+    $digit = "\p{Nd}"; // Unicode-aware equivalent of "[:digit:]"
+    // Matches Unicode printing characters (excluding space):
+    $graph = "^\p{C}\t\n\f\r\p{Z}"; // Unicode-aware equivalent of "[:graph:]"
+    // Matches Unicode lower case letters:
+    $lower = "\p{Ll}\p{M}"; // Unicode-aware equivalent of "[:lower:]"
+    // Matches Unicode printing characters (including space):
+    $print = "\P{C}"; // same as "^\p{C}", Unicode-aware equivalent of "[:print:]"
+    // Matches Unicode punctuation (printing characters excluding letters & digits):
+    $punct = "\p{P}"; // Unicode-aware equivalent of "[:punct:]"
+    // Matches Unicode whitespace (separating characters with no visual representation):
+    $space = "\t\n\f\r\p{Z}"; // Unicode-aware equivalent of "[:space:]"
+    // Matches Unicode upper case letters:
+    $upper = "\p{Lu}\p{Lt}"; // Unicode-aware equivalent of "[:upper:]"
+    // Matches Unicode "word" characters:
+    $word = "_\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}"; // Unicode-aware equivalent of "[:word:]" (or "[:alnum:]" plus "_")
+    // Defines the PCRE pattern modifier(s) to be used in conjunction with the above variables:
+    // More info: <http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php>
+    $patternModifiers = "u"; // the "u" (PCRE_UTF8) pattern modifier causes PHP/PCRE to treat pattern strings as UTF-8
+    return array($alnum, $alpha, $cntrl, $dash, $digit, $graph, $lower,
+    $print, $punct, $space, $upper, $word, $patternModifiers);
+  }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_field_export_link.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,43 @@
+<?php
+class biblio_handler_field_export_link extends views_handler_field {
+  function init(&$view, &$options) {
+    parent::init($view, $options);
+    $this->additional_fields['nid'] = array('table' => 'node', 'field' => 'nid');
+  }
+
+  function query() {
+    $this->add_additional_fields();
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['text'] = array('default' => '', 'translatable' => TRUE);
+    $options['label'] = array('default' => '');
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $text = !empty($this->options['text']) ? $this->options['text'] : $this->definition['format name'];
+    $form['text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Text to display'),
+      '#default_value' => $text,
+    );
+  }
+
+  function render($values) {
+    if (user_access('show export links')) {
+      $format = $this->definition['format'];
+      $base = variable_get('biblio_base', 'biblio');
+      $nid = $this->get_value($values, 'nid');
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = "$base/export/$format/$nid";
+      $text = !empty($this->options['text']) ? $this->options['text'] : $this->definition['format name'];
+      return $text;
+    }
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_field_keyword.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,61 @@
+<?php
+class biblio_handler_field_keyword extends biblio_handler_field {
+  function init(&$view, &$options) {
+    module_load_include('inc', 'biblio', 'includes/biblio.keywords');
+    parent::init($view, $options);
+    $this->multiple = TRUE;
+    $this->additional_fields['vid'] = array('table' => 'biblio', 'field' => 'vid');
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['separator'] = array('default' => '; ');
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    $form['separator'] = array(
+      '#type' => 'textfield',
+      '#size' => 5,
+      '#title' => t('Keyword separator'),
+      '#default_value' => $this->options['separator'],
+      '#required' => TRUE,
+      '#description' => t('Enter the character which will be used to separate the keywords.'),
+      '#fieldset' => 'separators',
+    );
+    parent::options_form($form, $form_state);
+
+  }
+
+  function query() {
+    $this->add_additional_fields();
+    $this->field_alias = $this->aliases['vid'];
+  }
+
+  function post_execute(&$values) {
+    $vids = array();
+    $this->items = array();
+    $filter = '';
+
+    foreach ($values as $result) {
+      // Don't add empty results to the array.
+      if (isset($this->aliases['vid']) && !empty($result->{$this->aliases['vid']})) {
+        $vids[] = $result->{$this->aliases['vid']};
+      }
+    }
+
+    if (count($vids)) {
+      $this->items = biblio_load_keywords_multiple($vids);
+    }
+  }
+
+  function render($values) {
+    parent::set_label($values);
+    $vid = $values->{$this->field_alias};
+    if (!isset($this->items[$vid])) return NULL;
+    return implode($this->options['separator'], $this->items[$vid]);
+  }
+
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_field_markup.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,27 @@
+<?php
+class biblio_handler_field_markup extends views_handler_field {
+  function construct() {
+    parent::construct();
+
+    $this->additional_fields = array();
+    $this->additional_fields['biblio_formats'] = 'biblio_formats';
+
+  }
+
+  function render($values) {
+    $value = $this->get_value($values);
+    $formats = $this->get_value($values, 'biblio_formats');
+    $format = filter_default_format();
+    if (!empty($formats) ) {
+      $formats = unserialize($formats);
+      $format  = isset($formats[$this->field]) ? $formats[$this->field] : $format;
+    }
+    if ($value) {
+      $value = str_replace('<!--break-->', '', $value);
+      return check_markup($value, $format, '');
+    }
+  }
+
+
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_filter_biblio_contributor_auth_type.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+<?php
+class biblio_handler_filter_biblio_contributor_auth_type extends views_handler_filter_in_operator {
+
+  function construct() {
+    parent::construct();
+    $this->definition['numeric'] = TRUE;
+  }
+
+  function get_value_options() {
+    if (!isset($this->value_options)) {
+      $result = db_query("SELECT title, auth_type
+              FROM {biblio_contributor_type_data}
+              ORDER by auth_type");
+      $this->value_title = t('Author type');
+      $options = array();
+
+      foreach ($result as $row) {
+        $options[$row->auth_type] =  $row->title;
+      }
+      $this->value_options = $options;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_filter_biblio_keyword_kid.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,117 @@
+<?php
+class biblio_handler_filter_biblio_keyword_kid extends views_handler_filter_many_to_one {
+  function has_extra_options() { return TRUE; }
+
+  function get_value_options() {
+    $result = db_query("SELECT kd.* FROM {biblio_keyword_data} kd ORDER BY kd.word");
+    foreach ($result as $term) {
+      $this->value_options[$term->kid] = $term->word;
+    }
+
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['type'] = array('default' => 'textfield');
+    $options['limit'] = array('default' => TRUE);
+    $options['kid'] = array('default' => 0);
+
+    return $options;
+  }
+
+  function extra_options_form(&$form, &$form_state) {
+
+    if ($this->options['limit']) {
+      // We only do this when the form is displayed so this query doesn't run
+      // unnecessarily just when the object is constructed.
+
+      $form['type'] = array(
+      '#type' => 'radios',
+      '#title' => t('Selection type'),
+      '#options' => array('select' => t('Dropdown'), 'textfield' => t('Autocomplete')),
+      '#default_value' => $this->options['type'],
+      );
+    }
+  }
+  function value_form(&$form, &$form_state) {
+    if ($this->options['type'] == 'textfield') {
+      $default = '';
+      if ($this->value) {
+        $result = db_query("SELECT * FROM {biblio_keyword} bk WHERE bk.kid IN (:kids)",
+        array(':kids' => implode(', ', $this->value)));
+
+        foreach ($result as $term) {
+          if ($default) {
+            $default .= ', ';
+          }
+          $default .= $term->word;
+        }
+      }
+
+      $form['value'] = array(
+        '#title' => t('Select keywords'),
+        '#type' => 'textfield',
+        '#default_value' => $default,
+      );
+
+      if ($this->options['limit']) {
+        $form['value']['#autocomplete_path'] = 'biblio/autocomplete/biblio_keywords';
+      }
+    }
+    else {
+      $options = array();
+      $result = db_query("SELECT kd.* FROM {biblio_keyword_data} kd ORDER BY kd.word");
+      foreach ($result as $term) {
+        $options[$term->kid] = $term->word;
+      }
+
+      $default_value = (array) $this->value;
+
+      if (!empty($form_state['exposed'])) {
+        $identifier = $this->options['expose']['identifier'];
+
+        if (!empty($this->options['expose']['reduce'])) {
+          $options = $this->reduce_value_options($options);
+
+          if (empty($this->options['expose']['single']) && !empty($this->options['expose']['optional'])) {
+            $default_value = array();
+          }
+        }
+
+        if (!empty($this->options['expose']['single'])) {
+          if (!empty($this->options['expose']['optional']) && (empty($default_value) || !empty($this->options['expose']['reduce']))) {
+            $default_value = 'All';
+          }
+          elseif (empty($default_value)) {
+            $keys = array_keys($options);
+            $default_value = array_shift($keys);
+          }
+          else {
+            $copy = $default_value;
+            $default_value = array_shift($copy);
+          }
+        }
+      }
+      $form['value'] = array(
+        '#type' => 'select',
+        '#title' => t('Select keywords'),
+        '#multiple' => TRUE,
+        '#options' => $options,
+        '#size' => min(9, count($options)),
+        '#default_value' => $default_value,
+      );
+
+      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+        $form_state['input'][$identifier] = $default_value;
+      }
+    }
+
+
+    if (empty($form_state['exposed'])) {
+      // Retain the helper option
+      $this->helper->options_form($form, $form_state);
+    }
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_filter_biblio_keyword_word.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,72 @@
+<?php
+class biblio_handler_filter_biblio_keyword_word extends views_handler_filter_string {
+  function has_extra_options() { return TRUE; }
+
+  function get_value_options() {
+    $result = db_query("SELECT kd.* FROM {biblio_keyword_data} kd ORDER BY kd.word");
+    foreach ($result as $term) {
+      $this->value_options[$term->kid] = $term->word;
+    }
+
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['type'] = array('default' => 'textfield');
+    $options['limit'] = array('default' => TRUE);
+    $options['kid'] = array('default' => 0);
+
+    return $options;
+  }
+
+  function extra_options_form(&$form, &$form_state) {
+
+    if ($this->options['limit']) {
+      // We only do this when the form is displayed so this query doesn't run
+      // unnecessarily just when the object is constructed.
+
+      $form['type'] = array(
+      '#type' => 'radios',
+      '#title' => t('Selection type'),
+      '#options' => array('select' => t('Dropdown'), 'textfield' => t('Autocomplete')),
+      '#default_value' => $this->options['type'],
+      );
+    }
+  }
+  function value_form(&$form, &$form_state) {
+    parent::value_form(&$form, &$form_state);
+    if ($this->options['type'] == 'textfield') {
+/*      $default = '';
+      if ($this->value) {
+        $result = db_query("SELECT * FROM {biblio_keyword} bk WHERE bk.kid IN (:kids)",
+        array(':kids' => implode(', ', $this->value)));
+
+        foreach ($result as $term) {
+          if ($default) {
+            $default .= ', ';
+          }
+          $default .= $term->word;
+        }
+      }
+
+      $form['value'] = array(
+        '#title' => t('Select keywords'),
+        '#type' => 'textfield',
+        '#default_value' => $default,
+      );
+
+      if ($this->options['limit']) {
+        $form['value']['#autocomplete_path'] = 'biblio/autocomplete/biblio_keywords';
+      }
+      */
+    }
+
+
+    if (empty($form_state['exposed'])) {
+      // Retain the helper option
+ //     $this->helper->options_form($form, $form_state);
+    }
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_filter_biblio_type.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+<?php
+class biblio_handler_filter_biblio_type extends views_handler_filter_in_operator {
+
+  function construct() {
+    parent::construct();
+    $this->definition['numeric'] = TRUE;
+  }
+
+  function get_value_options() {
+    if (!isset($this->value_options)) {
+      $result = db_query("SELECT name, tid
+              FROM {biblio_types} t
+              WHERE t.tid > 0 AND t.visible=1
+              ORDER by name");
+      $this->value_title = t('Publication type');
+      $options = array();
+      foreach ($result as $row) {
+        $options[$row->tid] =  $row->name;
+      }
+      $this->value_options = $options;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_filter_contributor.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Filter handler for contributors
+ */
+class biblio_handler_filter_contributor extends views_handler_filter_many_to_one {
+  function get_value_options() {
+    $result = db_query("SELECT lastname, firstname, initials, cid
+              	  FROM {biblio_contributor_data} cd
+                  ORDER by lastname, firstname");
+    $this->value_options = array();
+    foreach ($result as $row) {
+      $this->value_options[$row->cid] =  "$row->lastname, $row->firstname $row->initials";
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_filter_contributor_lastname.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+<?php
+/**
+ * Filter handler for contributors
+ */
+class biblio_handler_filter_contributor_lastname extends views_handler_filter_many_to_one {
+  function get_value_options() {
+    $result = db_query("SELECT lastname, firstname, initials, cid
+              FROM {biblio_contributor_data} cd
+                  ORDER by lastname, firstname");
+    $this->value_options = array();
+    foreach ($result as $row) {
+      $this->value_options[$row->lastname] =  "$row->lastname, $row->firstname $row->initials";
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_filter_contributor_uid.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Filter handler for contributors
+ */
+class biblio_handler_filter_contributor_uid extends views_handler_filter_many_to_one {
+  function get_value_options() {
+    $result = db_query("SELECT u.name, lastname, firstname, initials, cid, drupal_uid
+              FROM {biblio_contributor_data} cd
+              INNER JOIN {users} u on u.uid = cd.drupal_uid
+              WHERE cd.drupal_uid > 0
+              ORDER by lastname, firstname");
+    $this->value_options = array();
+    foreach ($result as $row) {
+      $this->value_options[$row->drupal_uid] =  "$row->lastname, $row->firstname $row->initials ($row->name)";
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio/views/biblio_handler_sort_contributor_lastname.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,39 @@
+<?php
+
+class biblio_handler_sort_contributor_lastname extends views_handler_sort {
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['rank'] = array('default' => 0);
+    return $options;
+  }
+  function admin_summary() {
+    $order = parent::admin_summary();
+    $rank = $this->rank_options();
+    return $rank[$this->options['rank']] . ' ' . t('Author') . ', ' . $order;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['op_val_start'] = array('#value' => '<div class="clearfix">');
+      $form['rank'] = array(
+        '#title' => t('Sort by which author?'),
+        '#type' => 'select',
+        '#options' => $this->rank_options(),
+        '#default_value' => $this->options['rank'],
+      );
+    $form['op_val_end'] = array('#value' => '</div>');
+
+  }
+
+  function rank_options() {
+    return array('1st', '2nd', '3rd', '4th', '5th');
+  }
+  function query() {
+    parent::query();
+    $this->query->add_where(0, "biblio_contributor.rank", $this->options['rank'], '=');
+  }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/.gitignore	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,3 @@
+/.settings
+/.buildpath
+/.project
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/CHANGELOG.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,44 @@
+Biblio Advanced Import 7.x-1.0-alpha3, 2013-07-04
+-------------------------------------------------
+[#2027691] cspitzlay: respect the pubmed ID setting when detecting duplicates and when creating citekeys
+
+
+Biblio Advanced Import 7.x-1.0-alpha2, 2013-06-28
+-------------------------------------------------
+[        ] cspitzlay: Minor fixes for notices and deprecation warnings
+
+
+Biblio Advanced Import 7.x-1.0-alpha1, 2013-06-26
+-------------------------------------------------
+[        ] cspitzlay: straight port to D7 
+
+
+Biblio Advanced Import 6.x-1.0-rc1, 2013-04-05
+-------------------------------------------------
+[        ] mkalkbrenner: special handling for biblio's "year" 9999
+
+
+Biblio Advanced Import 6.x-1.0-beta1, 2011-09-06
+-------------------------------------------------
+[        ] mkalkbrenner: force Unified Cite ID Generation if import parser already created one
+
+
+Biblio Advanced Import 6.x-1.0-alpha3, 2011-06-20
+-------------------------------------------------
+[#1057650] mkalkbrenner: Unified Cite ID Generation
+[        ] mkalkbrenner: added workarounds for different biblio import pitfalls
+
+
+Biblio Advanced Import 6.x-1.0-alpha2, 2011-02-15
+-------------------------------------------------
+[        ] mkalkbrenner: combine different duplicate detection strategies
+[        ] mkalkbrenner: fixed bug merge always overrides
+
+
+Biblio Advanced Import 6.x-1.0-alpha1, 2011-02-14
+-------------------------------------------------
+[        ] mkalkbrenner: first public release
+[#1057646] mkalkbrenner: Create new revision on update
+[#1058992] mkalkbrenner: Configurable merge strategy
+[        ] mkalkbrenner: don't create a new revision if no data changed in record
+[#1058998] mkalkbrenner: Update all existing hashes if duplicate detection strategy changes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,41 @@
+
+Biblio Advanced Import
+======================
+
+Name: biblio_advanced_import
+Authors: Markus Kalkbrenner | bio.logis
+         Christian Spitzlay | bio.logis
+Drupal: 7.x
+Sponsors: Cocomore AG - http://www.cocomore.com
+          bio.logis   - http://www.biologis.com
+
+About
+=====
+
+"Biblio Advanced Import" is an add-on for the Bibliography Module,
+which can be found at http://drupal.org/project/biblio
+
+Instead of creating duplicate biblio records during imports,
+existing ones can be updated, or the import can be skipped
+depending on a configurable duplicate detection strategy.
+
+
+
+Installation
+============
+
+1. Install Bibliography Module itself from
+   http://drupal.org/project/biblio
+
+2. Place whole biblio_advanced_import folder into your Drupal
+   modules/ directory, or better, your sites/x/modules directory.
+
+3. Enable the "Biblio Advanced Import" module at /admin/build/modules
+
+
+
+Usage
+=====
+
+Configure your duplicate detection strategy at
+/admin/config/content/biblio/advanced_import
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/biblio_advanced_import.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,324 @@
+<?php
+
+/**
+ * @file
+ * Administration interface to configureable a duplicate
+ * detection strategy for biblio records
+ *
+ * @see biblio_advanced_import.module
+ * @see biblio.module
+ *
+ * @author Markus Kalkbrenner | Cocomore AG
+ *   @see http://drupal.org/user/124705
+ */
+
+/**
+ * Provides biblio_advanced_import_settings_form
+ * using system_settings_form().
+ */
+function biblio_advanced_import_settings_form($form, &$form_state) {
+  $form['biblio_advanced_import_duplicate_merge_fieldset'] = array(
+    '#title' => t('Duplicate Detection and Merge Strategy'),
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+
+  $options = array(
+    'create duplicate' => t('Create duplicate record.'),
+    'skip import' => t('Skip import of a record.'),
+    'update latest' => t('Update the latest existing duplicate record. (See "Merge Strategy" below.)'),
+    'update oldest' => t('Update the oldest existing duplicate record. (See "Merge Strategy" below.)'),
+    'update all' => t('Update all existing duplicate records. (See "Merge Strategy" below.)'),
+    'new rev latest' => t('Create a new revision of the latest existing duplicate record. (See "Merge Strategy" below.)'),
+    'new rev oldest' => t('Create a new revision of the oldest existing duplicate record. (See "Merge Strategy" below.)'),
+    'new rev all' => t('Create a new revisions of all existing duplicate records. (See "Merge Strategy" below.)'),
+  );
+
+  $form['biblio_advanced_import_duplicate_merge_fieldset']['biblio_advanced_import_duplicate_strategy'] = array(
+    '#title' => t('Duplicate Strategy'),
+    '#description' => t('Create a duplicate or skip a single record of an import or update existing records, if the import detects an already exiting biblio record.'),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_duplicate_strategy', 'create duplicate'),
+    '#required' => TRUE,
+  );
+
+  $options = array(
+    'md5' => t('Hashing over configurable biblio fields. (See "Hash Settings" below.)'),
+    'isbn' => t('ISBN'),
+    'issn' => t('ISSN'),
+    'doi' => t('DOI'),
+  );
+
+  if (module_exists('biblio_pm')) {
+    $options['pubmed'] = t('PubMed ID');
+  }
+
+  $form['biblio_advanced_import_duplicate_merge_fieldset']['biblio_advanced_import_detect_duplicate_strategy'] = array(
+    '#title' => t('Detect Duplicate Strategy'),
+    '#description' => t('These fields are used to decide if a new biblio record is a duplicate of an existing one. If you select more than one, only one of the fields has to be identical to declare two records as duplicate. P.e. if you choose "Hash" and "ISBN" duplicates will be found in general using the hash, but if available in both records, ISBN will be used.'),
+    '#type' => 'checkboxes',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_detect_duplicate_strategy', array('md5' => 'md5')),
+  );
+
+  $form['biblio_advanced_import_duplicate_merge_fieldset']['biblio_advanced_import_duplicate_criteria_fieldset'] = array(
+    '#title' => t('Hash Settings'),
+    '#description' => t('Select the criteria to create hashes to detect duplicate biblio records. But think twice about your selection. P.e. the ISBN is a perfect criteria. But if you import the same record from two different sources an one contains the ISBN while the other does not, they will not be considered as duplicates.'),
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+
+  $field_options = array('title' => t('Title'));
+  if (module_exists('biblio_pm')) {
+    // this key needs to be the name of the node property
+    $field_options['biblio_pubmed_id'] = t('Pubmed ID');
+  }
+  $result = db_query("SELECT name FROM {biblio_fields}");
+  while ($row = $result->fetchObject()) {
+    $field_options[$row->name] = str_replace('biblio_', '', $row->name);
+  }
+
+  $form['biblio_advanced_import_duplicate_merge_fieldset']['biblio_advanced_import_duplicate_criteria_fieldset']['biblio_advanced_import_duplicate_criteria'] = array(
+    '#type' => 'checkboxes',
+    '#options' => $field_options,
+    '#default_value' => variable_get('biblio_advanced_import_duplicate_criteria', array('title' => 'title', 'biblio_year' => 'biblio_year')),
+  );
+
+  $options = array(
+    'override' => t('Override the existing record.'),
+    'override but keep additional' => t('Override the existing record but keep non empty values that do not exist in the record to be imported.'),
+    'add new' => t('Only add new values that are empty in the existing record.'),
+    'override existing non empty' => t('Only override non empty existing values.'),
+    'override existing non empty with non empty' => t('Only override non empty existing values with new non empty existing values.'),
+  );
+
+  $form['biblio_advanced_import_duplicate_merge_fieldset']['biblio_advanced_import_merge_strategy'] = array(
+    '#title' => t('Merge Strategy'),
+    '#description' => t('If you did not choose "Create duplicate record." or "Skip import of a record." as Duplicate Strategy, you have to select a Merge Strategy as well.'),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_merge_strategy', 'override'),
+  );
+
+  $form['biblio_advanced_import_citekey_creation_fieldset'] = array(
+    '#title' => t('Cite ID Creation Strategy'),
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+
+  $options = array(
+    'biblio' => t('Use biblio default automatic Cite ID creation.'),
+    'fields' => t('Use configurable biblio fields. (See "Cite ID Creation Settings" below.)'),
+  );
+
+  $form['biblio_advanced_import_citekey_creation_fieldset']['biblio_advanced_import_citekey_creation_strategy'] = array(
+    '#title' => t('Automatic Cite ID Creation Strategy'),
+    '#description' => t("Note: Existing Cite IDs won't be changed."),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_citekey_creation_strategy', 'biblio'),
+  );
+
+  $form['biblio_advanced_import_citekey_creation_fieldset']['biblio_advanced_import_citekey_creation_fieldset'] = array(
+    '#title' => t('Cite ID Creation Settings'),
+    '#description' => t("Select the fields to automatically create Cite IDs. Note: Existing Cite IDs won't be changed."),
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+
+  $form['biblio_advanced_import_citekey_creation_fieldset']['biblio_advanced_import_citekey_creation_fieldset']['biblio_advanced_import_citekey_creation'] = array(
+    '#type' => 'checkboxes',
+    '#options' => $field_options,
+    '#default_value' => variable_get('biblio_advanced_import_citekey_creation', array('title' => 'title', 'biblio_year' => 'biblio_year')),
+  );
+
+  $options = array(
+    'skip' => t('Skip automatic Cite ID creation.'),
+    'append counter' => t('Append counter.'),
+  );
+
+  $form['biblio_advanced_import_citekey_creation_fieldset']['biblio_advanced_import_duplicate_citekey_strategy'] = array(
+    '#title' => t('Duplicate Cite ID Strategy'),
+    '#description' => t("Note: Existing Cite IDs won't be changed."),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_duplicate_citekey_strategy', 'skip'),
+  );
+
+  $form['biblio_advanced_import_workarounds_fieldset'] = array(
+    '#title' => t('Biblio Import Pitfall Workarounds'),
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+
+  $options = array(
+    'as is' => t('Store field ISBN as is'),
+    'remove' => t('Remove invalid ISBN'),
+    'convert 13' => t('Convert ISBN-10 into ISBN-13 and normalize ISBN-13 and GTIN-14'),
+  );
+
+  $form['biblio_advanced_import_workarounds_fieldset']['biblio_advanced_import_fix_isbn'] = array(
+    '#title' => t('ISBN'),
+    '#description' => t("There are three different formats ISBN-10, ISBN-13, GTIN-14."),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_fix_isbn', 'as is'),
+  );
+
+  $options = array(
+    'as is' => t('Store field ISSN as is'),
+    'normalize' => t('Normalize (numbers only)'),
+    'normalize from isbn' => t('Copy from ISBN if necessary and normalize (numbers only)'),
+  );
+
+  $form['biblio_advanced_import_workarounds_fieldset']['biblio_advanced_import_fix_issn'] = array(
+    '#title' => t('ISSN'),
+    '#description' => t('RIS format does not distinguish between ISBN and ISSN, so biblio imports ISSN as ISBN by default.'),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_fix_issn', 'as is'),
+  );
+
+  $options = array(
+    'as is' => t('Store field DOI as is'),
+    'one valid' => t('Only store the first valid DOI if additional text or a list of DOIs is provided'),
+  );
+
+  $form['biblio_advanced_import_workarounds_fieldset']['biblio_advanced_import_fix_doi'] = array(
+    '#title' => t('DOI'),
+    '#description' => t("Some import formats include multiple DOIs which is not supported by biblio."),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_fix_doi', 'as is'),
+  );
+
+  $options = array(
+    'as is' => t('Store field URL as is'),
+    'one valid' => t('Only store the first valid URL if additional text or a list of URLs is provided'),
+  );
+
+  $form['biblio_advanced_import_workarounds_fieldset']['biblio_advanced_import_fix_url'] = array(
+    '#title' => t('URL'),
+    '#description' => t("Some import formats include multiple URLs which is not supported by biblio."),
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_fix_url', 'as is'),
+  );
+
+  $options = array(
+    'as is' => t('Store field Title as is'),
+    'mendeley bibtex' => t('Remove {} from Title exported by Mendeley using BibTex'),
+  );
+
+  $form['biblio_advanced_import_workarounds_fieldset']['biblio_advanced_import_fix_title'] = array(
+    '#title' => t('Title'),
+    '#description' => '',
+    '#type' => 'radios',
+    '#options' => $options,
+    '#default_value' => variable_get('biblio_advanced_import_fix_title', 'as is'),
+  );
+
+  $form['#submit'] = array('biblio_advanced_import_settings_form_submit');
+
+  return system_settings_form($form);
+}
+
+
+/**
+ * Validation of biblio_advanced_import_settings_form().
+ */
+function biblio_advanced_import_settings_form_validate($form, &$form_state) {
+  if ('create duplicate' != $form_state['values']['biblio_advanced_import_duplicate_strategy']) {
+    $no_detect_duplicate_strategy = TRUE;
+    foreach ($form_state['values']['biblio_advanced_import_detect_duplicate_strategy'] as $value) {
+      if ($value) {
+        $no_detect_duplicate_strategy = FALSE;
+        break;
+      }
+    }
+    if ($no_detect_duplicate_strategy) {
+      form_set_error('biblio_advanced_import_detect_duplicate_strategy', t('You need to specifiy at least one criteria.'));
+    }
+
+    if (in_array('md5', $form_state['values']['biblio_advanced_import_detect_duplicate_strategy'], TRUE)) {
+      $no_duplicate_criteria = TRUE;
+      foreach ($form_state['values']['biblio_advanced_import_duplicate_criteria'] as $value) {
+        if ($value) {
+          $no_duplicate_criteria = FALSE;
+          break;
+        }
+      }
+      if ($no_duplicate_criteria) {
+        form_set_error('biblio_advanced_import_duplicate_criteria', t('You need to specifiy at least one criteria.'));
+      }
+    }
+
+    if (empty($form_state['values']['biblio_advanced_import_merge_strategy'])) {
+      form_set_error('biblio_advanced_import_merge_strategy', t('You need to specifiy a merge strategy.'));
+    }
+  }
+}
+
+
+/**
+ * Submit handler of biblio_advanced_import_settings_form().
+ *
+ * Checks if duplicate strategy has been changed which requires
+ * an update of all hashes of all existing biblio nodes.
+ * If required, a batch process will be started to recalculate
+ * all hashes.
+ */
+function biblio_advanced_import_settings_form_submit($form, &$form_state) {
+  if ($form_state['values']['biblio_advanced_import_citekey_creation_strategy'] == 'fields'
+     && variable_get('biblio_advanced_import_citekey_creation_strategy', 'biblio') != 'fields') {
+
+    // save existing custom citekey creation php code
+    variable_set('biblio_advanced_import_old_citekey_phpcode', variable_get('biblio_citekey_phpcode', ''));
+    // insert biblio_advanced_import citekey creation php code
+    // @see biblio_advanced_import_create_citekey()
+    variable_set('biblio_citekey_phpcode', 'return biblio_advanced_import_create_citekey($node);');
+  }
+  elseif ($form_state['values']['biblio_advanced_import_citekey_creation_strategy'] != 'fields'
+     && variable_get('biblio_advanced_import_citekey_creation_strategy', 'biblio') == 'fields') {
+
+    variable_set('biblio_citekey_phpcode', variable_get('biblio_advanced_import_old_citekey_phpcode', ''));
+  }
+
+  if ($form_state['values']['biblio_advanced_import_duplicate_strategy'] != 'create duplicate') {
+    $update_hashes = FALSE;
+    if (variable_get('biblio_advanced_import_duplicate_strategy', 'create duplicate') == 'create duplicate') {
+      $update_hashes = TRUE;
+    }
+    else {
+      $old_values = variable_get('biblio_advanced_import_duplicate_criteria', array('title' => 'title', 'biblio_year' => 'biblio_year'));
+      foreach ($form_state['values']['biblio_advanced_import_duplicate_criteria'] as $key => $value) {
+        if ($value) {
+          if (!array_key_exists($key, $old_values) || ((string) $old_values[$key] != (string) $value)) {
+            $update_hashes = TRUE;
+            break;
+          }
+        }
+      }
+    }
+
+    if ($update_hashes) {
+      $batch = array(
+        'title' => t('Re-hashing existing biblio nodes'),
+        'operations' => array(
+          array('biblio_advanced_import_update_hashes_batch', array()),
+        ),
+        'finished' => 'biblio_advanced_import_update_hashes_batch_finished',
+        'file' => 'biblio_advanced_import.batch.inc',
+      );
+      batch_set($batch);
+
+      // TODO block import and creation of new biblio nodes until batch is finished
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/biblio_advanced_import.batch.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Batch process to update existing biblio nodes
+ *
+ * @see biblio_advanced_import.module
+ * @see biblio.module
+ *
+ * @author Markus Kalkbrenner | Cocomore AG
+ *   @see http://drupal.org/user/124705
+ */
+
+/**
+ * Updates the hashes of all biblio nodes as batch process.
+ *
+ * @see biblio_advanced_import_settings_form_submit()
+ *
+ * @param $context
+ *   drupal batch process context
+ */
+function biblio_advanced_import_update_hashes_batch(&$context) {
+  if (empty($context['biblio_advanced_import_update_hashes_batch'])) {
+    $context['sandbox']['progress'] = 0;
+    $context['sandbox']['current_nid'] = 0;
+    $context['sandbox']['max_nid'] = db_query('SELECT MAX(nid) FROM {biblio}')->fetchField();
+    $context['sandbox']['num_nids'] = db_query('SELECT COUNT(DISTINCT nid) FROM {biblio}')->fetchField();
+    $context['sandbox']['limit'] = $context['sandbox']['num_nids'] > 20 ? 5 : 1;
+  }
+
+  if ($context['sandbox']['current_nid'] >= $context['sandbox']['max_nid']) {
+    $context['sandbox']['progress'] = $context['sandbox']['num_nids'];
+    $context['finished'] = 1;
+  }
+  else {
+    $query = db_select('biblio', 'b');
+    $alias = $query->innerJoin('node', 'n', 'b.nid = n.nid AND b.vid = n.vid');
+    $query->fields('b', array('nid'))
+      ->condition('b.nid', $context['sandbox']['current_nid'], '>')
+      ->condition('b.nid', $context['sandbox']['max_nid'], '<=')
+      ->orderBy('b.nid', 'ASC');
+    $result = $query->execute();
+    while ($row = $result->fetchObject()) {
+      $node = node_load($row['nid'], NULL, TRUE);
+      biblio_advanced_import_update_hash($node);
+
+      $context['results'][] = $node->nid . ' : ' . $node->biblio_md5;
+      $context['sandbox']['progress']++;
+      $context['sandbox']['current_nid'] = $node->nid;
+      $context['message'] = $node->nid . ' : ' . $node->title;
+    }
+
+    if ($context['sandbox']['progress'] != $context['sandbox']['num_nids']) {
+      $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['num_nids'];
+    }
+  }
+}
+
+
+/**
+ * Clean-up after hashes of all biblio nodes have been updated
+ * in a batch process.
+ *
+ * @see biblio_advanced_import_settings_form_submit()
+ */
+function biblio_advanced_import_update_hashes_batch_finished($success, $results, $operations) {
+  if ($success) {
+    $message = format_plural(count($results), 'Updated one biblio hash.', 'Updates @count biblio hashes.');
+  }
+  else {
+    $message = t('Finished with an error.');
+  }
+  drupal_set_message($message);
+
+  // TODO re-enable import and creation of new biblio nodes
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/biblio_advanced_import.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = "Biblio Advanced Import"
+description = "Identification of duplicates across different import formats, updating of existing nodes, cite id generation."
+core = 7.x
+package = Biblio
+dependencies[] = biblio
+
+files[] = lib/isbntest.class.php
+
+; Information added by drupal.org packaging script on 2013-07-04
+version = "7.x-1.0-alpha3"
+core = "7.x"
+project = "biblio_advanced_import"
+datestamp = "1372929652"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/biblio_advanced_import.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,476 @@
+<?php
+
+/**
+ * @file
+ * Biblio add-on.
+ *
+ * Instead of creating duplicate biblio records,
+ * existing ones could be updated or the import could
+ * be skipped depending on a configurable duplicate
+ * detection strategy.
+ *
+ * @see biblio.module
+ *
+ * @author Markus Kalkbrenner | Cocomore AG
+ *   @see http://drupal.org/user/124705
+ */
+
+
+/**
+ * Implements hook_menu().
+ */
+function biblio_advanced_import_menu() {
+  $items['admin/config/content/biblio/advanced_import'] = array(
+    'title' => 'Advanced Import',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('biblio_advanced_import_settings_form'),
+    'access arguments' => array('administer biblio'),
+    'file' => 'biblio_advanced_import.admin.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 2,
+  );
+
+  return $items;
+}
+
+
+/**
+ * Implements hook_node_presave().
+ */
+function biblio_advanced_import_node_presave($node) {
+  if ('biblio' == $node->type && empty($node->nid)) {
+
+    biblio_advanced_import_pitfall_workarounds($node);
+
+    if (variable_get('biblio_auto_citekey', 1)) {
+      // on new entries, override citekeys generated by parses, depending on settings
+      $citekey = biblio_advanced_import_create_citekey($node);
+      if ($citekey) {
+        $node->biblio_citekey = $citekey;
+      }
+    }
+
+    $query = db_select('biblio', 'b');
+    $alias = $query->innerJoin('node', 'n', 'b.nid = n.nid AND b.vid = n.vid');
+    $query->fields('b', array('nid'));
+    $skip = FALSE;
+    $revision = FALSE;
+
+    switch (variable_get('biblio_advanced_import_duplicate_strategy', 'create duplicate')) {
+      case 'create duplicate':
+        return;
+
+      case 'skip import':
+        // There's no way to stop an already running node_save()
+        // in a safe way without breaking a batch process.
+        // So we do a little trick to realize the 'skip import':
+        // We simply replace the current node to be saved by the
+        // unmodified oldest duplicate and save this one instead
+        $skip = TRUE;
+        $query->orderBy('b.nid', 'DESC')
+          ->range(0, 1);
+        break;
+
+      case 'new rev latest':
+        $revision = TRUE;
+      case 'update latest':
+        $query->orderBy('b.nid', 'DESC')
+          ->range(0, 1);
+        break;
+
+      case 'new rev oldest':
+        $revision = TRUE;
+      case 'update oldest':
+        $query->orderBy('b.nid', 'ASC')
+          ->range(0, 1);
+        break;
+
+      case 'new rev all':
+        $revision = TRUE;
+      case 'update all':
+        break;
+    }
+
+    $condition_exists = FALSE;
+    $or_condition = db_or();
+    foreach (variable_get('biblio_advanced_import_detect_duplicate_strategy', array('md5' => 'md5')) as $field) {
+      switch ((string) $field) {
+        case 'md5':
+          $or_condition->condition('b.biblio_md5', biblio_advanced_import_hash($node));
+          $condition_exists = TRUE;
+          break;
+        case 'isbn':
+        case 'issn':
+        case 'doi':
+          $field_property = 'biblio_' . $field;
+          if (!empty($node->$field_property)) {
+            $or_condition->condition('b.' . $field_property, $node->$field_property);
+            $condition_exists = TRUE;
+          }
+          break;
+
+        case 'pubmed':
+          if (module_exists('biblio_pm') && !empty($node->biblio_pubmed_id)) {
+            $query->innerJoin('biblio_pubmed', 'bp', 'b.nid = bp.nid');
+            $or_condition->condition('bp.biblio_pubmed_id', $node->biblio_pubmed_id);
+            $condition_exists = TRUE;
+          }
+          break;
+      }
+    }
+
+    if ($condition_exists) {
+      $query->condition($or_condition);
+
+      $result = $query->execute();
+      $is_first_duplicate = TRUE;
+      $node_new = (Array) $node;
+
+      while ($row = $result->fetchObject()) {
+        // there are duplicates:
+        $node_old = node_load($row->nid);
+        // we need to set this or the node module will throw notices
+        // (if this node becomes the one to be really saved instead of the original one)
+        $node_old->is_new = FALSE;
+
+        if (!$skip) {
+          // update an existing biblio node with new data
+          $merge = FALSE;
+          foreach ($node_new as $key => $value) {
+            if (strpos($key, 'biblio') === 0 || strpos($key, 'contributors') === 0 || 'title' == $key) {
+              $strategy = variable_get('biblio_advanced_import_merge_strategy', 'override');
+              if ('override' == $strategy
+                     || ('override but keep additional' == $strategy && !empty($value))
+                     || ('add new' == $strategy && !empty($value) && empty($node_old->$key))
+                     || ('override existing non empty' == $strategy && !empty($node_old->$key))
+                     || ('override existing non empty with non empty' == $strategy && !empty($value) && !empty($node_old->$key))
+                  ) {
+                if (!property_exists($node_old, $key) || $node_old->$key != $value) {
+                  $node_old->$key = $value;
+                  $merge = TRUE;
+                }
+              }
+            }
+          }
+
+          if ($revision && $merge) {
+            $node_old->revision = TRUE;
+            $node_old->log = t('New revision created automatically by Biblio Advanced Import.');
+          }
+        }
+        else {
+          // There's no way to stop an already running node_save()
+          // in a safe way without breaking the batch process.
+          // So we use a little trick to implement the 'skip import':
+          // We replace the current node to be saved with the
+          // unmodified first duplicate and let drupal save that one instead.
+        }
+
+        if ($is_first_duplicate) {
+          // the content of the node being saved gets replaced with the values from the first duplicate node
+          // (replacing the whole object with the loaded node did not seem to work
+          // so we do it property by property ...)
+          $is_first_duplicate = FALSE;
+          // clear existing object
+          foreach (get_object_vars($node) as $key => $value) {
+            unset($node->$key);
+          }
+          // copy values over
+          foreach (get_object_vars($node_old) as $key => $value) {
+            $node->$key = $value;
+          }
+        }
+        else {
+          // save any other existing duplicates, with values updated
+          node_save($node_old);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_node_insert().
+ */
+function biblio_advanced_import_node_insert($node) {
+  if ('biblio' == $node->type) {
+    biblio_advanced_import_update_hash($node);
+  }
+}
+
+/**
+ * Implements hook_node_update().
+ */
+function biblio_advanced_import_node_update($node) {
+  if ('biblio' == $node->type) {
+    biblio_advanced_import_update_hash($node);
+  }
+}
+
+
+/**
+ * Helper function to create a hash from a biblio node
+ * depending on a configurable duplicate detection
+ * strategy.
+ *
+ * @see biblio_advanced_import_settings_form()
+ *
+ * @param $node
+ *   a biblio node
+ *
+ * @return
+ *   a md5 hash
+ */
+function biblio_advanced_import_hash($node) {
+  $hash_string = '';
+  $duplicate_criteria = variable_get('biblio_advanced_import_duplicate_criteria',
+    array('title' => 'title', 'biblio_year' => 'biblio_year'));
+
+  foreach ($duplicate_criteria as $field) {
+    if ($field) {
+      $field_value = '';
+
+      if (isset($node->$field)) {
+        $field_value = $node->$field;
+      }
+
+      if ('biblio_year' == $field && empty($field_value)) {
+        // If the year is empty, it will be set to 9999 by biblio on save.
+        // 9999 => "Submitted"
+        // Therefore we have to do the same here to not break duplicate detection.
+        $field_value = 9999;
+      }
+
+      if ($field_value) {
+        if (is_array($field_value) || is_object($field_value)) {
+          $hash_string .= serialize($field_value);
+        }
+        else {
+          $hash_string .= preg_replace("/\s+/", '', mb_strtolower(mb_substr($field_value, 0, 256)));
+        }
+      }
+    }
+  }
+
+  return md5(strtolower($hash_string));
+}
+
+
+/**
+ * Helper function to update the hash of a biblio node.
+ *
+ * @see biblio_advanced_import_settings_form()
+ *
+ * @param $node
+ *   a biblio node
+ */
+function biblio_advanced_import_update_hash(&$node) {
+  $node->biblio_md5 = biblio_advanced_import_hash($node);
+  db_update('biblio')
+    ->fields(array(
+      'biblio_md5' => $node->biblio_md5,
+    ))
+    ->condition('nid', $node->nid)
+    ->condition('vid', $node->vid)
+    ->execute();
+}
+
+
+/**
+ * Helper function to create a configurable biblio node citekey.
+ *
+ * @see biblio_advanced_import_settings_form()
+ * @see biblio_advanced_import_settings_form_submit()
+ *
+ * @param $node
+ *   a biblio node
+ */
+function biblio_advanced_import_create_citekey($node) {
+  $citekey = '';
+
+  switch (variable_get('biblio_advanced_import_citekey_creation_strategy', 'biblio')) {
+    case 'fields':
+      $citekey_parts = array();
+      $prefix = variable_get('biblio_citekey_prefix', '');
+      if (!empty($prefix)) {
+        $citekey_parts[] = $prefix;
+      }
+      foreach (variable_get('biblio_advanced_import_citekey_creation', array('title' => 'title', 'biblio_year' => 'biblio_year')) as $field) {
+        if (!empty($field) && !empty($node->$field)) {
+          $citekey_parts[] = $node->$field;
+        }
+      }
+      $citekey = implode('|', $citekey_parts);
+      // biblio stores citekey as varchar(255), we need to make sure it fits
+      // or a PDO Exception is thrown
+      $citekey = mb_substr($citekey, 0, 255);
+      // strip trailing pipe symbol, if any
+      $citekey = preg_replace('@\|+$@', '', $citekey);
+      $citekey = trim($citekey);
+      break;
+  }
+
+  if ($citekey) {
+    if (db_query("SELECT 1 FROM {biblio} WHERE biblio_citekey = :biblio_citekey", array(':biblio_citekey' => $citekey))->fetchField()) {
+      switch (variable_get('biblio_advanced_import_citekey_creation_strategy', 'skip')) {
+        case 'skip':
+          $citekey = '';
+          break;
+
+        case 'append counter':
+          $counter = variable_get('biblio_advanced_import_citekey_creation_counter', 0) + 1;
+          variable_set('biblio_advanced_import_citekey_creation_counter', $counter);
+          // biblio stores citekey as varchar(255), so we have to ensure that the counter is saved
+          $citekey = mb_substr($citekey, 0, 254 - strlen($counter)) . '|' . $counter;
+      }
+    }
+  }
+
+  return $citekey;
+}
+
+
+/**
+ * @todo Please document this function.
+ * @see http://drupal.org/node/1354
+ */
+function biblio_advanced_import_form_biblio_admin_settings_alter(&$form, &$form_state) {
+  if ('fields' == variable_get('biblio_advanced_import_citekey_creation_strategy', 'biblio')) {
+    $form['citekey']['biblio_citekey_field1']['#type'] = 'value';
+    $form['citekey']['biblio_citekey_field1']['#value'] = $form['citekey']['biblio_citekey_field1']['#default_value'];
+    $form['citekey']['biblio_citekey_field2']['#type'] = 'value';
+    $form['citekey']['biblio_citekey_field2']['#value'] = $form['citekey']['biblio_citekey_field2']['#default_value'];
+    $form['citekey']['biblio_citekey_phpcode']['#type'] = 'value';
+    $form['citekey']['biblio_citekey_phpcode']['#value'] = $form['citekey']['biblio_citekey_phpcode']['#default_value'];
+  }
+}
+
+
+/**
+ * This function implements some optional data cleanup / normalization
+ * that can be activated on the "advanced import" tab.
+ */
+function biblio_advanced_import_pitfall_workarounds(&$node) {
+  switch (variable_get('biblio_advanced_import_fix_issn', 'as is')) {
+    case 'as is':
+      break;
+
+    case 'normalize from isbn':
+      if (empty($node->biblio_issn) || !empty($node->biblio_isbn)) {
+        // RIS format does not distinguish between ISBN and ISSN
+        $node->biblio_issn = $node->biblio_isbn;
+      }
+      // no break
+    case 'normalize':
+      // @see http://en.wikipedia.org/wiki/International_Standard_Serial_Number
+      if (!empty($node->biblio_issn)) {
+        if (preg_match("@\b([0-9]{4})-?([0-9X]{4})\b@i", $node->biblio_issn, $matches)) {
+          $issn = strtoupper($matches[1] . $matches[2]);
+          $sum = 0;
+          for ($i = 0; $i < 7; $i++) {
+            $sum += $issn[$i] * (8 - $i);
+          }
+          $checksum = 11 - ($sum % 11);
+          if ($checksum == $issn[7] || (10 == $checksum && 'X' == $issn[7])) {
+            $node->biblio_issn = $issn;
+          }
+          else {
+            unset($node->biblio_issn);
+          }
+        }
+        else {
+          unset($node->biblio_issn);
+        }
+      }
+      break;
+  }
+
+  switch (variable_get('biblio_advanced_import_fix_isbn', 'as is')) {
+    case 'as is':
+      break;
+
+    case 'remove':
+      // @see http://en.wikipedia.org/wiki/International_Standard_Book_Number
+      if (!empty($node->biblio_isbn)) {
+        module_load_include('class.php', 'biblio_advanced_import', 'lib/isbntest');
+        $currISBN = new ISBNtest();
+        $currISBN->set_isbn($matches[0]);
+        if ($currISBN->valid_isbn10() || $currISBN->valid_isbn13() || $currISBN->valid_gtin14()) {
+          $node->biblio_isbn = $currISBN->get_gtin14();
+        }
+        else {
+          unset($node->biblio_isbn);
+        }
+      }
+      break;
+
+    case 'convert 13':
+      // @see http://en.wikipedia.org/wiki/International_Standard_Book_Number
+      if (!empty($node->biblio_isbn)) {
+        if (preg_match("@[0-9\-]{10,}@", $node->biblio_isbn, $matches)) {
+          module_load_include('class.php', 'biblio_advanced_import', 'lib/isbntest');
+          $currISBN = new ISBNtest();
+          $currISBN->set_isbn($matches[0]);
+          if ($currISBN->valid_isbn13()) {
+            $node->biblio_isbn = $currISBN->get_isbn13();
+          }
+          elseif ($currISBN->valid_gtin14()) {
+            $node->biblio_isbn = $currISBN->get_gtin14();
+          }
+          else {
+            unset($node->biblio_isbn);
+          }
+        }
+        else {
+          unset($node->biblio_isbn);
+        }
+      }
+      break;
+  }
+
+  switch (variable_get('biblio_advanced_import_fix_doi', 'as is')) {
+    case 'as is':
+      break;
+
+    case 'one valid':
+      // @see http://en.wikipedia.org/wiki/Digital_object_identifier
+      if (!empty($node->biblio_doi)) {
+        if (preg_match("@10\.\d{4,}/[^\s]+@i", $node->biblio_doi, $matches)) {
+          $node->biblio_doi = $matches[0];
+        }
+        else {
+          unset($node->biblio_doi);
+        }
+      }
+      break;
+  }
+
+  switch (variable_get('biblio_advanced_import_fix_title', 'as is')) {
+    case 'as is':
+      break;
+
+    case 'mendeley bibtex':
+      if (!empty($node->title)) {
+        $node->title = trim($node->title, '{}');
+      }
+      break;
+  }
+
+  switch (variable_get('biblio_advanced_import_fix_title', 'as is')) {
+    case 'as is':
+      break;
+
+    case 'one valid':
+      if (!empty($node->biblio_url)) {
+        if (preg_match("@(http|https)://[^\s]+@i", $node->biblio_url, $matches)) {
+          // ris import runs together lists of urls without a delimiter
+          $urls = explode('http', str_replace(array('HTTP:', 'HTTPS:'), array('http:', 'https:'), $matches[0]));
+          $node->biblio_url = 'http' . $urls[1];
+        }
+        else {
+          unset($node->biblio_url);
+        }
+      }
+      break;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_advanced_import/lib/isbntest.class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,353 @@
+<?php
+    /*
+     * This class contains a method to do validity checks on ISBNs.
+     * it's pretty basic and should require no further docs
+     *
+     * Updated to be more flexible in the face of new isbn standards
+     * 2009-11-19 bugfixes to deal with problems reported in the forums.
+     *
+     * copyright 1999, 2004, 2008, 2009 Keith Nunn
+     * kapn@kapn.net
+     * Released under the terms of the GNU General Public License v.2 or later
+     */
+
+    class ISBNtest
+    {
+        private $isbn10 = FALSE; // the stripped ISBN-10, includes given checkdigit
+        private $isbn13 = FALSE; // the stripped ISBN-13 (or Bookland EAN), includes given checkdigit
+        private $gtin14 = FALSE; // the stripped GTIN-14 (or ISBN-14), includes given checkdigit
+        private $error = "";  // error to return, if required
+
+        private function get_isbn10_checkdigit()
+        // calculate the checkdigit for ISBN-10
+        {
+            if (strlen($this->isbn10) != 10)
+            {
+                return FALSE;
+                $this->error = "Given ISBN-10 is not 10 digits (" . $this->isbn10 . ")";
+            }
+            /* 
+             * this checkdigit calculation could probably be expressed in less 
+             * space using a lop, but this keeps it very clear what the math
+             * involved is 
+             */
+            $checkdigit = 11 - ( ( 10 * substr($this->isbn10,0,1) + 9 * substr($this->isbn10,1,1) + 8 * substr($this->isbn10,2,1) + 7 * substr($this->isbn10,3,1) + 6 * substr($this->isbn10,4,1) + 5 * substr($this->isbn10,5,1) + 4 * substr($this->isbn10,6,1) + 3 * substr($this->isbn10,7,1) + 2 * substr($this->isbn10,8,1) ) % 11);
+            /*
+             * convert the numeric check value
+             * into the single char version
+             */
+            switch ( $checkdigit ) 
+            {
+            case 10:
+                $checkdigit = "X";
+                break;
+            case 11:
+                $checkdigit = 0;
+                break;
+            default:
+            }
+            return $checkdigit;
+        }
+        /***********************************************/
+        
+        private function get_isbn13_checkdigit()
+        // calculate the checkdigit for ISBN-10
+        {
+            if (strlen($this->isbn13) != 13)
+            {
+                return FALSE;
+                $this->error = "Given ISBN-13 is not 10 digits (" . $this->isbn13 . ")";
+            }
+            /* 
+             * this checkdigit calculation could probably be expressed in less 
+             * space using a lop, but this keeps it very clear what the math
+             * involved is 
+             */
+            $checkdigit = 10 - ( ( 1 * substr($this->isbn13,0,1) + 3 * substr($this->isbn13,1,1) + 1 * substr($this->isbn13,2,1) + 3 * substr($this->isbn13,3,1) + 1 * substr($this->isbn13,4,1) + 3 * substr($this->isbn13,5,1) + 1 * substr($this->isbn13,6,1) + 3 * substr($this->isbn13,7,1) + 1 * substr($this->isbn13,8,1) + 3 * substr($this->isbn13,9,1) + 1 * substr($this->isbn13,10,1) + 3 * substr($this->isbn13,11,1) ) % 10 );
+            /*
+             * convert the numeric check value
+             * into the single char version
+             */
+            if ( $checkdigit == 10 ) 
+            {
+                $checkdigit = "0";
+            }
+            return $checkdigit;
+        }
+        /***********************************************/
+
+        private function get_gtin14_checkdigit()
+        // calculate the checkdigit for GTIN
+        {
+            if (strlen($this->gtin14) != 14)
+            {
+                return FALSE;
+                $this->error = "Given GTIN is not 14 digits (" . $this->gtin14 . ")";
+            }
+            $checkdigit = 10 - ( ( 3 * substr($this->gtin14,0,1) + 1 * substr($this->gtin14,1,1) + 3 * substr($this->gtin14,2,1) + 1 * substr($this->gtin14,3,1) + 3 * substr($this->gtin14,4,1) + 1 * substr($this->gtin14,5,1) + 3 * substr($this->gtin14,6,1) + 1 * substr($this->gtin14,7,1) + 3 * substr($this->gtin14,8,1) + 1 * substr($this->gtin14,9,1) + 3 * substr($this->gtin14,10,1) + 1 * substr($this->gtin14,11,1) + 3 * substr($this->gtin14,12,1) ) % 10 );
+            /*
+             * convert the numeric check value
+             * into the single char version
+             */
+            if ( $checkdigit == 10 ) 
+            {
+                $checkdigit = "0";
+            }
+            return $checkdigit;
+        }
+        /***********************************************/
+
+        public function set_isbn10($isbn)
+        {
+            $isbn = preg_replace("@[^0-9X]@","",strtoupper($isbn)); // strip to the basic ISBN
+            if (strlen($isbn)==10)
+            {
+                $this->isbn10 = $isbn;
+            }
+            else
+            {
+                $this->error = "ISBN-10 given is not 10 digits ($isbn)";
+                return FALSE;
+            }
+        }
+        /***********************************************/
+
+        public function set_isbn13($isbn)
+        {
+            $isbn = preg_replace("@[^0-9]@","",strtoupper($isbn)); // strip to the basic ISBN
+            if (strlen($isbn)==13)
+            {
+                $this->isbn13 = $isbn;
+            }
+            else
+            {
+                $this->error = "ISBN-13 given is not 13 digits ($isbn)";
+                return FALSE;
+            }
+        }
+        /***********************************************/
+
+        public function set_gtin14($isbn)
+        {
+            $isbn = preg_replace("@[^0-9]@","",strtoupper($isbn)); // strip to the basic ISBN
+            if (strlen($isbn)==14)
+            {
+                $this->gtin14 = $isbn;
+            }
+            else
+            {
+                $this->error = "GTIN given is not 14 digits ($isbn)";
+                return FALSE;
+            }
+        }
+        /***********************************************/
+
+        public function set_isbn($isbn)
+        // trying to provide a common interface here so it's possible to cope 
+        // if you don't know for sure what you have -- provided the data is valid
+        {
+            $isbn = preg_replace("@[^0-9X]@","",strtoupper($isbn)); // strip to the basic ISBN
+            if (strlen($isbn)==14)
+            {
+                $this->set_gtin14($isbn);
+                return TRUE;
+            }
+            if (strlen($isbn)==13)
+            {
+                $this->set_isbn13($isbn);
+                return TRUE;
+            }
+            elseif (strlen($isbn)==10)
+            {
+                $this->isbn10 = $isbn;
+                return TRUE;
+            }
+            else
+            {
+                $this->error = "ISBN given is not 10, 13, or 14 digits ($isbn)";
+                return FALSE;
+            }
+        }
+        /***********************************************/
+        
+        public function valid_isbn10($isbn="")
+        // report on the validity of the ISBN-10 we have or are given
+        {
+            if ($isbn != "") // If we've been given a new ISBN then use it.
+            {
+                $this->set_isbn10($isbn);
+            }
+            if ( FALSE === $this->isbn10 && FALSE !== $this->isbn13 )
+            {
+                if ( TRUE === $this->valid_isbn13() )
+                {
+                    $this->get_isbn10();
+                }
+            }
+            if ( FALSE === $this->isbn10 || strlen($this->isbn10) != 10 )
+            {
+                $this->error = "ISBN-10 is not set";
+                return FALSE;
+            }
+            if ( (string) substr($this->isbn10,9,1) === (string) $this->get_isbn10_checkdigit() )
+            {
+                return TRUE;
+            }
+            else
+            {
+                $this->error = "Checkdigit failure";
+                return FALSE;
+            }
+        }
+        /***********************************************/
+        
+        public function valid_isbn13($isbn="")
+        // report on the validity of the ISBN-13 we have or are given
+        {
+            if ($isbn != "") // if we've been given an isbn here, use it
+            { 
+                $this->set_isbn13($isbn);
+            }
+            if ( FALSE === $this->isbn13 && FALSE !== $this->isbn10 )
+            {
+                if ( TRUE === $this->valid_isbn10() )
+                {
+                    $this->get_isbn13();
+                }
+            }
+            if ( FALSE === $this->isbn13 || strlen($this->isbn13) != 13 )
+            {
+                $this->error = "ISBN-13 is not set";
+                return FALSE;
+            }
+            if ( (string) substr($this->isbn13,12,1) === (string) $this->get_isbn13_checkdigit() )
+            {
+                return TRUE;
+            }
+            else
+            {
+                $this->error = "Checkdigit failure";
+                return FALSE;
+            }
+        }
+        /***********************************************/
+        
+        public function valid_gtin14($isbn="")
+        // report on the validity of the GTIN we have or are given
+        {
+            if ($isbn != "") // if we've been given an ISBN here, use it
+            {
+                $this->set_gtin14($isbn);
+            }
+            if ( FALSE === $this->gtin14 || strlen($this->gtin14) != 14 )
+            {
+                $this->error = "GTIN-14 is not set";
+                return FALSE;
+            }
+            if ( substr($this->gtin14,13,1) === $this->get_gtin14_checkdigit() )
+            {
+                return TRUE;
+            }
+            else
+            {
+                $this->error = "Checkdigit failure";
+                return FALSE;
+            }
+        }
+        /***********************************************/
+        public function valid_isbn($isbn="")
+        // trying to provide a common interface here so it's possible to cope 
+        // if you don't know for sure what you have -- provided the data is valid
+        {
+            if ($isbn != "") // if we've been given an ISBN then use it
+            {
+                $this->set_isbn($isbn);
+            }
+            if ( (isset($this->gtin14) && $this->valid_gtin14() == TRUE) || (isset($this->isbn13) && $this->valid_isbn13() == TRUE) || (isset($this->isbn10) && $this->valid_isbn10() == TRUE) ) // in this routine, we don't care what kind it is, only that it's valid.
+            {
+                return TRUE;
+            }
+            else
+            {
+                $this->error = "Checkdigit failure";
+                return FALSE;
+            }
+        }
+        /***********************************************/
+        
+        public function get_isbn10()
+        // return the ISBN-10 that has been set or create one if we have a valid ISBN-13
+        {
+            if ( $this->isbn10 != FALSE )
+            {
+                return $this->isbn10;
+            }
+            elseif ( $this->valid_isbn13() != FALSE )
+            {
+                if ( preg_match("@979@i", $this->isbn13) )
+                {
+                    $this->error = "979 Bookland EAN values can't be converted to ISBN-10";
+                    return FALSE; // if it's a 979 prefix it can't be downgraded
+                }
+                else
+                {
+                    $this->set_isbn10(substr($this->isbn13, 3, 10)); // invalid ISBN used as a temp value for next step
+                    $checkdigit = $this->get_isbn10_checkdigit();
+                    $this->set_isbn10(substr($this->isbn13, 3, 9) . $checkdigit); // true value (I hope)
+                    return $this->isbn10;
+                }
+            }
+            else
+            {
+                $this->error = "No ISBN-10 value set or calculable";
+                return FALSE;
+            }
+        }
+        /*********************************************/
+        
+        public function get_isbn13()
+        // return the ISBN-13 that has been set or create one if we have a valid ISBN-10
+        {
+            if ( $this->isbn13 != FALSE )
+            {
+                return $this->isbn13;
+            }
+            elseif ( $this->valid_isbn10() != FALSE )
+            {
+                $this->set_isbn13("978" . substr($this->isbn10, 0, 9) . "0"); // invalid ISBN used as a temp value for next step
+                $checkdigit = (string) $this->get_isbn13_checkdigit();
+                $this->set_isbn13("978" . substr($this->isbn10, 0, 9) . $checkdigit); // true value (I hope)
+                return $this->isbn13;
+            }
+            else
+            {
+                $this->error = "No ISBN-10 value set or calculable";
+                return FALSE;
+            }
+        }
+        /*********************************************/ 
+
+        public function get_gtin14()
+        // return the ISBN-13 that has been set or create one if we have a valid ISBN-10
+        {
+            if ( $this->gtin14 != FALSE )
+            {
+                return $this->gtin14;
+            }
+            else
+            {
+                $this->error = "No GTIN-14 value set or calculable";
+                return FALSE;
+            }
+        }
+        /*********************************************/ 
+        
+        public function get_error()
+        // return the error message
+        {
+            return $this->error;
+        }
+        /*********************************************/ 
+        
+    }
+?>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/biblio_autocomplete.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+; $Id$
+name = Biblio Autocomplete
+description = Allows other modules to provide autocomplete functionality to Biblio nodes
+core = 7.x
+dependencies[] = biblio
+package = Biblio
+; Information added by drupal.org packaging script on 2013-04-18
+version = "7.x-1.4"
+core = "7.x"
+project = "biblio_autocomplete"
+datestamp = "1366294251"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/biblio_autocomplete.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,92 @@
+<?php
+
+function biblio_autocomplete_menu(){
+  $items=array();
+  $autocompletes = module_invoke_all('biblio_autocomplete_info');
+  foreach ($autocompletes as $field => $data){
+  	$items['biblio_autocomplete/'.$field] = array(
+  	  'title' => t('Biblio autocomplete for ').$field,
+  	  'page callback' => 'biblio_autocomplete_json',
+  	  'page arguments' => array($field, 2),
+  	  'access callback' => TRUE,
+  	  'type' => MENU_CALLBACK,
+  	);
+  }
+  return $items;
+}
+
+function biblio_autocomplete_json($biblio_field, $string){
+  $autocompletes = module_invoke_all('biblio_autocomplete_info');
+  $matches = array();
+  foreach ($autocompletes as $field => $data){
+  	if ($field == $biblio_field){
+  		if (!is_array($data['function'])){
+  			$data['function'] = array($data['function']);
+  		}
+  	  foreach($data['function'] as $function){
+  	    $matches = array_merge($matches, $function($string) );
+  	  }
+  	}
+  }
+  asort($matches);
+  
+  $return_matches = array();
+  $i = 0;
+  foreach ($matches as $key => $data){
+  	if ($data['key'] != '' && $data['description'] != ''){
+  	  $i++;
+  	  $return_matches[$data['key']] = $data['provider'].': '.$data['description'];
+  	  if ($i >= 10){
+  		break;
+  	  }
+  	}
+  }
+  
+  print drupal_json_output($return_matches);
+}
+
+/**
+ * Implemets hook_form_alter().
+ *
+ * @param unknown_type $form
+ * @param unknown_type $form_state
+ * @param unknown_type $form_id
+ */
+function biblio_autocomplete_form_alter(&$form, &$form_state, $form_id){
+  if ($form_id == 'biblio_node_form'){
+    $autocompletes = module_invoke_all('biblio_autocomplete_info');
+    foreach ($autocompletes as $field => $values){
+      if (in_array($field, $form)){
+      	$key = array_tree_search_key($form, $field);
+      	if (!is_null($key)){
+      	  array_tree_update_autocomplete($form, $key, 'biblio_autocomplete/'.$field);
+      	}
+      }
+    }
+  }
+}
+
+function array_tree_search_key($a, $subkey) {
+if (is_array($a)){
+   foreach (array_keys($a) as $i=>$k) {
+      if ($k === $subkey) {
+         return array($k);
+      }
+      elseif ($pos = array_tree_search_key($a[$k], $subkey)) {
+         return array_merge(array($k), $pos);
+      }
+   }
+}
+}
+
+function array_tree_update_autocomplete(&$a, $key_array, $autocomplete){
+  if (count($key_array) == 0){
+  	$a['#autocomplete_path'] = $autocomplete;
+  } else {
+  	$a_next = array_shift($key_array);
+  	array_tree_update_autocomplete($a[$a_next], $key_array, $autocomplete);
+  }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/plugins/biblio_ipni/biblio_ipni.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+; $Id$
+name = Biblio IPNI autocomplete
+description = Allows autocompletion of Biblio fields from IPNI.
+core = 7.x
+dependencies[] = biblio_autocomplete
+package = Biblio
+
+
+; Information added by drupal.org packaging script on 2013-04-18
+version = "7.x-1.4"
+core = "7.x"
+project = "biblio_autocomplete"
+datestamp = "1366294251"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/plugins/biblio_ipni/biblio_ipni.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,202 @@
+<?php
+
+/**
+ * Implements hook_biblio_autocomplete_info().
+ * 
+ * @return $fields
+ *   An array of Biblio fields with associated autocomplete data.
+ *   Format: 
+ *     'biblio_field_to_autocomplete' => array('function' => 'autocomplete_callback_function')
+ */
+function biblio_ipni_biblio_autocomplete_info(){
+	$fields = array(
+	  'biblio_secondary_title' => array('function' => 'biblio_ipni_autocomplete_publication'),
+	  'biblio_alternate_title' => array('function' => 'biblio_ipni_autocomplete_publication'),
+	  'biblio_original_publication' => array('function' => 'biblio_ipni_autocomplete_publication'),
+	  'biblio_short_title' => array('function' => 'biblio_ipni_autocomplete_short_publication'),
+	  'title' => array('function' => 'biblio_ipni_autocomplete_publication'),
+	  'biblio_authors' => array('function' => 'biblio_ipni_autocomplete_author_short'),
+	);
+	return $fields;
+}
+
+/**
+ * 
+ * Gets a list of potential publication matches for the autocomplete
+ * 
+ * @param $string
+ *   Text string to try and match
+ *   
+ * @return $return_matches
+ *   An array of autocomplete results for use in biblio_autocomple_json().
+ *   Format: 
+ *     array(
+ *       'key' => 'value to put in biblio field', 
+ *       'description' => 'can be the same as key or contain extra information to help use decide', 
+ *       'provider' => 'source of the autocmplete information',
+ *     )
+ */
+function biblio_ipni_autocomplete_publication($string){
+  $ipni_matches = biblio_ipni_get_publication_data($string);
+  $return_matches = array();
+  foreach($ipni_matches as $result){
+    $return_matches[] = array(
+      'key' => $result[3],
+      'description' => $result[3],
+      'provider' => 'IPNI',
+    );
+  }
+  return $return_matches;
+}
+
+/**
+ * 
+ * Gets a list of potential short (abbreviated) publication matches for the autocomplete
+ * 
+ * @param $string
+ *   Text string to try and match
+ *   
+ * @return $return_matches
+ *   An array of autocomplete results for use in biblio_autocomple_json().
+ *   Format: 
+ *     array(
+ *       'key' => 'value to put in biblio field', 
+ *       'description' => 'can be the same as key or contain extra information to help use decide', 
+ *       'provider' => 'source of the autocmplete information',
+ *     )
+ */
+function biblio_ipni_autocomplete_short_publication($string){
+  $ipni_matches = biblio_ipni_get_publication_data_short($string);
+  foreach($ipni_matches as $result){
+    $return_matches[] = array(
+      'key' => $result[2],
+      'description' =>     $result[2] . ' | ' . $result[3],
+      'provider' => 'IPNI',
+    );
+    
+
+  }
+  return $return_matches;
+}
+
+/**
+ * 
+ * Function to get publication data from IPNI
+ * 
+ * @param $string
+ *   Text string to try and match
+ *   
+ * @return $ipni_matches
+ *   An array of matched data from IPNI
+ */
+function biblio_ipni_get_publication_data($string){
+  $ipni_result = file_get_contents('http://www.ipni.org/ipni/advPublicationSearch.do?find_title=' . str_replace(' ', '+', $string) . '&output_format=delimited');
+  $ipni_matches = biblio_ipni_process_file($ipni_result);
+  return $ipni_matches;
+}
+
+/**
+ * 
+ * Function to get short publication data from IPNI
+ * 
+ * @param $string
+ *   Text string to try and match
+ *   
+ * @return $ipni_matches
+ *   An array of matched data from IPNI
+ */
+function biblio_ipni_get_publication_data_short($string){
+  $ipni_result = file_get_contents('http://www.ipni.org/ipni/advPublicationSearch.do?find_abbreviation=' . str_replace(' ', '+', $string) . '&output_format=delimited');
+  $ipni_matches = biblio_ipni_process_file($ipni_result);
+  return $ipni_matches;
+}
+
+/**
+ * 
+ * Gets a list of potential author matches for the autocomplete
+ * 
+ * @param $string
+ *   Text string to try and match
+ *   
+ * @return $return_matches
+ *   An array of autocomplete results for use in biblio_autocomple_json().
+ *   Format: 
+ *     array(
+ *       'key' => 'value to put in biblio field', 
+ *       'description' => 'can be the same as key or contain extra information to help use decide', 
+ *       'provider' => 'source of the autocmplete information',
+ *     )
+ */
+function biblio_ipni_autocomplete_author_short($string){
+  $ipni_matches = biblio_ipni_get_author_data($string);
+  foreach($ipni_matches as $result){
+    $return_matches[$result[5]] = $result[2];
+    $return_matches[] = array(
+      'key' => $result[5],
+      'description' => $result[2],
+      'provider' => 'IPNI',
+    );
+  }
+  return $return_matches;
+}
+
+/**
+ * 
+ * Function to get author data from IPNI
+ * 
+ * @param $string
+ *   Text string to try and match
+ *   
+ * @return $ipni_matches
+ *   An array of matched data from IPNI
+ */
+function biblio_ipni_get_author_data($string){
+  $ipni_result = file_get_contents('http://www.ipni.org/ipni/advAuthorSearch.do?find_abbreviation=' . str_replace(' ', '+', $string) . '&output_format=delimited');
+  $ipni_matches = biblio_ipni_process_file($ipni_result);
+  return $ipni_matches;
+}
+
+/**
+ * 
+ * IPNI data is delimited by newlines and the % character, this function parses
+ * this format into an array
+ * 
+ * @param $file
+ *   Input file from IPNI
+ *   
+ * @return $ipni_matches
+ *   An array of data parsed from $file
+ */
+function biblio_ipni_process_file($file){
+  $ipni_result = explode("\n", $file);
+  $i = 0;
+  $ipni_matches = array();
+  foreach($ipni_result as $result){
+    $i++;
+    $ipni_matches[] = explode('%', $result);
+    if($i > 10){
+      break;
+    }
+  }
+  array_shift($ipni_matches);
+  array_walk($ipni_matches, 'biblio_ipni_clean');
+  return $ipni_matches;
+}
+
+
+/**
+ * 
+ * Function called by array_walk() in biblio_ipni_process_file() to remove
+ * artefacts from the IPNI data
+ * 
+ * @param $value
+ */
+function biblio_ipni_clean(&$value){
+  if(is_array($value)){
+    array_walk($value, 'biblio_ipni_clean');
+  }else{
+    if(substr($value, 0, 1) == '>'){
+      $value = substr($value, 1);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/plugins/biblio_self/biblio_self.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+; $Id$
+name = Biblio self autocomplete
+description = Allows autocompletion of Biblio fields from previously used entries.
+core = 7.x
+dependencies[] = biblio_autocomplete
+package = Biblio
+
+
+; Information added by drupal.org packaging script on 2013-04-18
+version = "7.x-1.4"
+core = "7.x"
+project = "biblio_autocomplete"
+datestamp = "1366294251"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/plugins/biblio_self/biblio_self.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * Implements hook_biblio_autocomplete_info().
+ * 
+ * @return $fields
+ *   An array of Biblio fields with associated autocomplete data.
+ *   Format: 
+ *     'biblio_field_to_autocomplete' => array('function' => 'autocomplete_callback_function')
+ */
+function biblio_self_biblio_autocomplete_info(){
+	$fields = array(
+	  'biblio_secondary_title' => array('function' => 'biblio_self_autocomplete_secondary_title'),
+	  'biblio_tertiary_title' => array('function' => 'biblio_self_autocomplete_tertiary_title'),
+	  'biblio_alternate_title' => array('function' => 'biblio_self_autocomplete_alternate_title'),
+	  'biblio_original_publication' => array('function' => 'biblio_self_autocomplete_original_publication'),
+	  'biblio_short_title' => array('function' => 'biblio_self_autocomplete_short_title'),
+	  'biblio_publisher' => array('function' => 'biblio_self_autocomplete_publisher'),
+	  'biblio_place_published' => array('function' => 'biblio_self_autocomplete_place_published'),
+	  'biblio_type_of_work' => array('function' => 'biblio_self_autocomplete_type_of_work'),
+	  'biblio_translated_title' => array('function' => 'biblio_self_autocomplete_translated_title'),
+	);
+	return $fields;
+}
+
+function biblio_self_autocomplete_secondary_title($string){
+  return biblio_self_autocomplete($string, 'secondary_title');
+}
+
+function biblio_self_autocomplete_tertiary_title($string){
+	return biblio_self_autocomplete($string, 'tertiary_title');
+}
+
+function biblio_self_autocomplete_alternate_title($string){
+	return biblio_self_autocomplete($string, 'alternate_title');
+}
+
+function biblio_self_autocomplete_original_publication($string){
+	return biblio_self_autocomplete($string, 'original_publication');
+}
+	
+function biblio_self_autocomplete_short_title($string){
+	return biblio_self_autocomplete($string, 'short_title');
+}
+
+function biblio_self_autocomplete_publisher($string){
+	return biblio_self_autocomplete($string, 'publisher');
+}
+
+function biblio_self_autocomplete_place_published($string){
+	return biblio_self_autocomplete($string, 'place_published');
+}
+
+function biblio_self_autocomplete_type_of_work($string){
+	return biblio_self_autocomplete($string, 'type_of_work');
+}
+
+function biblio_self_autocomplete_translated_title($string){
+	return biblio_self_autocomplete($string, 'translated_title');
+}
+
+
+function biblio_self_autocomplete($string, $field){
+	$field = 'biblio_'.$field;
+	$sql = 'SELECT DISTINCT '.$field.' FROM biblio WHERE '.$field." LIKE '%".$string."%';";
+	$result = db_query($sql)->fetchAll();
+	$results = array();
+	foreach ($result as $match){
+		$results[] = array(
+		  'key' => $match->$field,
+		  'description' => $match->$field,
+		  'provider' => 'Biblio',
+		);
+	}
+	return $results;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/plugins/biblio_zoobank/biblio_zoobank.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+; $Id$
+name = Biblio ZooBank autocomplete
+description = Allows autocompletion of Biblio fields using ZooBank
+core = 7.x
+dependencies[] = biblio_autocomplete
+package = Biblio
+
+
+; Information added by drupal.org packaging script on 2013-04-18
+version = "7.x-1.4"
+core = "7.x"
+project = "biblio_autocomplete"
+datestamp = "1366294251"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_autocomplete/plugins/biblio_zoobank/biblio_zoobank.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,440 @@
+<?php
+
+/**
+ * Implements hook_biblio_autocomplete_info().
+ * 
+ * @return $fields
+ *   An array of Biblio fields with associated autocomplete data.
+ *   Format: 
+ *     'biblio_field_to_autocomplete' => array('function' => 'autocomplete_callback_function')
+ */
+function biblio_zoobank_biblio_autocomplete_info(){
+	$fields = array(
+	  'biblio_secondary_title' => array('module' => 'biblio_zoobank', 'function' => 'biblio_zoobank_autocomplete_publication'),
+	  'biblio_alternate_title' => array('module' => 'biblio_zoobank', 'function' => 'biblio_zoobank_autocomplete_publication'),
+	  'biblio_original_publication' => array('module' => 'biblio_zoobank', 'function' => 'biblio_zoobank_autocomplete_publication'),
+	  'title' => array('module' => 'biblio_zoobank', 'function' => 'biblio_zoobank_autocomplete_publication'),
+	  'biblio_authors' => array('module' => 'biblio_zoobank', 'function' => 'biblio_zoobank_autocomplete_author_short'),
+	);
+	return $fields;
+}
+
+/**
+ * 
+ * Gets a list of potential publication matches for the autocomplete
+ * 
+ * @param $string
+ *   Text string to try and match
+ *   
+ * @return $return_matches
+ *   An array of autocomplete results for use in biblio_autocomple_json().
+ *   Format: 
+ *     array(
+ *       'key' => 'value to put in biblio field', 
+ *       'description' => 'can be the same as key or contain extra information to help use decide', 
+ *       'provider' => 'source of the autocmplete information',
+ *     )
+ */
+function biblio_zoobank_autocomplete_publication($string){
+  $zoobank_matches = biblio_zoobank_get_publication_data($string);
+  $return_matches = array();
+  foreach($zoobank_matches as $result => $data){
+    $return_matches[] = array(
+      'key' => strip_tags($data->title),
+      'description' => $data->label,
+      'provider' => 'ZooBank',
+    );
+  }
+  return $return_matches;
+}
+
+/**
+ * 
+ * Function to get publication data from ZooBank
+ * 
+ * @param $string
+ *   Text string to try and match
+ *   
+ * @return $zoobank_result
+ *   An array of data objects from ZooBank
+ */
+function biblio_zoobank_get_publication_data($string){
+  $zoobank_result = file_get_contents('http://test.zoobank.org/References.json?term=' . urlencode($string));
+  $zoobank_result = json_decode($zoobank_result);
+  
+  return $zoobank_result;
+}
+
+
+//Code below here relates to ZooBank biblio import function (not yet implemented)
+//
+//
+
+/**
+ * Implemets hook_menu().
+ * 
+ * @return $items
+ *   Array of menu_items
+ */
+function biblio_zoobank_menu(){
+	$items['biblio_autocomplete/zoobank_import'] = array(
+  	  'title' => t('ZooBank import lookup'),
+  	  'page callback' => 'biblio_zoobank_import_lookup',
+  	  'access callback' => TRUE,
+  	  'type' => MENU_CALLBACK,
+  	);
+  	return $items;
+}
+
+function biblio_zoobank_import_lookup($string){
+  $matches = biblio_zoobank_get_publication_data($string);
+  $return_matches = array();
+  $i = 0;
+  foreach ($matches as $result => $data){
+  	$i++;
+  	$return_matches[$data->referenceuuid] = $data->label; 
+  	if ($i >=10){
+  		break;
+  	}
+  }
+  print drupal_json_output($return_matches);
+}
+
+
+function biblio_zoobank_form_biblio_node_form_alter(&$form, &$form_state, $form_id) {
+  if ((!isset($form_state['biblio_type']) || empty($form_state['biblio_type'])) && !isset($form_state['node']->nid)) {
+    $form['biblio_zoobank_lookup'] = array(
+        '#type' => 'fieldset',
+        '#title' => t('ZooBank Lookup'),
+        '#weight' => -20,
+        '#collapsible' => TRUE,
+        '#collapsed' => TRUE,
+    );
+
+    $form['biblio_zoobank_lookup']['referenceuuid'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Lookup reference'),
+        '#required' => TRUE,
+        '#default_value' => '',
+        '#description' => t('Search for a publication in ZooBank'),
+        '#size' => 60,
+        '#maxlength' => 255,
+        '#weight' => -4,
+        '#autocomplete_path' => 'biblio_autocomplete/zoobank_import',
+    );
+    $form['biblio_zoobank_lookup']['zoobank_submit'] = array(
+        '#type' => 'submit',
+        '#value' => t('Populate from ZooBank'),
+        '#submit' => array('biblio_zoobank_form_biblio_node_form_submit')
+    );
+  }
+}
+
+function biblio_zoobank_form_biblio_node_form_submit($form, &$form_state){
+  $url = 'http://test.zoobank.org/References.json/427D7953-E8FC-41E8-BEA7-8AE644E6DE77';
+  $url = temp_zoobank_example();
+  $data = file_get_contents($url);
+  $data = json_decode($data);
+  
+  
+  //TODO: Fails here as ZooBank JSON is invalid
+  $i =0;
+  drupal_set_message('Node (would have been) created', 'status');
+}
+
+function temp_zoobank_example(){
+	$json='[
+    {
+        "columns": [
+            "pkid",
+            "uuid",
+            "referencetype",
+            "authors",
+            "year",
+            "numericyear",
+            "fulltitle",
+            "volume",
+            "number",
+            "edition",
+            "publisher",
+            "placepublished",
+            "pagination",
+            "startpage",
+            "endpage",
+            "startdateof",
+            "enddateof",
+            "startdateon",
+            "enddateon",
+            "datepublished",
+            "language",
+            "languageid",
+            "parentreferenceid",
+            "parentreferenceuuid",
+            "parentreference",
+            "formattedparentreference",
+            "typework",
+            "formatted",
+            "cleandisplay",
+            "citationdetails"
+        ],
+        "data": [
+            [
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                "Journal Article",
+                "Randall, John E. & Richard L. Pyle.",
+                "2001",
+                2001,
+                "Four new serranid fishes of the anthiine genus <i>Pseudanthias</i> from the South Pacific",
+                "49",
+                "1",
+                "",
+                "",
+                "",
+                "19-34",
+                "",
+                "",
+                "2001-01-01",
+                "2001-12-31",
+                "2001-01-01",
+                "2001-12-31",
+                "",
+                "English",
+                19691433,
+                19703683,
+                "0089FB37-AA19-41B8-8622-011CCA4EF778",
+                "Raffles Bulletin of Zoology",
+                "<I>Raffles Bulletin of Zoology</I>",
+                "",
+                "Randall, John E. & Richard L. Pyle.  2001. Four new serranid fishes of the anthiine genus <i>Pseudanthias</i> from the South Pacific. <I>Raffles Bulletin of Zoology</I> <B>49</B>(1): 19-34.",
+                "Randall, John E. & Richard L. Pyle.  2001. Four new serranid fishes of the anthiine genus Pseudanthias from the South Pacific. Raffles Bulletin of Zoology 49(1): 19-34.",
+                "<I>Raffles Bulletin of Zoology</I> <B>49</B>(1): 19-34."
+            ]
+        ]
+    },
+    {
+        "columns": [
+            "pkid",
+            "uuid",
+            "protonymid",
+            "protonymuuid",
+            "rankgroup",
+            "taxonnamerankid",
+            "referenceid",
+            "referenceuuid",
+            "originalreferenceid",
+            "originalreferenceuuid",
+            "startpage",
+            "illustration",
+            "validusageid",
+            "validusageuuid",
+            "parentusageid",
+            "parentusageuuid",
+            "parentname",
+            "originalparentusageid",
+            "originalparentusageuuid",
+            "genderid",
+            "isfossil",
+            "types",
+            "typelocality",
+            "authors",
+            "year",
+            "namestring",
+            "scientificname",
+            "cleandisplay",
+            "formatteddisplay",
+            "formattedprotonym",
+            "usageauthors",
+            "usageyear",
+            "cleanprotonym",
+            "isprotonym"
+        ],
+        "data": [
+            [
+                20195759,
+                "B1FBF746-782B-4AE8-9817-F4E3B8C03FFF",
+                20231068,
+                "F77E4029-F731-4B62-829E-A050365DF383",
+                "Genus",
+                60,
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                19714690,
+                "FDA2DE2F-54D6-43AE-9FB0-733138334F18",
+                "",
+                "",
+                20195759,
+                "B1FBF746-782B-4AE8-9817-F4E3B8C03FFF",
+                0,
+                "00000000-0000-0000-0000-000000000000",
+                "",
+                0,
+                "00000000-0000-0000-0000-000000000000",
+                1,
+                0,
+                "",
+                "",
+                "Bleeker",
+                "1871",
+                "Pseudanthias",
+                "<em>Pseudanthias</em> Bleeker in Bleeker 1871",
+                "Pseudanthias Bleeker in Bleeker 1871",
+                "<em>Pseudanthias</em> Bleeker in Bleeker 1871",
+                "<em>Pseudanthias</em> Bleeker in Bleeker 1871",
+                "Randall & Pyle",
+                "2001",
+                "Pseudanthias Bleeker in Bleeker 1871",
+                0
+            ],
+            [
+                20130879,
+                "6EA8BB2A-A57B-47C1-953E-042D8CD8E0E2",
+                20130879,
+                "6EA8BB2A-A57B-47C1-953E-042D8CD8E0E2",
+                "Species",
+                70,
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                "20",
+                "Figs. 1-4",
+                20130879,
+                "6EA8BB2A-A57B-47C1-953E-042D8CD8E0E2",
+                20195759,
+                "B1FBF746-782B-4AE8-9817-F4E3B8C03FFF",
+                "Pseudanthias",
+                20231068,
+                "F77E4029-F731-4B62-829E-A050365DF383",
+                0,
+                0,
+                "",
+                "",
+                "Randall & Pyle",
+                "2001",
+                "carlsoni",
+                "<em>Pseudanthias</em> <em>carlsoni</em> Randall & Pyle 2001",
+                "Pseudanthias carlsoni Randall & Pyle 2001",
+                "<em>Pseudanthias</em> <em>carlsoni</em> Randall & Pyle 2001",
+                "<em>Pseudanthias</em> <em>carlsoni</em> Randall & Pyle 2001",
+                "Randall & Pyle",
+                "2001",
+                "carlsoni Randall & Pyle 2001 (as a species of Pseudanthias)",
+                1
+            ],
+            [
+                20428317,
+                "07DAC21C-21CE-42E9-B835-686B03E98E81",
+                20428317,
+                "07DAC21C-21CE-42E9-B835-686B03E98E81",
+                "Species",
+                70,
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                "23",
+                "Figs. 5-8",
+                20428317,
+                "07DAC21C-21CE-42E9-B835-686B03E98E81",
+                20195759,
+                "B1FBF746-782B-4AE8-9817-F4E3B8C03FFF",
+                "Pseudanthias",
+                20231068,
+                "F77E4029-F731-4B62-829E-A050365DF383",
+                0,
+                0,
+                "",
+                "",
+                "Randall & Pyle",
+                "2001",
+                "flavicauda",
+                "<em>Pseudanthias</em> <em>flavicauda</em> Randall & Pyle 2001",
+                "Pseudanthias flavicauda Randall & Pyle 2001",
+                "<em>Pseudanthias</em> <em>flavicauda</em> Randall & Pyle 2001",
+                "<em>Pseudanthias</em> <em>flavicauda</em> Randall & Pyle 2001",
+                "Randall & Pyle",
+                "2001",
+                "flavicauda Randall & Pyle 2001 (as a species of Pseudanthias)",
+                1
+            ],
+            [
+                20070742,
+                "BB0F5636-525B-4B1F-BDAD-E4C4FA7EB03B",
+                20070742,
+                "BB0F5636-525B-4B1F-BDAD-E4C4FA7EB03B",
+                "Species",
+                70,
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                "25",
+                "Figs. 9-11",
+                20070742,
+                "BB0F5636-525B-4B1F-BDAD-E4C4FA7EB03B",
+                20195759,
+                "B1FBF746-782B-4AE8-9817-F4E3B8C03FFF",
+                "Pseudanthias",
+                20231068,
+                "F77E4029-F731-4B62-829E-A050365DF383",
+                0,
+                0,
+                "",
+                "",
+                "Randall & Pyle",
+                "2001",
+                "hiva",
+                "<em>Pseudanthias</em> <em>hiva</em> Randall & Pyle 2001",
+                "Pseudanthias hiva Randall & Pyle 2001",
+                "<em>Pseudanthias</em> <em>hiva</em> Randall & Pyle 2001",
+                "<em>Pseudanthias</em> <em>hiva</em> Randall & Pyle 2001",
+                "Randall & Pyle",
+                "2001",
+                "hiva Randall & Pyle 2001 (as a species of Pseudanthias)",
+                1
+            ],
+            [
+                20230739,
+                "C7D36E15-93A9-43CD-A1FE-D734B676D66D",
+                20230739,
+                "C7D36E15-93A9-43CD-A1FE-D734B676D66D",
+                "Species",
+                70,
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                19692512,
+                "427D7953-E8FC-41E8-BEA7-8AE644E6DE77",
+                "28",
+                "Fig. 12",
+                20230739,
+                "C7D36E15-93A9-43CD-A1FE-D734B676D66D",
+                20195759,
+                "B1FBF746-782B-4AE8-9817-F4E3B8C03FFF",
+                "Pseudanthias",
+                20231068,
+                "F77E4029-F731-4B62-829E-A050365DF383",
+                0,
+                0,
+                "",
+                "",
+                "Randall & Pyle",
+                "2001",
+                "privitera",
+                "<em>Pseudanthias</em> <em>privitera</em> Randall & Pyle 2001",
+                "Pseudanthias privitera Randall & Pyle 2001",
+                "<em>Pseudanthias</em> <em>privitera</em> Randall & Pyle 2001",
+                "<em>Pseudanthias</em> <em>privitera</em> Randall & Pyle 2001",
+                "Randall & Pyle",
+                "2001",
+                "privitera Randall & Pyle 2001 (as a species of Pseudanthias)",
+                1
+            ]
+        ]
+    }
+]';
+	
+	$json = preg_replace('/\s+/', '', $json);
+	
+	return $json;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_scholar/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_scholar/biblio_scholar.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+; $Id$
+name = Biblio Scholar
+description = Adds Google Scholar metatags to Biblio nodes.
+core = 7.x
+dependencies[] = biblio
+package = Biblio
+
+
+; Information added by drupal.org packaging script on 2012-11-22
+version = "7.x-1.6"
+core = "7.x"
+project = "biblio_scholar"
+datestamp = "1353587456"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/biblio_scholar/biblio_scholar.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,105 @@
+<?php
+
+// $Id$
+/**
+ * @file
+ * Add Google Scholar metatags to Biblio node pages
+ */
+function biblio_scholar_preprocess_node($variables){
+  if($variables['type'] == 'biblio'){
+    drupal_add_html_head(array(
+      '#tag' => 'meta',
+      '#attributes' => array(
+        'name' => 'citation_title',
+        'content' => $variables['title']
+      )
+    ), 'biblio_scholar_title');
+    //Sort out the authors
+    $i = 0;
+    foreach($variables['biblio_contributors'] as $author){
+      $author_types = array(1,2,3,4);
+      if(in_array($author['auth_type'], $author_types) ){
+        drupal_add_html_head(array(
+          '#tag' => 'meta',
+          '#attributes' => array(
+            'name' => 'citation_author',
+            'content' => $author['name']
+          ),
+          '#weight' => $i,
+        ), 'biblio_scholar_author' . $i);
+        $i++;
+      }
+    }
+    if($variables['biblio_year'] != ''){
+      drupal_add_html_head(array(
+        '#tag' => 'meta',
+        '#attributes' => array(
+          'name' => 'citation_publication_date',
+          'content' => $variables['biblio_year']
+        )
+      ), 'biblio_scholar_publication_date');
+    }
+    if($variables['biblio_secondary_title'] != ''){
+      drupal_add_html_head(array(
+        '#tag' => 'meta',
+        '#attributes' => array(
+          'name' => 'citation_journal_title',
+          'content' => $variables['biblio_secondary_title']
+        )
+      ), 'biblio_scholar_secondary_title');
+    }
+    if($variables['biblio_volume'] != ''){
+      drupal_add_html_head(array(
+        '#tag' => 'meta',
+        '#attributes' => array(
+          'name' => 'citation_volume',
+          'content' => $variables['biblio_volume']
+        )
+      ), 'biblio_scholar_volume');
+    }
+    if($variables['biblio_issue'] != ''){
+      drupal_add_html_head(array(
+        '#tag' => 'meta',
+        '#attributes' => array(
+          'name' => 'citation_issue',
+          'content' => $variables['biblio_issue']
+        )
+      ), 'biblio_scholar_issue');
+    }
+    if($variables['biblio_isbn'] != ''){
+      drupal_add_html_head(array(
+        '#tag' => 'meta',
+        '#attributes' => array(
+          'name' => 'citation_isbn',
+          'content' => $variables['biblio_isbn']
+        )
+      ), 'biblio_scholar_isbn');
+    }
+    if($variables['biblio_issn'] != ''){
+      // drupal_set_html_head('<meta name="citation_issn" content="' . $variables['biblio_issn'] . '"/>');
+      drupal_add_html_head(array(
+        '#tag' => 'meta',
+        '#attributes' => array(
+          'name' => 'citation_issn',
+          'content' => $variables['biblio_issn']
+        )
+      ), 'biblio_scholar_issn');
+    }
+    
+    foreach ($variables as $key => $field){
+      if (is_array($field) && isset($field[0]['fid'])){
+      	foreach ($field as $file){
+      	  if ($file['filemime'] == 'application/pdf'){
+    		drupal_add_html_head(array(
+    		  '#tag' => 'meta',
+    		  '#attributes' => array(
+    		    'name' => 'citation_pdf_url',
+    		    'content' => url(file_create_url($file['uri']), array('absolute' => TRUE))
+    		)
+    		), 'biblio_scholar_url');
+    	  }
+      	}
+      }
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,39 @@
+Description:
+  The main target of the Bundle Inherit module is to allow users to inherit
+  bundles of different entity types from any other bundles of the same entity
+  type. Inheritance could be performed while creating new bundle of some entity
+  type (for example new content type). There are two types (modes) of inherit
+  available:
+  - Soft: All field instances from existing (parent) bundle will be cloned and
+     attached to the newly created bundle. As for the soft mode it is all.
+  - Strict: All field instances from existing (parent) bundle will be cloned and
+     attached to the newly created bundle. After that you will not be able to
+     directly edit inherited field instances in the children bundles and they
+     will be always kept synchronized.
+
+Structure:
+  Consist of two modules.
+  First module only Provide API for other modules to implement inheritance logic
+  on their (or other modules) entity types.
+  Second one extends node module and allow end users to inherit new content
+  types from already created.
+
+  Support for other entity types (like commerce products, etc) could be easily
+  added by writing appropriate module. You can look at Bundle Inherit Node
+  module (included in Bundle Inherit module basic package, presented on this
+  page) for example of bundle inheritance logic implementation.
+
+Demo
+  Demo site: http://demo.etreyd.com/
+  Demo login: demo
+  Demo password: demo
+
+Module project page:
+  http://drupal.org/project/bundle_inherit
+
+To submit bug reports and feature suggestions, or to track changes:
+  http://drupal.org/project/issues/bundle_inherit
+
+-- MAINTAINERS --
+
+lemark - http://drupal.org/user/317870
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/bundle_inherit.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,10 @@
+name = Bundle Inheritance
+description = Provide API for modules to implement bundle inheritance logic
+core = 7.x
+files[] = bundle_inherit.test
+; Information added by drupal.org packaging script on 2011-11-05
+version = "7.x-1.0-alpha2"
+core = "7.x"
+project = "bundle_inherit"
+datestamp = "1320523829"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/bundle_inherit.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @file
+ * Bundle Inherit module install file.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function bundle_inherit_schema() {
+  $schema['bundle_hierarchy'] = array(
+    'description' => 'Holds info about hierarchy relations between entity types.',
+    'fields' => array(
+      'entity_type' => array(
+        'description' => 'The entity type of the bundles.',
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+      ),
+      'bundle' => array(
+        'description' => 'Child bundle name.',
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+      ),
+      'bundle_parent' => array(
+        'description' => 'Parent bundle name.',
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('entity_type', 'bundle'),
+    'indexes' => array(
+      'parent' => array('entity_type', 'bundle_parent'),
+    ),
+  );
+
+
+  return $schema;
+}
+
+
+/**
+ * Implements hook_uninstall().
+ *
+ * We should remove 'locked' state from all inherited fields instances.
+ *
+ * @todo
+ *   Maybe some better way to implement this function exists (talking about
+ *   performance). But anyway we are getting info about instances from cache
+ *   so I think that this implementation is more stable and logicaly loocking.
+ */
+function bundle_inherit_uninstall() {
+  $records = db_select('bundle_hierarchy', 'bh')
+    ->fields('bh')
+    ->execute();
+  foreach ($records as $record) {
+    $instances = field_info_instances($record->entity_type, $record->bundle_parent);
+    foreach ($instances as $instance) {
+      $inherited_instance = field_info_instance($record->entity_type, $instance['field_name'], $record->bundle);
+      $inherited_instance['locked'] = FALSE;
+      field_update_instance($inherited_instance);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/bundle_inherit.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,294 @@
+<?php
+/**
+ * @file
+ * Bundle Inherit module.
+ */
+
+/**
+ * Perform necesary inherit operations.
+ */
+function bundle_inherit_perform($entity_type, $bundle, $bundle_parent, $strict = TRUE) {
+  // Get fields from parent bundle.
+  $instances = field_info_instances($entity_type, $bundle_parent);
+  foreach ($instances as $instance) {
+    $new_instance = $instance;
+    $new_instance['bundle'] = $bundle;
+
+    if ($strict) {
+      $new_instance['locked'] = TRUE;
+    }
+
+    $new_instance = field_create_instance($new_instance);
+    $query = db_select('field_config_instance', 'fci');
+    $query->addField('fci', 'id');
+    $query->condition('fci.bundle', $bundle);
+    $new_instance['id'] = $query->execute()->fetchField();
+  }
+  // Check if we perform strict inheritance.
+  if ($strict) {
+    db_insert('bundle_hierarchy')
+      ->fields(array(
+        'entity_type' => $entity_type,
+        'bundle' => $bundle,
+        'bundle_parent' => $bundle_parent
+      ))
+      ->execute();
+    watchdog('bundle_inherit', 'The %bundle bundle of the entity %type was STRICTLY inherited from %parent_bundle bundle.', array('%bundle' => $bundle, '%bundle_parent' => $bundle_parent, '%type' => $entity_type));
+    drupal_static_reset('bundle_inherit_bundle_get_children');
+  }
+  else{
+    watchdog('bundle_inherit', 'The %bundle bundle of the entity %type was SOFTLY inherited from %parent_bundle bundle.', array('%bundle' => $bundle, '%bundle_parent' => $bundle_parent, '%type' => $entity_type));
+  }
+}
+
+/**
+ * Implements hook_field_create_instance().
+ */
+function bundle_inherit_field_create_instance($instance) {
+  $children = bundle_inherit_bundle_get_children($instance['entity_type'], $instance['bundle']);
+  foreach ($children as $bundle) {
+    $new_instance = $instance;
+    unset($new_instance['id']);
+    $new_instance['bundle'] = $bundle;
+    $new_instance['locked'] = TRUE;
+    field_create_instance($new_instance);
+  }
+}
+
+/**
+ * Implements hook_field_update_instance().
+ */
+function bundle_inherit_field_update_instance($instance, $prior_instance) {
+  $children = bundle_inherit_bundle_get_children($prior_instance['entity_type'], $prior_instance['bundle']);
+
+  foreach ($children as $bundle) {
+    $old_instance = field_info_instance($instance['entity_type'], $instance['field_name'], $bundle);
+
+    $new_instance = array(
+      'id' => $old_instance['id'],
+      'bundle' => $old_instance['bundle'],
+      'locked' => TRUE
+    );
+    $new_instance += $instance;
+
+    field_update_instance($new_instance);
+  }
+}
+
+/**
+ * Implements hook_field_delete_instance().
+ */
+function bundle_inherit_field_delete_instance($instance) {
+  $children = bundle_inherit_bundle_get_children($instance['entity_type'], $instance['bundle']);
+  foreach ($children as $bundle) {
+    $new_instance = $instance;
+    $new_instance['bundle'] = $bundle;
+    $new_instance['locked'] = FALSE;
+    try {
+      field_update_instance($new_instance);
+    }
+    catch (Exception $e) {
+      drupal_set_message($e->getMessage(), 'error');
+    }
+  }
+}
+
+/**
+ * Implements hook_form_FORMID_alter().
+ *
+ * Attach additional validation callback to the field_ui_field_overview_form.
+ * When adding new field instance to the parent we should check that all of it
+ * childrens hase not that field instances.
+ */
+function bundle_inherit_form_field_ui_field_overview_form_alter(&$form, &$form_instance, $form_id) {
+  $form['#validate'][] = 'bundle_inherit_validate_field_instance_creation';
+}
+
+/**
+ * Additional validation function to the field_ui_field_overview_form.
+ *
+ * While adding existing field instance, get this form is created for and set
+ * form error if any of this children has instance of this field.
+ */
+function bundle_inherit_validate_field_instance_creation($form, &$form_state) {
+  $form_values = $form_state['values']['fields'];
+  if (!empty($form_values['_add_existing_field']['field_name'])) {
+    $children = bundle_inherit_bundle_get_children_all($form['#entity_type'], $form['#bundle']);
+    $bundles_with_instance = array();
+    foreach ($children as $child) {
+      $prior_instance = field_info_instance($form['#entity_type'], $form_values['_add_existing_field']['field_name'], $child);
+      if (!empty($prior_instance)) {
+        $bundles_with_instance[] = $prior_instance['bundle'];
+      }
+    }
+    if (count($bundles_with_instance) > 0) {
+      $string = implode(", ", $bundles_with_instance);
+      form_set_error('fields][_add_existing_field', t("Instance of the field %field can't be attached to %bundle bundle because this field instances are already attached to some of this bundle children bundles: %children", array('%bundle' => $form['#bundle'], '%field' => $form_values['_add_existing_field']['field_name'], '%children' => $string)));
+    }
+  }
+}
+
+/**
+ * Get direct children bundles of the selected entity bundle.
+ */
+function bundle_inherit_bundle_get_children($entity_type, $bundle_parent) {
+  $children = &drupal_static(__FUNCTION__);
+  if (!isset($children[$entity_type][$bundle_parent])) {
+    $children[$entity_type][$bundle_parent] = db_select('bundle_hierarchy', 'bh')
+      ->fields('bh', array('bundle'))
+      ->condition('bundle_parent', $bundle_parent)
+      ->condition('entity_type', $entity_type)
+      ->execute()
+      ->fetchCol();
+  }
+  return $children[$entity_type][$bundle_parent];
+}
+
+/**
+ * Get all children bundles of the selected entity bundle.
+ */
+function bundle_inherit_bundle_get_children_all($entity_type, $bundle_parent) {
+  $children = array();
+  $children = bundle_inherit_bundle_get_children($entity_type, $bundle_parent);
+  foreach ($children as $child) {
+    $children = array_merge($children, bundle_inherit_bundle_get_children_all($entity_type, $child));
+  }
+  return $children;
+}
+
+/**
+ * Get parent of the selected entity bundle.
+ *
+ * @return
+ *   Entity type parent type.
+ */
+function bundle_inherit_bundle_get_parent($entity_type, $bundle) {
+  $parent = &drupal_static(__FUNCTION__);
+  if (!isset($parent[$entity_type][$bundle])) {
+    $parent[$entity_type][$bundle] = db_select('bundle_hierarchy', 'bh')
+      ->fields('bh', array('bundle_parent'))
+      ->condition('bh.bundle', $bundle)
+      ->execute()
+      ->fetchField();
+    if (!$parent[$entity_type][$bundle]) $parent[$entity_type][$bundle] = '';
+  }
+  return $parent[$entity_type][$bundle];
+}
+
+/**
+ * Attach ineritance form to selected form element.
+ *
+ * @param $form
+ *   Parent form element to attach inheritance form to.
+ * @param $form_state
+ *   From state from the parent form.
+ * @param $entity_type
+ *   Entity for which bundle is creating for.
+ * @param $bundle
+ *   If editing existing bundle value for this argument should be provided.
+ */
+function bundle_inherit_attach_inherit_form(&$form, &$form_state, $entity_type, $bundle = '') {
+  $entity = entity_get_info($entity_type);
+  if (count($entity['bundles']) > 0) {
+    if (empty($bundle)) {
+      $form['bundle_inherit'] = array(
+        '#type' => 'fieldset',
+        '#tree' => TRUE,
+        '#title' => t('Inheritance')
+      );
+      $form['bundle_inherit']['entity_type'] = array('#type' => 'value', '#value' => $entity_type);
+      $form['bundle_inherit']['#parents'] = array('bundle_inherit');
+      $form['bundle_inherit']['inherit'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Inherit from other')
+      );
+
+      foreach ($entity['bundles'] as $bundle_name => $bundle) {
+        $options[$bundle_name] = $bundle['label'];
+      }
+      $form['bundle_inherit']['parent_type'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#title' => t('Parent'),
+        '#states' => array(
+          // Hide the inheritance settings when inherit checkbox is disabled.
+          'invisible' => array(
+            'input[name="bundle_inherit[inherit]"]' => array('checked' => FALSE),
+          ),
+        ),
+      );
+      $form['bundle_inherit']['mode'] = array(
+        '#type' => 'radios',
+        '#options' => array(
+          'strict' => t('Strict inherit'),
+          'soft' => t('Soft inherit'),
+        ),
+        '#default_value' => 'strict',
+        '#required' => TRUE,
+        '#states' => array(
+          // Hide the inheritance settings when inherit checkbox is disabled.
+          'invisible' => array(
+           'input[name="bundle_inherit[inherit]"]' => array('checked' => FALSE),
+          ),
+        ),
+        '#title' => t('Inheritance mode')
+      );
+    }
+    else {
+      $parent_bundle_name = bundle_inherit_bundle_get_parent($entity_type, $bundle);
+      if (!empty($parent_bundle_name)) {
+        $form['bundle_inherit'] = array(
+          '#type' => 'fieldset',
+          '#tree' => TRUE,
+          '#title' => t('Inheritance')
+        );
+        $form['bundle_inherit']['message'] = array(
+          '#markup' => t('This bundle was inherited from !parent_bundle bundle.', array('!parent_bundle' => l($entity['bundles'][$parent_bundle_name]['label'], $entity['bundles'][$parent_bundle_name]['admin']['real path'].'/fields')))
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Should be executed when entity creation form is submiting.
+ *
+ * @param $bundle
+ *   Newly created bundle name.
+ */
+function bundle_inherit_attach_inherit_form_submit($bundle, &$form, &$form_state) {
+  if (isset($form_state['values']['bundle_inherit']) && $form_state['values']['bundle_inherit']['inherit']) {
+    $bundle_inherit_values = $form_state['values']['bundle_inherit'];
+    bundle_inherit_perform($bundle_inherit_values['entity_type'], $bundle, $bundle_inherit_values['parent_type'], $bundle_inherit_values['mode'] == 'strict' ? TRUE : FALSE);
+  }
+}
+
+/**
+ * Implements hook_field_attach_delete_bundle().
+ */
+function bundle_inherit_field_attach_delete_bundle($entity_type, $bundle, $instances) {
+  db_delete('bundle_hierarchy')
+    ->condition('entity_type', $entity_type)
+    ->condition(db_or()->condition('bundle_parent', $bundle)->condition('bundle', $bundle))
+    ->execute();
+}
+
+/**
+ * Implements hook_field_attach_rename_bundle().
+ */
+function bundle_inherit_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
+  db_update('bundle_hierarchy')
+    ->condition('entity_type', $entity_type)
+    ->condition('bundle', $bundle_old)
+    ->fields(array(
+        'bundle' => $bundle_new
+    ))
+    ->execute();
+  db_update('bundle_hierarchy')
+    ->condition('entity_type', $entity_type)
+    ->condition('bundle_parent', $bundle_old)
+    ->fields(array(
+        'bundle_parent' => $bundle_new
+    ))
+    ->execute();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/bundle_inherit.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,127 @@
+<?php
+/**
+ * @file
+ * Tests for bundle_inherit module.
+ */
+
+class BundleInherit extends  DrupalWebTestCase {
+  protected $parentType, $childType, $customFields, $extraField;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Bundle Inherit',
+      'description' => 'Ensure that the Bundle Inherit module works properly',
+      'group' => 'Bundle Inherit'
+    );
+  }
+
+  public function setUp($modules = array()) {
+    $modules += array('bundle_inherit', 'node');
+    parent::setUp($modules);
+
+    // Add new content type (for example we'll create node type, but generaly,
+    // kind of the entity type does not matter here)
+    $this->parentType = $this->drupalCreateContentType();
+    $this->childType = $this->drupalCreateContentType();
+    // Create custom field
+    do {
+      $field_name = drupal_strtolower($this->randomName());
+    } while (field_info_field($field_name));
+    // Add 5 custom fields
+    for ($i = 0; $i < 5; $i++) {
+      do {
+        $field_name = drupal_strtolower($this->randomName());
+      } while (field_info_field($field_name));
+      $this->customFields[$field_name]['field'] = field_create_field(array(
+          'field_name' => $field_name,
+          'type' => 'text'
+      ));
+      field_create_instance(array(
+          'field_name' => $field_name,
+          'entity_type' => 'node',
+          'bundle' => $this->parentType->type
+      ));
+      $this->customFields[$field_name]['instance'] = field_info_instance('node', $field_name, $this->parentType->type);
+    }
+    do {
+      $field_name = drupal_strtolower($this->randomName());
+    } while (field_info_field($field_name));
+    $this->extraField['field'] = field_create_field(array(
+        'field_name' => $field_name,
+        'type' => 'text'
+    ));
+  }
+
+  public function inheritPerform() {
+    // When implementing inheritance on node entity type we should delete body
+    // field first.
+    if ($body_field_instance = field_info_instance('node', 'body', $this->childType->type)) {
+      field_delete_instance($body_field_instance);
+    }
+
+    // Perform inherit operations
+    bundle_inherit_perform('node', $this->childType->type, $this->parentType->type, TRUE);
+
+    $type_inherited = db_query('SELECT 1 FROM {bundle_hierarchy} WHERE entity_type = :entity_type AND bundle = :bundle AND bundle_parent = :bundle_parent', array(':entity_type' => 'node', ':bundle' => $this->childType->type, ':bundle_parent' => $this->parentType->type))->fetchField();
+    $this->assertTrue($type_inherited, t('Type was inherited.'));
+
+   // Check if fields instances was succesfuly inherited
+    $n = 1;
+    foreach ($this->customFields as $field_name => $field) {
+      $parent_type_field_instance = $this->customFields[$field_name]['instance'];
+      $child_type_field_instance = field_info_instance('node', $field_name, $this->childType->type);
+      $this->assertTrue($this->compareInstances($parent_type_field_instance, $child_type_field_instance), t('Child field instance %n is equal to the parent one', array('%n' => $n++)));
+    }
+  }
+
+  public function fieldInstanceCreate() {
+    field_create_instance(array(
+      'field_name' => $this->extraField['field']['field_name'],
+      'entity_type' => 'node',
+      'bundle' => $this->parentType->type
+    ));
+    $this->extraField['instance'] = field_info_instance('node', $this->extraField['field']['field_name'], $this->parentType->type);
+    $parent_type_field_instance = $this->extraField['instance']; $child_type_field_instance = field_info_instance('node', $this->extraField['field']['field_name'], $this->childType->type);
+    $this->assertTrue($this->compareInstances($parent_type_field_instance, $child_type_field_instance), t('The field instance attached to the parent type was succesfuly attached to the child type and equal to the parent one.'));
+  }
+
+  public function fieldInstanceUpdate() {
+    $this->extraField['instance']['label'] = $this->randomString();
+    $this->extraField['instance']['required'] = TRUE;
+    field_update_instance($this->extraField['instance']);
+    $child_type_field_instance = field_info_instance('node', $this->extraField['field']['field_name'], $this->childType->type);
+    $this->assertTrue($this->compareInstances($this->extraField['instance'], $child_type_field_instance), t('Child type field instance is equal to the parent one after updating.'));
+  }
+
+  public function fieldInstanceDelete() {
+    field_delete_instance($this->extraField['instance']);
+    $child_type_field_instance = field_info_instance('node', $this->extraField['field']['field_name'], $this->childType->type);
+    $this->assertTrue($child_type_field_instance['locked'] == FALSE, t('Child type field instance was succesfuly deleted when the parent type one was deleted.'));
+  }
+
+  /**
+   * Run complex CRUD test based on node entity type.
+   */
+  public function testCRUD() {
+    $this->inheritPerform();
+    $this->fieldInstanceCreate();
+    $this->fieldInstanceUpdate();
+    $this->fieldInstanceDelete();
+  }
+
+  /**
+   * Helper function to compare two instances indeferent of their 'id',
+   * 'bundle'and 'locked' fields.
+   * @param $a
+   *   First instance.
+   * @param $b
+   *   Second instance.
+   * @return
+   *   TRUE if $a and $b are equal.
+   */
+  private function compareInstances($a, $b) {
+    unset($a['id'], $a['bundle'], $a['locked']);
+    unset($b['id'], $b['bundle'], $b['locked']);
+    return $a == $b;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/bundle_inherit_node/bundle_inherit_node.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,11 @@
+name = Bundle Inheritance Node
+description = Allow to inherit one node type from other
+dependencies[] = bundle_inherit
+files[] = bundle_inherit_node.test
+core = 7.x
+; Information added by drupal.org packaging script on 2011-11-05
+version = "7.x-1.0-alpha2"
+core = "7.x"
+project = "bundle_inherit"
+datestamp = "1320523829"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/bundle_inherit_node/bundle_inherit_node.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,129 @@
+<?php
+/**
+ * @file
+ *
+ * Bundle Inherit Node module.
+ */
+
+/**
+ *
+ * Implements hook_form_alter().
+ */
+function bundle_inherit_node_form_alter(&$form, &$form_state, $form_id) {
+  $entity = entity_get_info('node');
+  if ($form_id == 'node_type_form' && count($entity['bundles']) > 0) {
+    // Attach inheritance form
+    if (empty($form['#node_type']->type)) {
+       bundle_inherit_attach_inherit_form($form, $form_state, 'node');
+    }
+    // If editing existing node type we should provide it
+    else {
+       bundle_inherit_attach_inherit_form($form, $form_state, 'node', $form['#node_type']->type);
+    }
+    if (!empty($form['bundle_inherit'])) {
+      $form['bundle_inherit']['#group'] = 'additional_settings';
+      // We should add submit callback only if we are creating new content type
+      if (empty($form['#node_type']->type)) {
+        $form['#submit'][] = 'bundle_inherit_node_form_submit';
+      }
+    }
+  }
+}
+
+/**
+ *
+ * Additional submit handler to the 'node_type_form' form. Perform inherit
+ * operations.
+ */
+function bundle_inherit_node_form_submit(&$form, &$form_state) {
+  // Check if body field instance already exists.
+  if (isset($form_state['values']['bundle_inherit']['inherit']) && $form_state['values']['bundle_inherit']['inherit']) {
+    if ($instance = field_info_instance('node', 'body', trim($form_state['values']['type']))) {
+      field_delete_instance($instance);
+    }
+    bundle_inherit_attach_inherit_form_submit(trim($form_state['values']['type']), $form, $form_state);
+    drupal_set_message(t('Node type %type was inherited from %parent_type. All fields from %parent_type type was attached to %type type.',
+                        array('%type' => $form_state['values']['name'], '%parent_type' => $form['bundle_inherit']['parent_type']['#options'][$form_state['values']['bundle_inherit']['parent_type']])));
+  }
+}
+
+/**
+ * Implements hook_menu_alter().
+ */
+function bundle_inherit_menu_alter(&$items) {
+  $items['admin/structure/types']['page callback'] = 'bundle_inherit_node_overview_types';
+}
+
+/**
+ * Redeclare content types admin page. Sort and add indention to the inherited types.
+ */
+function bundle_inherit_node_overview_types() {
+  $types = node_type_get_types();
+  $names = node_type_get_names();
+  $field_ui = module_exists('field_ui');
+  $header = array(t('Name'), array('data' => t('Operations'), 'colspan' => $field_ui ? '4' : '2'));
+  $rows = array();
+
+  // Firstly we need to iterate through node types wich has children types
+  $top_items = $child_items = array();
+  foreach ($names as $key => $name) {
+    $type = $types[$key];
+    if (node_hook($type->type, 'form')) {
+      $type_url_str = str_replace('_', '-', $type->type);
+      $row = array(theme('node_admin_overview', array('name' => $name, 'type' => $type)));
+      // Set the edit column.
+      $row[] = array('data' => l(t('edit'), 'admin/structure/types/manage/' . $type_url_str));
+
+      if ($field_ui) {
+        // Manage fields.
+        $row[] = array('data' => l(t('manage fields'), 'admin/structure/types/manage/' . $type_url_str . '/fields'));
+
+        // Display fields.
+        $row[] = array('data' => l(t('manage display'), 'admin/structure/types/manage/' . $type_url_str . '/display'));
+      }
+
+      // Set the delete column.
+      if ($type->custom) {
+        $row[] = array('data' => l(t('delete'), 'admin/structure/types/manage/' . $type_url_str . '/delete'));
+      }
+      else {
+        $row[] = array('data' => '');
+      }
+
+      $parent_type = bundle_inherit_bundle_get_parent('node', $type->type);
+      if (empty($parent_type)) {
+        $top_items[$type->type] = $row;
+      }
+      else {
+        $child_items[$parent_type][$type->type] = $row;
+      }
+    }
+  }
+
+  foreach ($top_items as $type => $row) {
+    $rows[] = $row;
+    _bundle_inherit_node_overview_types_populate_rows($child_items, $type, $rows);
+  }
+
+  $build['node_table'] = array(
+    '#theme' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+    '#empty' => t('No content types available. <a href="@link">Add content type</a>.', array('@link' => url('admin/structure/types/add'))),
+  );
+
+  return $build;
+}
+
+/**
+ * Helper function for bundle_inherit_node_overview_types().
+ */
+function _bundle_inherit_node_overview_types_populate_rows($child_items, $parent, &$rows, $level = 1) {
+  if (array_key_exists($parent, $child_items)) {
+    foreach ($child_items[$parent] as $type => $row) {
+      $row[0] = str_repeat('-&nbsp;&nbsp;-&nbsp;&nbsp;', $level) . $row[0];
+      $rows[] = $row;
+      _bundle_inherit_node_overview_types_populate_rows($child_items, $type, $rows, $level + 1);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/bundle_inherit/bundle_inherit_node/bundle_inherit_node.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+/**
+ * @file
+ * Tests for bundle_inherit_node module.
+ */
+
+class BundleInheritTestCase extends DrupalWebTestCase {
+  protected $privelegedUser;
+  protected $parentType;
+  protected $childTypeName;
+
+  public static function getInfo() {
+    return array(
+        'name' => 'Bundle Inherit Node',
+        'description' => 'Ensure that the Bundle Inherit Node module works properly',
+        'group' => 'Bundle Inherit'
+    );
+  }
+
+  public function setUp() {
+    parent::setUp(array('bundle_inherit_node', 'field_ui', 'text', 'node'));
+
+    $this->privelegedUser = $this->drupalCreateUser(array('administer content types'));
+    $this->childTypeName = drupal_strtolower($this->randomName());
+    $this->drupalLogin($this->privelegedUser);
+
+    // Add new content type.
+    $this->parentType = $this->drupalCreateContentType();
+
+    // Add 5 custom fields.
+    for ($i = 0; $i < 5; $i++) {
+      do{
+        $field_name = drupal_strtolower($this->randomName());
+      } while (field_info_field($field_name));
+      $field = field_create_field(array(
+          'field_name' => $field_name,
+          'type' => 'text'
+      ));
+      field_create_instance(array(
+          'field_name' => $field_name,
+          'entity_type' => 'node',
+          'bundle' => $this->parentType->type
+      ));
+    }
+  }
+
+  /**
+   * Create new content type. Strictly inherit it from content type created in
+   * setUp().
+   */
+  public function testInherit() {
+    $edit = array(
+      'name' => $this->childTypeName,
+      'type' => $this->childTypeName,
+      'bundle_inherit[inherit]' => TRUE,
+      'bundle_inherit[parent_type]' => $this->parentType->type,
+      'bundle_inherit[mode]' => 'strict'
+    );
+
+    $this->drupalPost('admin/structure/types/add', $edit, t('Save content type'));
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $this->childTypeName))->fetchField();
+    $this->assertTrue($type_exists, t('Type was created.'));
+    $type_inherited = db_query('SELECT 1 FROM {bundle_hierarchy} WHERE entity_type = :entity_type AND bundle = :bundle AND bundle_parent = :bundle_parent', array(':entity_type' => 'node', ':bundle' => $this->childTypeName, ':bundle_parent' => $this->parentType->type))->fetchField();
+    $this->assertTrue($type_inherited, t('Type was inherited.'));
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,156 @@
+
+Entity API module
+-----------------
+by Wolfgang Ziegler, nuppla@zites.net
+
+This module extends the entity API of Drupal core in order to provide a unified
+way to deal with entities and their properties. Additionally, it provides an
+entity CRUD controller, which helps simplifying the creation of new entity types.
+
+
+This is an API module. You only need to enable it if a module depends on it or
+you are interested in using it for development.
+
+This README is for interested developers. If you are not interested in
+developing, you may stop reading now.
+
+--------------------------------------------------------------------------------
+                                Entity API
+--------------------------------------------------------------------------------
+
+  * The module provides API functions allowing modules to create, save, delete
+    or to determine access for entities based on any entity type, for which the
+    necessary metadata is available. The module comes with integration for all
+    core entity types, as well as for entities provided via the Entity CRUD API
+    (see below). However, for any other entity type implemented by a contrib
+    module, the module integration has to be provided by the contrib module
+    itself.
+
+  * Thus the module provides API functions like entity_save(), entity_create(),
+    entity_delete(), entity_revision_delete(), entity_view() and entity_access()
+    among others.
+    entity_load(), entity_label() and entity_uri() are already provided by
+    Drupal core.
+
+ *  For more information about how to provide this metadata, have a look at the
+    API documentation, i.e. entity_metadata_hook_entity_info().
+
+--------------------------------------------------------------------------------
+               Entity CRUD API - Providing new entity types
+--------------------------------------------------------------------------------
+
+ * This API helps you when defining a new entity type. It provides an entity
+   controller, which implements full CRUD functionality for your entities.
+
+ * To make use of the CRUD functionality you may just use the API functions
+   entity_create(), entity_delete() and entity_save().
+
+   Alternatively you may specify a class to use for your entities, for which the
+   "Entity" class is provided. In particular, it is useful to extend this class
+   in order to easily customize the entity type, e.g. saving.
+
+ * The controller supports fieldable entities and revisions. There is also a
+   controller which supports implementing exportable entities.
+
+ * The Entity CRUD API helps with providing additional module integration too,
+   e.g. exportable entities are automatically integrated with the Features
+   module. These module integrations are implemented in separate controller
+   classes, which may be overridden and deactivated on their own.
+
+ * There is also an optional ui controller class, which assists with providing
+   an administrative UI for managing entities of a certain type.
+
+ * For more details check out the documentation in the drupal.org handbook
+   http://drupal.org/node/878804 as well as the API documentation, i.e.
+   entity_crud_hook_entity_info().
+
+
+ Basic steps to add a new entity type:
+---------------------------------------
+
+  * You might want to study the code of the "entity_test.module".
+
+  * Describe your entities db table as usual in hook_schema().
+
+  * Just use the "Entity" directly or extend it with your own class.
+    To see how to provide a separate class have a look at the "EntityClass" from
+    the "entity_test.module".
+
+  * Implement hook_entity_info() for your entity. At least specifiy the
+    controller class (EntityAPIController, EntityAPIControllerExportable or your
+    own), your db table and your entity's keys.
+    Again just look at "entity_test.module"'s hook_entity_info() for guidance.
+
+  * If you want your entity to be fieldable just set 'fieldable' in
+    hook_entity_info() to TRUE. The field API attachers are then called
+    automatically in the entity CRUD functions.
+
+  * The entity API is able to deal with bundle objects too (e.g. the node type
+    object). For that just specify another entity type for the bundle objects
+    and set the 'bundle of' property for it.
+    Again just look at "entity_test.module"'s hook_entity_info() for guidance.
+
+  * Schema fields marked as 'serialized' are automatically unserialized upon
+    loading as well as serialized on saving. If the 'merge' attribute is also
+    set to TRUE the unserialized data is automatically "merged" into the entity.
+
+  * Further details can be found at http://drupal.org/node/878804.
+
+
+
+--------------------------------------------------------------------------------
+                Entity Properties & Entity metadata wrappers
+--------------------------------------------------------------------------------
+
+  * This module introduces a unique place for metadata about entity properties:
+    hook_entity_property_info(), whereas hook_entity_property_info() may be
+    placed in your module's {YOUR_MODULE}.info.inc include file. For details
+    have a look at the API documentation, i.e. hook_entity_property_info() and
+    at http://drupal.org/node/878876.
+
+  * The information about entity properties contains the data type and callbacks
+    for how to get and set the data of the property. That way the data of an
+    entity can be easily re-used, e.g. to export it into other data formats like
+    XML.
+
+  * For making use of this information (metadata) the module provides some
+    wrapper classes which ease getting and setting values. The wrapper supports
+    chained usage for retrieving wrappers of entity properties, e.g. to get a
+    node author's mail address one could use:
+
+       $wrapper = entity_metadata_wrapper('node', $node);
+       $wrapper->author->mail->value();
+
+    To update the user's mail address one could use
+
+       $wrapper->author->mail->set('sepp@example.com');
+
+       or
+
+       $wrapper->author->mail = 'sepp@example.com';
+
+    The wrappers always return the data as described in the property
+    information, which may be retrieved directly via entity_get_property_info()
+    or from the wrapper:
+
+       $mail_info = $wrapper->author->mail->info();
+
+    In order to force getting a textual value sanitized for output one can use,
+    e.g.
+
+       $wrapper->title->value(array('sanitize' => TRUE));
+
+    to get the sanitized node title. When a property is already returned
+    sanitized by default, like the node body, one possibly wants to get the
+    not-sanitized data as it would appear in a browser for other use-cases.
+    To do so one can enable the 'decode' option, which ensures for any sanitized
+    data the tags are stripped and HTML entities are decoded before the property
+    is returned:
+
+       $wrapper->body->value->value(array('decode' => TRUE));
+
+    That way one always gets the data as shown to the user. However if you
+    really want to get the raw, unprocessed value, even for sanitized textual
+    data, you can do so via:
+
+      $wrapper->body->value->raw();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/ctools/content_types/entity_view.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * @file
+ * Content type plugin to expose rendered entities, view mode configuration
+ * still available.
+ */
+
+$plugin = array(
+  'title' => t('Rendered entity'),
+  'defaults' => array('view_mode' => 'full'),
+  'content type' => 'entity_entity_view_content_type_info',
+);
+
+/**
+ * Get the entity content type info.
+ */
+function entity_entity_view_content_type_info($entity_type) {
+  $types = entity_entity_view_content_type_content_types();
+  if (isset($types[$entity_type])) {
+    return $types[$entity_type];
+  }
+}
+
+/**
+ * Implements hook_PLUGIN_content_type_content_types().
+ *
+ * Rendered entity use entity types machine name as subtype name.
+ */
+function entity_entity_view_content_type_content_types() {
+  $types = array();
+  $entities = entity_get_info();
+
+  foreach ($entities as $entity_type => $info) {
+    if (entity_type_supports($entity_type, 'view')) {
+      $types[$entity_type] = array(
+        'title' => t('Rendered @entity_type', array('@entity_type' => $info['label'])),
+        'category' => t('Entity'),
+        'required context' => new ctools_context_required(t('Entity'), $entity_type),
+      );
+    }
+  }
+
+  return $types;
+}
+
+/**
+ * Returns an edit form for a entity.
+ *
+ * Rendered entity use entity types machine name as subtype name.
+ *
+ * @see entity_entity_view_get_content_types()
+ */
+function entity_entity_view_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+  $entity_type = $form_state['subtype_name'];
+  $entity_info = entity_get_info($entity_type);
+
+  $options = array();
+  if (!empty($entity_info['view modes'])) {
+    foreach ($entity_info['view modes'] as $mode => $settings) {
+      $options[$mode] = $settings['label'];
+    }
+  }
+
+  if (count($options) > 1) {
+    $form['view_mode'] = array(
+      '#type' => 'select',
+      '#options' => $options,
+      '#title' => t('View mode'),
+      '#default_value' => $conf['view_mode'],
+    );
+  }
+  else {
+    $form['view_mode_info'] = array(
+      '#type' => 'item',
+      '#title' => t('View mode'),
+      '#description' => t('Only one view mode is available for this entity type.'),
+      '#markup' => $options ? current($options) : t('Default'),
+    );
+
+    $form['view_mode'] = array(
+      '#type' => 'value',
+      '#value' => $options ? key($options) : 'default',
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Save selected view mode.
+ */
+function entity_entity_view_content_type_edit_form_submit(&$form, &$form_state) {
+  if (isset($form_state['values']['view_mode'])) {
+    $form_state['conf']['view_mode'] = $form_state['values']['view_mode'];
+  }
+}
+
+/**
+ * Implements hook_PLUGIN_content_type_render().
+ *
+ * Ctools requires us to return a block.
+ *
+ * @see ctools_content_render()
+ */
+function entity_entity_view_content_type_render($entity_type, $conf, $panel_args, $context) {
+  if ($context->empty) {
+    return;
+  }
+  $block = new stdClass();
+  $block->module = 'entity';
+  $block->delta = $entity_type . '-' . str_replace('-', '_', $conf['view_mode']);
+
+  $entity_id = $context->argument;
+  $entity = entity_load_single($entity_type, $entity_id);
+  $block->content = entity_view($entity_type, array($entity_id => $entity), $conf['view_mode']);
+  return $block;
+}
+
+/**
+ * Implements hook_PLUGIN_content_type_admin_title().
+ *
+ * Returns the administrative title for a type.
+ */
+function entity_entity_view_content_type_admin_title($entity_type, $conf, $contexts) {
+  $entity_info = entity_get_info($entity_type);
+  $view_mode = $conf['view_mode'];
+  if (isset($entity_info['view modes'][$view_mode])) {
+    $view_mode = $entity_info['view modes'][$view_mode]['label'];
+  }
+  return t('Rendered @entity_type using view mode "@view_mode"', array('@entity_type' => $entity_info['label'], '@view_mode' => $view_mode));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,466 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the entity API.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Provide an entity type via the entity CRUD API.
+ *
+ * This is a placeholder for describing further keys for hook_entity_info(),
+ * which are introduced the entity API for providing a new entity type with the
+ * entity CRUD API. For that the entity API provides two controllers:
+ *  - EntityAPIController: A regular CRUD controller.
+ *  - EntityAPIControllerExportable: Extends the regular controller to
+ *    additionally support exportable entities and/or entities making use of a
+ *    name key.
+ * See entity_metadata_hook_entity_info() for the documentation of additional
+ * keys for hook_entity_info() as introduced by the entity API and supported for
+ * any entity type.
+ *
+ * The entity CRUD API supports the following keys:
+ * - entity class: (optional) A class the controller will use for instantiating
+ *   entities. It is suggested to make use of the provided "Entity" class or to
+ *   extend it.
+ * - bundle of: (optional) Entity types can be used as bundles for
+ *   other entity types. To enable this functionality, use the 'bundle of' key
+ *   to indicate which entity type this entity serves as a bundle for. But note
+ *   that the other entity type will still need to declare entities of this
+ *   type as bundles, as described by the documentation of hook_entity_info().
+ *   If the other entity type is fieldable, the entity API controller takes
+ *   care of invoking the field API bundle attachers. Note that
+ *   field_attach_delete_bundle() has to be invoked manually upon module
+ *   uninstallation. See entity_test_entity_info() and entity_test_uninstall()
+ *   for examples.
+ * - module: (optional) The module providing the entity type. This is optional,
+ *   but strongly suggested.
+ * - exportable: (optional) Whether the entity is exportable. Defaults to FALSE.
+ *   If enabled, a name key should be specified and db columns for the module
+ *   and status key as defined by entity_exportable_schema_fields() have to
+ *   exist in the entity's base table. Also see 'entity keys' below.
+ *   This option requires the EntityAPIControllerExportable to work.
+ * - entity keys: An array of keys as defined by Drupal core. The following
+ *   additional keys are used by the entity CRUD API:
+ *   - name: (optional) The key of the entity property containing the unique,
+ *     machine readable name of the entity. If specified, this is used as
+ *     identifier of the entity, while the usual 'id' key is still required and
+ *     may be used when modules deal with entities generically, or to refer to
+ *     the entity internally, i.e. in the database.
+ *     If a name key is given, the name is used as entity identifier by the
+ *     entity API module, metadata wrappers and entity-type specific hooks.
+ *     However note that for consistency all generic entity hooks like
+ *     hook_entity_load() are invoked with the entities keyed by numeric id,
+ *     while entity-type specific hooks like hook_{entity_type}_load() are
+ *     invoked with the entities keyed by name.
+ *     Also, just as entity_load_single() entity_load() may be called
+ *     with names passed as the $ids parameter, while the results of
+ *     entity_load() are always keyed by numeric id. Thus, it is suggested to
+ *     make use of entity_load_multiple_by_name() to implement entity-type
+ *     specific loading functions like {entity_type}_load_multiple(), as this
+ *     function returns the entities keyed by name. See entity_test_get_types()
+ *     for an example.
+ *     For exportable entities, it is strongly recommended to make use of a
+ *     machine name as names are portable across systems.
+ *     This option requires the EntityAPIControllerExportable to work.
+ *   - module: (optional) A key for the module property used by the entity CRUD
+ *     API to save the source module name for exportable entities that have been
+ *     provided in code. Defaults to 'module'.
+ *   - status: (optional) The name of the entity property used by the entity
+ *     CRUD API to save the exportable entity status using defined bit flags.
+ *     Defaults to 'status'. See entity_has_status().
+ *   - default revision: (optional) The name of the entity property used by
+ *     the entity CRUD API to determine if a newly-created revision should be
+ *     set as the default revision. Defaults to 'default_revision'.
+ *     Note that on entity insert the created revision will be always default
+ *     regardless of the value of this entity property.
+ * - export: (optional) An array of information used for exporting. For ctools
+ *   exportables compatibility any export-keys supported by ctools may be added
+ *   to this array too.
+ *   - default hook: What hook to invoke to find exportable entities that are
+ *     currently defined. This hook is automatically called by the CRUD
+ *     controller during entity_load(). Defaults to 'default_' . $entity_type.
+ * - admin ui: (optional) An array of optional information used for providing an
+ *   administrative user interface. To enable the UI at least the path must be
+ *   given. Apart from that, the 'access callback' (see below) is required for
+ *   the entity, as well as the 'ENTITY_TYPE_form' for editing, adding and
+ *   cloning. The form gets the entity and the operation ('edit', 'add' or
+ *   'clone') passed. See entity_ui_get_form() for more details.
+ *   Known keys are:
+ *   - path: A path where the UI should show up as expected by hook_menu().
+ *   - controller class: (optional) A controller class name for providing the
+ *     UI. Defaults to EntityDefaultUIController, which implements an admin UI
+ *     suiting for managing configuration entities. Other provided controllers
+ *     suiting for content entities are EntityContentUIController or
+ *     EntityBundleableUIController (which work fine despite the poorly named
+ *     'admin ui' key).
+ *     For customizing the UI inherit from the default class and override
+ *     methods as suiting and specify your class as controller class.
+ *   - file: (optional) The name of the file in which the entity form resides
+ *     as it is required by hook_menu().
+ *   - file path: (optional) The path to the file as required by hook_menu. If
+ *     not set, it defaults to entity type's module's path, thus the entity
+ *     types 'module' key is required.
+ *   - menu wildcard: The wildcard to use in paths of the hook_menu() items.
+ *     Defaults to %entity_object which is the loader provided by Entity API.
+ * - rules controller class: (optional) A controller class for providing Rules
+ *   integration, or FALSE to disable this feature. The given class has to
+ *   inherit from the class EntityDefaultRulesController, which serves as
+ *   default in case the entity type is not marked as configuration. For
+ *   configuration entities it defaults to FALSE.
+ * - metadata controller class: (optional) A controller class for providing
+ *   entity property info. By default some info is generated out of the
+ *   information provided in your hook_schema() implementation, while only read
+ *   access is granted to that properties by default. Based upon that the
+ *   Entity tokens module also generates token replacements for your entity
+ *   type, once activated.
+ *   Override the controller class to adapt the defaults and to improve and
+ *   complete the generated metadata. Set it to FALSE to disable this feature.
+ *   Defaults to the EntityDefaultMetadataController class.
+ * - extra fields controller class: (optional) A controller class for providing
+ *   field API extra fields. Defaults to none.
+ *   The class must implement the EntityExtraFieldsControllerInterface. Display
+ *   extra fields that are exposed that way are rendered by default by the
+ *   EntityAPIController. The EntityDefaultExtraFieldsController class may be
+ *   used to generate extra fields based upon property metadata, which in turn
+ *   get rendered by default by the EntityAPIController.
+ * - features controller class: (optional) A controller class for providing
+ *   Features module integration for exportable entities. The given class has to
+ *   inherit from the default class being EntityDefaultFeaturesController. Set
+ *   it to FALSE to disable this feature.
+ * - i18n controller class: (optional) A controller class for providing
+ *   i18n module integration for (exportable) entities. The given class has to
+ *   inherit from the class EntityDefaultI18nStringController. Defaults to
+ *   FALSE (disabled). See EntityDefaultI18nStringController for more
+ *   information.
+ * - views controller class: (optional) A controller class for providing views
+ *   integration. The given class has to inherit from the class
+ *   EntityDefaultViewsController, which is set as default in case the providing
+ *   module has been specified (see 'module') and the module does not provide
+ *   any views integration. Else it defaults to FALSE, which disables this
+ *   feature. See EntityDefaultViewsController.
+ * - access callback: (optional) Specify a callback that returns access
+ *   permissions for the operations 'create', 'update', 'delete' and 'view'.
+ *   The callback gets optionally the entity and the user account to check for
+ *   passed. See entity_access() for more details on the arguments and
+ *   entity_metadata_no_hook_node_access() for an example.
+ *   This is optional, but suggested for the Rules integration, and required for
+ *   the admin ui (see above).
+ * - form callback: (optional) Specfiy a callback that returns a fully built
+ *   edit form for your entity type. See entity_form().
+ *   In case the 'admin ui' is used, no callback needs to be specified.
+ * - entity cache: (optional) Whether entities should be cached using the cache
+ *   system. Requires the entitycache module to be installed and enabled. As
+ *   cached entities are only retrieved by id key, the cache would not apply to
+ *   exportable entities retrieved by name key. If enabled, 'field cache' is
+ *   obsolete and should be disabled. Defaults to FALSE.
+ *
+ * @see hook_entity_info()
+ * @see entity_metadata_hook_entity_info()
+ */
+function entity_crud_hook_entity_info() {
+  $return = array(
+    'entity_test' => array(
+      'label' => t('Test Entity'),
+      'entity class' => 'Entity',
+      'controller class' => 'EntityAPIController',
+      'base table' => 'entity_test',
+      'module' => 'entity_test',
+      'fieldable' => TRUE,
+      'entity keys' => array(
+        'id' => 'pid',
+        'name' => 'name',
+        'bundle' => 'type',
+      ),
+      'bundles' => array(),
+    ),
+  );
+  foreach (entity_test_get_types() as $name => $info) {
+    $return['entity_test']['bundles'][$name] = array(
+      'label' => $info['label'],
+    );
+  }
+  return $return;
+}
+
+/**
+ * Provide additional metadata for entities.
+ *
+ * This is a placeholder for describing further keys for hook_entity_info(),
+ * which are introduced the entity API in order to support any entity type; e.g.
+ * to make entity_save(), entity_create(), entity_view() and others work.
+ * See entity_crud_hook_entity_info() for the documentation of additional keys
+ * for hook_entity_info() as introduced by the entity API for providing new
+ * entity types with the entity CRUD API.
+ *
+ * Additional keys are:
+ * - plural label: (optional) The human-readable, plural name of the entity
+ *   type. As 'label' it should start capitalized.
+ * - description: (optional) A human-readable description of the entity type.
+ * - access callback: (optional) Specify a callback that returns access
+ *   permissions for the operations 'create', 'update', 'delete' and 'view'.
+ *   The callback gets optionally the entity and the user account to check for
+ *   passed. See entity_access() for more details on the arguments and
+ *   entity_metadata_no_hook_node_access() for an example.
+ * - creation callback: (optional) A callback that creates a new instance of
+ *   this entity type. See entity_metadata_create_node() for an example.
+ * - save callback: (optional) A callback that permanently saves an entity of
+ *   this type.
+ * - deletion callback: (optional) A callback that permanently deletes an
+ *   entity of this type.
+ * - revision deletion callback: (optional) A callback that deletes a revision
+ *   of the entity.
+ * - view callback: (optional) A callback to render a list of entities.
+ *   See entity_metadata_view_node() as example.
+ * - form callback: (optional) A callback that returns a fully built edit form
+ *   for the entity type.
+ * - token type: (optional) A type name to use for token replacements. Set it
+ *   to FALSE if there aren't any token replacements for this entity type.
+ * - configuration: (optional) A boolean value that specifies whether the entity
+ *   type should be considered as configuration. Modules working with entities
+ *   may use this value to decide whether they should deal with a certain entity
+ *   type. Defaults to TRUE to for entity types that are exportable, else to
+ *   FALSE.
+ *
+ * @see hook_entity_info()
+ * @see entity_crud_hook_entity_info()
+ * @see entity_access()
+ * @see entity_create()
+ * @see entity_save()
+ * @see entity_delete()
+ * @see entity_view()
+ * @see entity_form()
+ */
+function entity_metadata_hook_entity_info() {
+  return array(
+    'node' => array(
+      'label' => t('Node'),
+      'access callback' => 'entity_metadata_no_hook_node_access',
+      // ...
+    ),
+  );
+}
+
+/**
+ * Allow modules to define metadata about entity properties.
+ *
+ * Modules providing properties for any entities defined in hook_entity_info()
+ * can implement this hook to provide metadata about this properties.
+ * For making use of the metadata have a look at the provided wrappers returned
+ * by entity_metadata_wrapper().
+ * For providing property information for fields see entity_hook_field_info().
+ *
+ * @return
+ *   An array whose keys are entity type names and whose values are arrays
+ *   containing the keys:
+ *   - properties: The array describing all properties for this entity. Entries
+ *     are keyed by the property name and contain an array of metadata for each
+ *     property. The name may only contain alphanumeric lowercase characters
+ *     and underscores. Known keys are:
+ *     - label: A human readable, translated label for the property.
+ *     - description: (optional) A human readable, translated description for
+ *       the property.
+ *     - type: The data type of the property. To make the property actually
+ *       useful it is important to map your properties to one of the known data
+ *       types, which currently are:
+ *        - text: Any text.
+ *        - token: A string containing only lowercase letters, numbers, and
+ *          underscores starting with a letter; e.g. this type is useful for
+ *          machine readable names.
+ *        - integer: A usual PHP integer value.
+ *        - decimal: A PHP float or integer.
+ *        - date: A full date and time, as timestamp.
+ *        - duration: A duration as number of seconds.
+ *        - boolean: A usual PHP boolean value.
+ *        - uri: An absolute URI or URL.
+ *        - entities - You may use the type of each entity known by
+ *          hook_entity_info(), e.g. 'node' or 'user'. Internally entities are
+ *          represented by their identifieres. In case of single-valued
+ *          properties getter callbacks may return full entity objects as well,
+ *          while a value of FALSE is interpreted like a NULL value as "property
+ *          is not set".
+ *        - entity: A special type to be used generically for entities where the
+ *          entity type is not known beforehand. The entity has to be
+ *          represented using an EntityMetadataWrapper.
+ *        - struct: This as well as any else not known type may be used for
+ *          supporting arbitrary data structures. For that additional metadata
+ *          has to be specified with the 'property info' key. New type names
+ *          have to be properly prefixed with the module name.
+ *        - list: A list of values, represented as numerically indexed array.
+ *          The list<TYPE> notation may be used to specify the type of the
+ *          contained items, where TYPE may be any valid type expression.
+ *     - bundle: (optional) If the property is an entity, you may specify the
+ *       bundle of the referenced entity.
+ *     - options list: (optional) A callback that returns a list of possible
+ *       values for the property. The callback has to return an array as
+ *       used by hook_options_list().
+ *       Note that it is possible to return a different set of options depending
+ *       whether they are used in read or in write context. See
+ *       EntityMetadataWrapper::optionsList() for more details on that.
+ *     - getter callback: (optional) A callback used to retrieve the value of
+ *       the property. Defaults to entity_property_verbatim_get().
+ *       It is important that your data is represented, as documented for your
+ *       data type, e.g. a date has to be a timestamp. Thus if necessary, the
+ *       getter callback has to do the necessary conversion. In case of an empty
+ *       or not set value, the callback has to return NULL.
+ *     - setter callback: (optional) A callback used to set the value of the
+ *       property. In many cases entity_property_verbatim_set() can be used.
+ *     - validation callback: (optional) A callback that returns whether the
+ *       passed data value is valid for the property. May be used to implement
+ *       additional validation checks, such as to ensure the value is a valid
+ *       mail address.
+ *     - access callback: (optional) An access callback to allow for checking
+ *       'view' and 'edit' access for the described property. If no callback
+ *       is specified, a 'setter permission' may be specified instead.
+ *     - setter permission: (optional) A permission that describes whether
+ *       a user has permission to set ('edit') this property. This permission
+ *       is only be taken into account, if no 'access callback' is given.
+ *     - schema field: (optional) In case the property is directly based upon
+ *       a field specified in the entity's hook_schema(), the name of the field.
+ *     - queryable: (optional) Whether a property is queryable with
+ *       EntityFieldQuery. Defaults to TRUE if a 'schema field' is specified, or
+ *       if the deprecated 'query callback' is set to
+ *       'entity_metadata_field_query'. Otherwise it defaults to FALSE.
+ *     - query callback: (deprecated) A callback for querying for entities
+ *       having the given property value. See entity_property_query().
+ *       Generally, properties should be queryable via EntityFieldQuery. If
+ *       that is the case, just set 'queryable' to TRUE.
+ *     - required: (optional) Whether this property is required for the creation
+ *       of a new instance of its entity. See
+ *       entity_property_values_create_entity().
+ *     - field: (optional) A boolean indicating whether a property is stemming
+ *       from a field.
+ *     - computed: (optional) A boolean indicating whether a property is
+ *       computed, i.e. the property value is not stored or loaded by the
+ *       entity's controller but determined on the fly by the getter callback.
+ *       Defaults to FALSE.
+ *     - entity views field: (optional) If enabled, the property is
+ *       automatically exposed as views field available to all views query
+ *       backends listing this entity-type. As the property value will always be
+ *       generated from a loaded entity object, this is particularly useful for
+ *       'computed' properties. Defaults to FALSE.
+ *     - sanitized: (optional) For textual properties only, whether the text is
+ *       already sanitized. In this case you might want to also specify a raw
+ *       getter callback. Defaults to FALSE.
+ *     - sanitize: (optional) For textual properties, that are not sanitized
+ *       yet, specify a function for sanitizing the value. Defaults to
+ *       check_plain().
+ *     - raw getter callback: (optional) For sanitized textual properties, a
+ *       separate callback which can be used to retrieve the raw, unprocessed
+ *       value.
+ *     - clear: (optional) An array of property names, of which the cache should
+ *       be cleared too once this property is updated. As a rule of thumb any
+ *       duplicated properties should be avoided though.
+ *     - property info: (optional) An array of info for an arbitrary data
+ *       structure together with any else not defined type, see data type
+ *       'struct'. Specify metadata in the same way as defined for this hook.
+ *     - property info alter: (optional) A callback for altering the property
+ *       info before it is used by the metadata wrappers.
+ *     - property defaults: (optional) An array of property info defaults for
+ *       each property derived of the wrapped data item (e.g. an entity).
+ *       Applied by the metadata wrappers.
+ *     - auto creation: (optional) Properties of type 'struct' may specify
+ *       this callback which is used to automatically create the data structure
+ *       (e.g. an array) if necessary. This is necessary in order to support
+ *       setting a property of a not yet initialized data structure.
+ *       See entity_metadata_field_file_callback() for an example.
+ *     - translatable: (optional) Whether the property is translatable, defaults
+ *       to FALSE.
+ *     - entity token: (optional) If Entity tokens module is enabled, the
+ *       module provides a token for the property if one does not exist yet.
+ *       Specify FALSE to disable this functionality for the property.
+ *   - bundles: An array keyed by bundle name containing further metadata
+ *     related to the bundles only. This array may contain the key 'properties'
+ *     with an array of info about the bundle specific properties, structured in
+ *     the same way as the entity properties array.
+ *
+ *  @see hook_entity_property_info_alter()
+ *  @see entity_get_property_info()
+ *  @see entity_metadata_wrapper()
+ */
+function hook_entity_property_info() {
+  $info = array();
+  $properties = &$info['node']['properties'];
+
+  $properties['nid'] = array(
+    'label' => t("Content ID"),
+    'type' => 'integer',
+    'description' => t("The unique content ID."),
+  );
+  return $info;
+}
+
+/**
+ * Allow modules to alter metadata about entity properties.
+ *
+ * @see hook_entity_property_info()
+ */
+function hook_entity_property_info_alter(&$info) {
+  $properties = &$info['node']['bundles']['poll']['properties'];
+
+  $properties['poll-votes'] = array(
+    'label' => t("Poll votes"),
+    'description' => t("The number of votes that have been cast on a poll node."),
+    'type' => 'integer',
+    'getter callback' => 'entity_property_poll_node_get_properties',
+  );
+}
+
+/**
+ * Provide entity property information for fields.
+ *
+ * This is a placeholder for describing further keys for hook_field_info(),
+ * which are introduced by the entity API.
+ *
+ * For providing entity property info for fields each field type may specify a
+ * property type to map to using the key 'property_type'. With that info in
+ * place useful defaults are generated, which suffice for a lot of field
+ * types.
+ * However it is possible to specify further callbacks that may alter the
+ * generated property info. To do so use the key 'property_callbacks' and set
+ * it to an array of function names. Apart from that any property info provided
+ * for a field instance using the key 'property info' is added in too.
+ *
+ * @see entity_field_info_alter()
+ * @see entity_metadata_field_text_property_callback()
+ */
+function entity_hook_field_info() {
+  return array(
+    'text' => array(
+      'label' => t('Text'),
+      'property_type' => 'text',
+      // ...
+    ),
+  );
+}
+
+/**
+ * Alter the handlers used by the data selection tables provided by this module.
+ *
+ * @param array $field_handlers
+ *   An array of the field handler classes to use for specific types. The keys
+ *   are the types, mapped to their respective classes. Contained types are:
+ *   - All primitive types known by the entity API (see
+ *     hook_entity_property_info()).
+ *   - options: Special type for fields having an options list.
+ *   - field: Special type for Field API fields.
+ *   - entity: Special type for entity-valued fields.
+ *   - relationship: Views relationship handler to use for relationships.
+ *   Values for all specific entity types can be additionally added.
+ *
+ * @see entity_views_field_definition()
+ * @see entity_views_get_field_handlers()
+ */
+function hook_entity_views_field_handlers_alter(array &$field_handlers) {
+  $field_handlers['duration'] = 'example_duration_handler';
+  $field_handlers['node'] = 'example_node_handler';
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,174 @@
+<?php
+
+/**
+ * @file
+ * Provides Features integration for entity types using the CRUD API.
+ */
+
+/**
+ * Returns the configured entity features controller.
+ */
+function entity_features_get_controller($type) {
+  $static = &drupal_static(__FUNCTION__);
+  if (!isset($static[$type])) {
+    $info = entity_get_info($type);
+    $info += array('features controller class' => 'EntityDefaultFeaturesController');
+    $static[$type] = $info['features controller class'] ? new $info['features controller class']($type) : FALSE;
+  }
+  return $static[$type];
+}
+
+/**
+ * Default controller handling features integration.
+ */
+class EntityDefaultFeaturesController {
+
+  protected $type, $info;
+
+  public function __construct($type) {
+    $this->type = $type;
+    $this->info = entity_get_info($type);
+    $this->info['entity keys'] += array('module' => 'module', 'status' => 'status');
+    $this->statusKey = $this->info['entity keys']['status'];
+    $this->moduleKey = $this->info['entity keys']['module'];
+    if (!empty($this->info['bundle of'])) {
+      $entity_info = entity_get_info($this->info['bundle of']);
+      $this->bundleKey = $entity_info['bundle keys']['bundle'];
+    }
+  }
+
+  /**
+   * Defines the result for hook_features_api().
+   */
+  public function api() {
+    return array(
+      // The entity type has to be the features component name.
+      $this->type => array(
+        'name' => $this->info['label'],
+        'feature_source' => TRUE,
+        'default_hook' => isset($this->info['export']['default hook']) ? $this->info['export']['default hook'] : 'default_' . $this->type,
+        // Use the provided component callbacks making use of the controller.
+        'base' => 'entity',
+        'file' => drupal_get_path('module', 'entity') . '/entity.features.inc',
+      ),
+    );
+  }
+
+  /**
+   * Generates the result for hook_features_export_options().
+   */
+  public function export_options() {
+    $options = array();
+    foreach (entity_load_multiple_by_name($this->type, FALSE) as $name => $entity) {
+      $options[$name] = entity_label($this->type, $entity);
+    }
+    return $options;
+  }
+
+  /**
+   * Generates the result for hook_features_export().
+   */
+  public function export($data, &$export, $module_name = '') {
+    $pipe = array();
+    foreach (entity_load_multiple_by_name($this->type, $data) as $name => $entity) {
+      // If this entity is provided by a different module, add it as dependency.
+      if (($entity->{$this->statusKey} & ENTITY_IN_CODE) && $entity->{$this->moduleKey} != $module_name) {
+        $module = $entity->{$this->moduleKey};
+        $export['dependencies'][$module] = $module;
+      }
+      // Otherwise export the entity.
+      else {
+        $export['features'][$this->type][$name] = $name;
+
+        // If this is a bundle of a fieldable entity, add its fields to the pipe.
+        if (!empty($this->info['bundle of'])) {
+          $fields = field_info_instances($this->info['bundle of'], $entity->{$this->bundleKey});
+          foreach ($fields as $name => $field) {
+            $pipe['field'][] = "{$field['entity_type']}-{$field['bundle']}-{$field['field_name']}";
+          }
+        }
+      }
+    }
+    // Add the module providing the entity type as dependency.
+    if ($data && !empty($this->info['module'])) {
+      $export['dependencies'][$this->info['module']] = $this->info['module'];
+      // In case entity is not already an indirect dependency, add it.
+      // We can do so without causing redundant dependencies because,
+      // if entity is an indirect dependency, Features will filter it out.
+      $export['dependencies']['entity'] = 'entity';
+    }
+    return $pipe;
+  }
+
+  /**
+   * Generates the result for hook_features_export_render().
+   */
+  function export_render($module, $data, $export = NULL) {
+    $output = array();
+    $output[] = '  $items = array();';
+    foreach (entity_load_multiple_by_name($this->type, $data) as $name => $entity) {
+      $export  = "  \$items['$name'] = entity_import('{$this->type}', '";
+      // Make sure to escape the characters \ and '.
+      $export .= addcslashes(entity_export($this->type, $entity, '  '), '\\\'');
+      $export .= "');";
+      $output[] = $export;
+    }
+    $output[] = '  return $items;';
+    $output = implode("\n", $output);
+
+    $hook = isset($this->info['export']['default hook']) ? $this->info['export']['default hook'] : 'default_' . $this->type;
+    return array($hook => $output);
+  }
+
+  /**
+   * Generates the result for hook_features_revert().
+   */
+  function revert($module = NULL) {
+    if ($defaults = features_get_default($this->type, $module)) {
+      foreach ($defaults as $name => $entity) {
+        entity_delete($this->type, $name);
+      }
+    }
+  }
+}
+
+/**
+ * Implements of hook_features_api().
+ */
+function entity_features_api() {
+  $items = array();
+  foreach (entity_crud_get_info() as $type => $info) {
+    if (!empty($info['exportable']) && $controller = entity_features_get_controller($type)) {
+      $items += $controller->api();
+    }
+  }
+  return $items;
+}
+
+/**
+ * Features component callback.
+ */
+function entity_features_export_options($entity_type) {
+  return entity_features_get_controller($entity_type)->export_options();
+}
+
+/**
+ * Features component callback.
+ */
+function entity_features_export($data, &$export, $module_name = '', $entity_type) {
+  return entity_features_get_controller($entity_type)->export($data, $export, $module_name);
+}
+
+/**
+ * Features component callback.
+ */
+function entity_features_export_render($module, $data, $export = NULL, $entity_type) {
+  return entity_features_get_controller($entity_type)->export_render($module, $data, $export);
+}
+
+/**
+ * Features component callback.
+ */
+function entity_features_revert($module = NULL, $entity_type) {
+  return entity_features_get_controller($entity_type)->revert($module);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.i18n.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,210 @@
+<?php
+/**
+ * @file
+ * Internationalization (i18n) integration.
+ */
+
+/**
+ * Gets the i18n controller for a given entity type.
+ *
+ * @return EntityDefaultI18nStringController|array|false
+ *   If a type is given, the controller for the given entity type. Else an array
+ *   of all enabled controllers keyed by entity type is returned.
+ */
+function entity_i18n_controller($type = NULL) {
+  $static = &drupal_static(__FUNCTION__);
+
+  if (!isset($type)) {
+    // Invoke the function for each type to ensure we have fully populated the
+    // static variable.
+    foreach (entity_get_info() as $entity_type => $info) {
+      entity_i18n_controller($entity_type);
+    }
+    return array_filter($static);
+  }
+
+  if (!isset($static[$type])) {
+    $info = entity_get_info($type);
+    // Do not activate it by default. Modules have to explicitly enable it by
+    // specifying EntityDefaultI18nStringController or their customization.
+    $class = isset($info['i18n controller class']) ? $info['i18n controller class'] : FALSE;
+    $static[$type] = $class ? new $class($type, $info) : FALSE;
+  }
+
+  return $static[$type];
+}
+
+/**
+ * Implements hook_i18n_string_info().
+ */
+function entity_i18n_string_info() {
+  $groups = array();
+  foreach (entity_i18n_controller() as $entity_type => $controller) {
+    $groups += $controller->hook_string_info();
+  }
+  return $groups;
+}
+
+/**
+ * Implements hook_i18n_object_info().
+ */
+function entity_i18n_object_info() {
+  $info = array();
+  foreach (entity_i18n_controller() as $entity_type => $controller) {
+    $info += $controller->hook_object_info();
+  }
+  return $info;
+}
+
+/**
+ * Implements hook_i18n_string_objects().
+ */
+function entity_i18n_string_objects($type) {
+  if ($controller = entity_i18n_controller($type)) {
+    return $controller->hook_string_objects();
+  }
+}
+
+/**
+ * Default controller handling i18n integration.
+ *
+ * Implements i18n string translation for all non-field properties marked as
+ * 'translatable' and having the flag 'i18n string' set. This translation
+ * approach fits in particular for translating configuration, i.e. exportable
+ * entities.
+ *
+ * Requirements for the default controller:
+ *  - The entity type providing module must be specified using the 'module' key
+ *    in hook_entity_info().
+ *  - An 'entity class' derived from the provided class 'Entity' must be used.
+ *  - Properties must be declared as 'translatable' and the 'i18n string' flag
+ *    must be set to TRUE using hook_entity_property_info().
+ *  - i18n must be notified about changes manually by calling
+ *    i18n_string_object_update(), i18n_string_object_remove() and
+ *    i18n_string_update_context(). Ideally, this is done in a small integration
+ *    module depending on the entity API and i18n_string. Look at the provided
+ *    testing module "entity_test_i18n" for an example.
+ *  - If the entity API admin UI is used, the "translate" tab will be
+ *    automatically enabled and linked from the UI.
+ *  - There are helpers for getting translated values which work regardless
+ *    whether the i18n_string module is enabled, i.e. entity_i18n_string()
+ *    and Entity::getTranslation().
+ *
+ *  Current limitations:
+ *   - Translatable property values cannot be updated via the metadata wrapper,
+ *     however reading works fine. See Entity::getTranslation().
+ */
+class EntityDefaultI18nStringController {
+
+  protected $entityType, $entityInfo;
+
+  /**
+   * The i18n textgroup we are using.
+   */
+  protected $textgroup;
+
+  public function __construct($type) {
+    $this->entityType = $type;
+    $this->entityInfo = entity_get_info($type);
+    // By default we go with the module name as textgroup.
+    $this->textgroup = $this->entityInfo['module'];
+  }
+
+  /**
+   * Implements hook_i18n_string_info() via entity_i18n_string_info().
+   */
+  public function hook_string_info() {
+    $list = system_list('module_enabled');
+    $info = $list[$this->textgroup]->info;
+
+    $groups[$this->textgroup] = array(
+      'title' => $info['name'],
+      'description' => !empty($info['description']) ? $info['description'] : NULL,
+      'format' => FALSE,
+      'list' => TRUE,
+    );
+    return $groups;
+  }
+
+  /**
+   * Implements hook_i18n_object_info() via entity_i18n_object_info().
+   *
+   * Go with the same default values as the admin UI as far as possible.
+   */
+  public function hook_object_info() {
+    $wildcard = $this->menuWildcard();
+    $id_key = !empty($this->entityInfo['entity keys']['name']) ? $this->entityInfo['entity keys']['name'] : $this->entityInfo['entity keys']['id'];
+
+    $info[$this->entityType] = array(
+      // Generic object title.
+      'title' => $this->entityInfo['label'],
+      // The object key field.
+      'key' => $id_key,
+      // Placeholders for automatic paths.
+      'placeholders' => array(
+        $wildcard => $id_key,
+      ),
+
+      // Properties for string translation.
+      'string translation' => array(
+        // Text group that will handle this object's strings.
+        'textgroup' => $this->textgroup,
+        // Object type property for string translation.
+        'type' => $this->entityType,
+        // Translatable properties of these objects.
+        'properties' => $this->translatableProperties(),
+      ),
+    );
+
+    // Integrate the translate tab into the admin-UI if enabled.
+    if ($base_path = $this->menuBasePath()) {
+      $info[$this->entityType] += array(
+        // To produce edit links automatically.
+        'edit path' => $base_path . '/manage/' . $wildcard,
+        // Auto-generate translate tab.
+        'translate tab' => $base_path . '/manage/' . $wildcard . '/translate',
+      );
+      $info[$this->entityType]['string translation'] += array(
+        // Path to translate strings to every language.
+        'translate path' => $base_path . '/manage/' . $wildcard . '/translate/%i18n_language',
+      );
+    }
+    return $info;
+  }
+
+  /**
+   * Defines the menu base path used by self::hook_object_info().
+   */
+  protected function menuBasePath() {
+    return !empty($this->entityInfo['admin ui']['path']) ? $this->entityInfo['admin ui']['path'] : FALSE;
+  }
+
+  /**
+   * Defines the menu wildcard used by self::hook_object_info().
+   */
+  protected function menuWildcard() {
+    return isset($this->entityInfo['admin ui']['menu wildcard']) ? $this->entityInfo['admin ui']['menu wildcard'] : '%entity_object';
+  }
+
+  /**
+   * Defines translatable properties used by self::hook_object_info().
+   */
+  protected function translatableProperties() {
+    $list = array();
+    foreach (entity_get_all_property_info($this->entityType) as $name => $info) {
+      if (!empty($info['translatable']) && !empty($info['i18n string'])) {
+        $list[$name] = array(
+          'title' => $info['label'],
+        );
+      }
+    }
+    return $list;
+  }
+
+  /**
+   * Implements hook_i18n_string_objects() via entity_i18n_string_objects().
+   */
+  public function hook_string_objects() {
+    return entity_load_multiple_by_name($this->entityType, FALSE);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,33 @@
+name = Entity API
+description = Enables modules to work with any entity type and to provide entities.
+core = 7.x
+files[] = entity.features.inc
+files[] = entity.i18n.inc
+files[] = entity.info.inc
+files[] = entity.rules.inc
+files[] = entity.test
+files[] = includes/entity.inc
+files[] = includes/entity.controller.inc
+files[] = includes/entity.ui.inc
+files[] = includes/entity.wrapper.inc
+files[] = views/entity.views.inc
+files[] = views/handlers/entity_views_field_handler_helper.inc
+files[] = views/handlers/entity_views_handler_area_entity.inc
+files[] = views/handlers/entity_views_handler_field_boolean.inc
+files[] = views/handlers/entity_views_handler_field_date.inc
+files[] = views/handlers/entity_views_handler_field_duration.inc
+files[] = views/handlers/entity_views_handler_field_entity.inc
+files[] = views/handlers/entity_views_handler_field_field.inc
+files[] = views/handlers/entity_views_handler_field_numeric.inc
+files[] = views/handlers/entity_views_handler_field_options.inc
+files[] = views/handlers/entity_views_handler_field_text.inc
+files[] = views/handlers/entity_views_handler_field_uri.inc
+files[] = views/handlers/entity_views_handler_relationship_by_bundle.inc
+files[] = views/handlers/entity_views_handler_relationship.inc
+files[] = views/plugins/entity_views_plugin_row_entity_view.inc
+; Information added by drupal.org packaging script on 2013-08-14
+version = "7.x-1.2"
+core = "7.x"
+project = "entity"
+datestamp = "1376493705"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,262 @@
+<?php
+
+/**
+ * @file
+ * Provides basic entity property info for entities provided via the CRUD API,
+ * as well as property info for all entity types defined by core. For that
+ * the respective modules/MODULE.info.inc files are included.
+ */
+
+/**
+ * Implements hook_entity_property_info().
+ */
+function entity_entity_property_info() {
+  $items = array();
+  // Add in info about entities provided by the CRUD API.
+  foreach (entity_crud_get_info() as $type => $info) {
+    // Automatically enable the controller only if the module does not implement
+    // the hook itself.
+    if (!isset($info['metadata controller class']) && !empty($info['base table']) && (!isset($info['module']) || !module_hook($info['module'], 'entity_property_info'))) {
+      $info['metadata controller class'] = 'EntityDefaultMetadataController';
+    }
+    if (!empty($info['metadata controller class'])) {
+      $controller = new $info['metadata controller class']($type);
+      $items += $controller->entityPropertyInfo();
+    }
+  }
+  // Add in info for all core entities.
+  foreach (_entity_metadata_core_modules() as $module) {
+    module_load_include('inc', 'entity', "modules/$module.info");
+    if (function_exists($function = "entity_metadata_{$module}_entity_property_info")) {
+      if ($return = $function()) {
+        $items = array_merge_recursive($items, $return);
+      }
+    }
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_entity_property_info_alter().
+ */
+function entity_entity_property_info_alter(&$entity_info) {
+  // Add in info for all core entities.
+  foreach (_entity_metadata_core_modules() as $module) {
+    module_load_include('inc', 'entity', "modules/$module.info");
+    if (function_exists($function = "entity_metadata_{$module}_entity_property_info_alter")) {
+      $function($entity_info);
+    }
+  }
+}
+
+function _entity_metadata_core_modules() {
+  return array_filter(array('book', 'comment', 'field', 'locale', 'node', 'taxonomy', 'user', 'system', 'statistics'), 'module_exists');
+}
+
+/**
+ * Default controller for generating some basic metadata for CRUD entity types.
+ */
+class EntityDefaultMetadataController {
+
+  protected $type, $info;
+
+  public function __construct($type) {
+    $this->type = $type;
+    $this->info = entity_get_info($type);
+  }
+
+  public function entityPropertyInfo() {
+    $entity_label = drupal_strtolower($this->info['label']);
+
+    // Provide defaults based on the schema.
+    $info['properties'] = $this->convertSchema();
+    foreach ($info['properties'] as $name => &$property) {
+      // Add a description.
+      $property['description'] = t('@entity "@property" property.', array('@entity' => drupal_ucfirst($entity_label), '@property' => $name));
+    }
+
+    // Set better metadata for known entity keys.
+    $id_key = $this->info['entity keys']['id'];
+
+    if (!empty($this->info['entity keys']['name']) && $key = $this->info['entity keys']['name']) {
+      $info['properties'][$key]['type'] = 'token';
+      $info['properties'][$key]['label'] = t('Machine-readable name');
+      $info['properties'][$key]['description'] = t('The machine-readable name identifying this @entity.', array('@entity' => $entity_label));
+      $info['properties'][$id_key]['label'] = t('Internal, numeric @entity ID', array('@entity' => $entity_label));
+      $info['properties'][$id_key]['description'] = t('The ID used to identify this @entity internally.', array('@entity' => $entity_label));
+    }
+    else {
+      $info['properties'][$id_key]['label'] = t('@entity ID', array('@entity' => drupal_ucfirst($entity_label)));
+      $info['properties'][$id_key]['description'] = t('The unique ID of the @entity.', array('@entity' => $entity_label));
+    }
+    // Care for the bundle.
+    if (!empty($this->info['entity keys']['bundle']) && $key = $this->info['entity keys']['bundle']) {
+      $info['properties'][$key]['type'] = 'token';
+      $info['properties'][$key]['options list'] = array(get_class($this), 'bundleOptionsList');
+    }
+    // Care for the label.
+    if (!empty($this->info['entity keys']['label']) && $key = $this->info['entity keys']['label']) {
+      $info['properties'][$key]['label'] = t('Label');
+      $info['properties'][$key]['description'] = t('The human readable label.');
+    }
+
+    // Add a computed property for the entity URL and expose it to views.
+    if (empty($info['properties']['url']) && !empty($this->info['uri callback'])) {
+      $info['properties']['url'] = array(
+        'label' => t('URL'),
+        'description' => t('The URL of the entity.'),
+        'getter callback' => 'entity_metadata_entity_get_properties',
+        'type' => 'uri',
+        'computed' => TRUE,
+        'entity views field' => TRUE,
+      );
+    }
+
+    return array($this->type => $info);
+  }
+
+  /**
+   * A options list callback returning all bundles for an entity type.
+   */
+  public static function bundleOptionsList($name, $info) {
+    if (!empty($info['parent']) && $type = $info['parent']) {
+      $entity_info = $info['parent']->entityInfo();
+      $options = array();
+      foreach ($entity_info['bundles'] as $name => $bundle_info) {
+        $options[$name] = $bundle_info['label'];
+      }
+      return $options;
+    }
+  }
+
+  /**
+   * Return a set of properties for an entity based on the schema definition
+   */
+  protected function convertSchema() {
+    return entity_metadata_convert_schema($this->info['base table']);
+  }
+}
+
+/**
+ * Converts the schema information available for the given table to property info.
+ *
+ * @param $table
+ *   The name of the table as used in hook_schema().
+ * @return
+ *   An array of property info as suiting for hook_entity_property_info().
+ */
+function entity_metadata_convert_schema($table) {
+  $schema = drupal_get_schema($table);
+  $properties = array();
+  foreach ($schema['fields'] as $name => $info) {
+    if ($type = _entity_metadata_convert_schema_type($info['type'])) {
+      $properties[$name] = array(
+        'type' => $type,
+        'label' => drupal_ucfirst($name),
+        'schema field' => $name,
+        // As we cannot know about any setter access, leave out the setter
+        // callback. For getting usually no further access callback is needed.
+      );
+      if ($info['type'] == 'serial') {
+        $properties[$name]['validation callback'] = 'entity_metadata_validate_integer_positive';
+      }
+    }
+  }
+  return $properties;
+}
+
+function _entity_metadata_convert_schema_type($type) {
+  switch ($type) {
+    case 'int':
+    case 'serial':
+      return 'integer';
+    case 'float':
+    case 'numeric':
+      return 'decimal';
+    case 'char':
+    case 'varchar':
+    case 'text':
+      return 'text';
+  }
+}
+
+/**
+ * Interface for extra fields controller.
+ *
+ * Note: Displays extra fields exposed by this controller are rendered by
+ * default by the EntityAPIController.
+ */
+interface EntityExtraFieldsControllerInterface {
+
+  /**
+   * Returns extra fields for this entity type.
+   *
+   * @see hook_field_extra_fields().
+   */
+  public function fieldExtraFields();
+}
+
+/**
+ * Default controller for generating extra fields based on property metadata.
+ *
+ * By default a display extra field for each property not being a field, ID or
+ * bundle is generated.
+ */
+class EntityDefaultExtraFieldsController implements EntityExtraFieldsControllerInterface {
+
+  /**
+   * @var string
+   */
+  protected $entityType;
+
+  /**
+   * @var array
+   */
+  protected $entityInfo;
+
+  /**
+   * Constructor.
+   */
+  public function __construct($type) {
+    $this->entityType = $type;
+    $this->entityInfo = entity_get_info($type);
+    $this->propertyInfo = entity_get_property_info($type);
+  }
+
+  /**
+   * Implements EntityExtraFieldsControllerInterface::fieldExtraFields().
+   */
+  public function fieldExtraFields() {
+    $extra = array();
+    foreach ($this->propertyInfo['properties'] as $name => $property_info) {
+      // Skip adding the ID or bundle.
+      if ($this->entityInfo['entity keys']['id'] == $name || $this->entityInfo['entity keys']['bundle'] == $name) {
+        continue;
+      }
+      $extra[$this->entityType][$this->entityType]['display'][$name] = $this->generateExtraFieldInfo($name, $property_info);
+    }
+
+    // Handle bundle properties.
+    $this->propertyInfo += array('bundles' => array());
+    foreach ($this->propertyInfo['bundles'] as $bundle_name => $info) {
+      foreach ($info['properties'] as $name => $property_info) {
+        $extra[$this->entityType][$bundle_name]['display'][$name] = $this->generateExtraFieldInfo($name, $property_info);
+      }
+    }
+    return $extra;
+  }
+
+  /**
+   * Generates the display field info for a given property.
+   */
+  protected function generateExtraFieldInfo($name, $property_info) {
+    $info = array(
+      'label' => $property_info['label'],
+      'weight' => 0,
+    );
+    if (!empty($property_info['description'])) {
+      $info['description'] = $property_info['description'];
+    }
+    return $info;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Install file for the entity API.
+ */
+
+/**
+ * The entity API modules have been merged into a single module.
+ */
+function entity_update_7000() {
+  // This empty update is required such that all caches are cleared as
+  // necessary.
+}
+
+/**
+ * Remove the deprecated 'entity_defaults_built' variable.
+ */
+function entity_update_7001() {
+  variable_del('entity_defaults_built');
+}
+
+/**
+ * Clear caches and rebuild registry.
+ */
+function entity_update_7002() {
+  // Do nothing, update.php clears cache for us in case there is an update.
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1443 @@
+<?php
+
+/**
+ * @file
+ * Module file for the entity API.
+ */
+
+module_load_include('inc', 'entity', 'modules/callbacks');
+module_load_include('inc', 'entity', 'includes/entity.property');
+
+
+/**
+ * Defines status codes used for exportable entities.
+ */
+
+/**
+ * A bit flag used to let us know if an entity is in the database.
+ */
+
+
+/**
+ * A bit flag used to let us know if an entity has been customly defined.
+ */
+define('ENTITY_CUSTOM', 0x01);
+
+/**
+ * Deprecated, but still here for backward compatibility.
+ */
+define('ENTITY_IN_DB', 0x01);
+
+/**
+ * A bit flag used to let us know if an entity is a 'default' in code.
+ */
+define('ENTITY_IN_CODE', 0x02);
+
+/**
+ * A bit flag used to mark entities as overridden, e.g. they were originally
+ * definded in code and are saved now in the database. Same as
+ * (ENTITY_CUSTOM | ENTITY_IN_CODE).
+ */
+define('ENTITY_OVERRIDDEN', 0x03);
+
+/**
+ * A bit flag used to mark entities as fixed, thus not changeable for any
+ * user.
+ */
+define('ENTITY_FIXED', 0x04 | 0x02);
+
+
+
+/**
+ * Determines whether for the given entity type a given operation is available.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $op
+ *   One of 'create', 'view', 'save', 'delete', 'revision delete', 'access' or
+ *   'form'.
+ *
+ * @return boolean
+ *   Whether the entity type supports the given operation.
+ */
+function entity_type_supports($entity_type, $op) {
+  $info = entity_get_info($entity_type);
+  $keys = array(
+    'view' => 'view callback',
+    'create' => 'creation callback',
+    'delete' => 'deletion callback',
+    'revision delete' => 'revision deletion callback',
+    'save' => 'save callback',
+    'access' => 'access callback',
+    'form' => 'form callback'
+  );
+  if (isset($info[$keys[$op]])) {
+    return TRUE;
+  }
+  if ($op == 'revision delete') {
+    return in_array('EntityAPIControllerInterface', class_implements($info['controller class']));
+  }
+  if ($op == 'form') {
+    return (bool) entity_ui_controller($entity_type);
+  }
+  if ($op != 'access') {
+    return in_array('EntityAPIControllerInterface', class_implements($info['controller class']));
+  }
+  return FALSE;
+}
+
+/**
+ * Menu loader function: load an entity from its path.
+ *
+ * This can be used to load entities of all types in menu paths:
+ *
+ * @code
+ * $items['myentity/%entity_object'] = array(
+ *   'load arguments' => array('myentity'),
+ *   'title' => ...,
+ *   'page callback' => ...,
+ *   'page arguments' => array(...),
+ *   'access arguments' => array(...),
+ * );
+ * @endcode
+ *
+ * @param $entity_id
+ *   The ID of the entity to load, passed by the menu URL.
+ * @param $entity_type
+ *   The type of the entity to load.
+ * @return
+ *   A fully loaded entity object, or FALSE in case of error.
+ */
+function entity_object_load($entity_id, $entity_type) {
+  $entities = entity_load($entity_type, array($entity_id));
+  return reset($entities);
+}
+
+/**
+ * Page callback to show links to add an entity of a specific bundle.
+ *
+ * Entity modules that provide a further description to their bundles may wish
+ * to implement their own version of this to show these.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ */
+function entity_ui_bundle_add_page($entity_type) {
+  // Set the title, as we're a MENU_LOCAL_ACTION and hence just get tab titles.
+  module_load_include('inc', 'entity', 'includes/entity.ui');
+  drupal_set_title(entity_ui_get_action_title('add', $entity_type));
+
+  // Get entity info for our bundles.
+  $info = entity_get_info($entity_type);
+  $items = array();
+  foreach ($info['bundles'] as $bundle_name => $bundle_info) {
+    // Create an empty entity with just the bundle set to check for access.
+    $dummy_entity = entity_create($entity_type, array(
+      'bundle' => $bundle_name,
+    ));
+    // If modules use a uid, they can default to the current-user
+    // in their create() method on the storage controller.
+    if (entity_access('create', $entity_type, $dummy_entity, $account = NULL)) {
+      $add_path = $info['admin ui']['path'] . '/add/' . $bundle_name;
+      $items[] = l(t('Add @label', array('@label' => $bundle_info['label'])), $add_path);
+    }
+  }
+  return theme('item_list', array('items' => $items));
+}
+
+/**
+ * Page callback to add an entity of a specific bundle.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $bundle_name
+ *   The bundle machine name.
+ */
+function entity_ui_get_bundle_add_form($entity_type, $bundle_name) {
+  $info = entity_get_info($entity_type);
+  $bundle_key = $info['entity keys']['bundle'];
+
+  // Make a stub entity of the right bundle to pass to the entity_ui_get_form().
+  $values = array(
+    $bundle_key => $bundle_name,
+  );
+  $entity = entity_create($entity_type, $values);
+
+  return entity_ui_get_form($entity_type, $entity, 'add');
+}
+
+/**
+ * A wrapper around entity_load() to load a single entity by name or numeric id.
+ *
+ * @todo: Re-name entity_load() to entity_load_multiple() in d8 core and this
+ * to entity_load().
+ *
+ * @param $entity_type
+ *   The entity type to load, e.g. node or user.
+ * @param $id
+ *   The entity id, either the numeric id or the entity name. In case the entity
+ *   type has specified a name key, both the numeric id and the name may be
+ *   passed.
+ *
+ * @return
+ *   The entity object, or FALSE.
+ *
+ * @see entity_load()
+ */
+function entity_load_single($entity_type, $id) {
+  $entities = entity_load($entity_type, array($id));
+  return reset($entities);
+}
+
+/**
+ * A wrapper around entity_load() to return entities keyed by name key if existing.
+ *
+ * @param $entity_type
+ *   The entity type to load, e.g. node or user.
+ * @param $names
+ *   An array of entity names or ids, or FALSE to load all entities.
+ * @param $conditions
+ *   (deprecated) An associative array of conditions on the base table, where
+ *   the keys are the database fields and the values are the values those
+ *   fields must have. Instead, it is preferable to use EntityFieldQuery to
+ *   retrieve a list of entity IDs loadable by this function.
+ *
+ * @return
+ *   An array of entity objects indexed by their names (or ids if the entity
+ *   type has no name key).
+ *
+ * @see entity_load()
+ */
+function entity_load_multiple_by_name($entity_type, $names = FALSE, $conditions = array()) {
+  $entities = entity_load($entity_type, $names, $conditions);
+  $info = entity_get_info($entity_type);
+  if (!isset($info['entity keys']['name'])) {
+    return $entities;
+  }
+  return entity_key_array_by_property($entities, $info['entity keys']['name']);
+}
+
+/**
+ * Permanently save an entity.
+ *
+ * In case of failures, an exception is thrown.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity to save.
+ *
+ * @return
+ *   For entity types provided by the CRUD API, SAVED_NEW or SAVED_UPDATED is
+ *   returned depending on the operation performed. If there is no information
+ *   how to save the entity, FALSE is returned.
+ *
+ * @see entity_type_supports()
+ */
+function entity_save($entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (method_exists($entity, 'save')) {
+    return $entity->save();
+  }
+  elseif (isset($info['save callback'])) {
+    $info['save callback']($entity);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->save($entity);
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Permanently delete the given entity.
+ *
+ * In case of failures, an exception is thrown.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $id
+ *   The uniform identifier of the entity to delete.
+ *
+ * @return
+ *   FALSE, if there were no information how to delete the entity.
+ *
+ * @see entity_type_supports()
+ */
+function entity_delete($entity_type, $id) {
+  return entity_delete_multiple($entity_type, array($id));
+}
+
+/**
+ * Permanently delete multiple entities.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $ids
+ *   An array of entity ids of the entities to delete. In case the entity makes
+ *   use of a name key, both the names or numeric ids may be passed.
+ * @return
+ *   FALSE if the given entity type isn't compatible to the CRUD API.
+ */
+function entity_delete_multiple($entity_type, $ids) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['deletion callback'])) {
+    foreach ($ids as $id) {
+      $info['deletion callback']($id);
+    }
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    entity_get_controller($entity_type)->delete($ids);
+  }
+  else {
+    return FALSE;
+  }
+}
+
+/**
+ * Loads an entity revision.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $revision_id
+ *   The id of the revision to load.
+ *
+ * @return
+ *   The entity object, or FALSE if there is no entity with the given revision
+ *   id.
+ */
+function entity_revision_load($entity_type, $revision_id) {
+  $info = entity_get_info($entity_type);
+  if (!empty($info['entity keys']['revision'])) {
+    $entity_revisions = entity_load($entity_type, FALSE, array($info['entity keys']['revision'] => $revision_id));
+    return reset($entity_revisions);
+  }
+  return FALSE;
+}
+
+/**
+ * Deletes an entity revision.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $revision_id
+ *   The revision ID to delete.
+ *
+ * @return
+ *   TRUE if the entity revision could be deleted, FALSE otherwise.
+ */
+function entity_revision_delete($entity_type, $revision_id) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['revision deletion callback'])) {
+    return $info['revision deletion callback']($revision_id, $entity_type);
+  }
+  elseif (in_array('EntityAPIControllerRevisionableInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->deleteRevision($revision_id);
+  }
+  return FALSE;
+}
+
+/**
+ * Checks whether the given entity is the default revision.
+ *
+ * Note that newly created entities will always be created in default revision,
+ * thus TRUE is returned for not yet saved entities.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity object to check.
+ *
+ * @return boolean
+ *   A boolean indicating whether the entity is in default revision is returned.
+ *   If the entity is not revisionable or is new, TRUE is returned.
+ *
+ * @see entity_revision_set_default()
+ */
+function entity_revision_is_default($entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (empty($info['entity keys']['revision'])) {
+    return TRUE;
+  }
+  // Newly created entities will always be created in default revision.
+  if (!empty($entity->is_new) || empty($entity->{$info['entity keys']['id']})) {
+    return TRUE;
+  }
+  if (in_array('EntityAPIControllerRevisionableInterface', class_implements($info['controller class']))) {
+    $key = !empty($info['entity keys']['default revision']) ? $info['entity keys']['default revision'] : 'default_revision';
+    return !empty($entity->$key);
+  }
+  else {
+    // Else, just load the default entity and compare the ID. Usually, the
+    // entity should be already statically cached anyway.
+    $default = entity_load_single($entity_type, $entity->{$info['entity keys']['id']});
+    return $default->{$info['entity keys']['revision']} == $entity->{$info['entity keys']['revision']};
+  }
+}
+
+/**
+ * Sets a given entity revision as default revision.
+ *
+ * Note that the default revision flag will only be supported by entity types
+ * based upon the EntityAPIController, i.e. implementing the
+ * EntityAPIControllerRevisionableInterface.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity revision to update.
+ *
+ * @see entity_revision_is_default()
+ */
+function entity_revision_set_default($entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (!empty($info['entity keys']['revision'])) {
+    $key = !empty($info['entity keys']['default revision']) ? $info['entity keys']['default revision'] : 'default_revision';
+    $entity->$key = TRUE;
+  }
+}
+
+/**
+ * Create a new entity object.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $values
+ *   An array of values to set, keyed by property name. If the entity type has
+ *   bundles the bundle key has to be specified.
+ * @return
+ *   A new instance of the entity type or FALSE if there is no information for
+ *   the given entity type.
+ *
+ * @see entity_type_supports()
+ */
+function entity_create($entity_type, array $values) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['creation callback'])) {
+    return $info['creation callback']($values, $entity_type);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->create($values);
+  }
+  return FALSE;
+}
+
+/**
+ * Exports an entity.
+ *
+ * Note: Currently, this only works for entity types provided with the entity
+ * CRUD API.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity to export.
+ * @param $prefix
+ *   An optional prefix for each line.
+ * @return
+ *   The exported entity as serialized string. The format is determined by the
+ *   respective entity controller, e.g. it is JSON for the EntityAPIController.
+ *   The output is suitable for entity_import().
+ */
+function entity_export($entity_type, $entity, $prefix = '') {
+  if (method_exists($entity, 'export')) {
+    return $entity->export($prefix);
+  }
+  $info = entity_get_info($entity_type);
+  if (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->export($entity, $prefix);
+  }
+}
+
+/**
+ * Imports an entity.
+ *
+ * Note: Currently, this only works for entity types provided with the entity
+ * CRUD API.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param string $export
+ *   The string containing the serialized entity as produced by
+ *   entity_export().
+ * @return
+ *   The imported entity object not yet saved.
+ */
+function entity_import($entity_type, $export) {
+  $info = entity_get_info($entity_type);
+  if (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->import($export);
+  }
+}
+
+/**
+ * Checks whether an entity type is fieldable.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ *
+ * @return
+ *   TRUE if the entity type is fieldable, FALSE otherwise.
+ */
+function entity_type_is_fieldable($entity_type) {
+  $info = entity_get_info($entity_type);
+  return !empty($info['fieldable']);
+}
+
+/**
+ * Builds a structured array representing the entity's content.
+ *
+ * The content built for the entity will vary depending on the $view_mode
+ * parameter.
+ *
+ * Note: Currently, this only works for entity types provided with the entity
+ * CRUD API.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   An entity object.
+ * @param $view_mode
+ *   A view mode as used by this entity type, e.g. 'full', 'teaser'...
+ * @param $langcode
+ *   (optional) A language code to use for rendering. Defaults to the global
+ *   content language of the current request.
+ * @return
+ *   The renderable array.
+ */
+function entity_build_content($entity_type, $entity, $view_mode = 'full', $langcode = NULL) {
+  $info = entity_get_info($entity_type);
+  if (method_exists($entity, 'buildContent')) {
+    return $entity->buildContent($view_mode, $langcode);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->buildContent($entity, $view_mode, $langcode);
+  }
+}
+
+/**
+ * Returns the entity identifier, i.e. the entities name or numeric id.
+ *
+ * Unlike entity_extract_ids() this function returns the name of the entity
+ * instead of the numeric id, in case the entity type has specified a name key.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   An entity object.
+ *
+ * @see entity_extract_ids()
+ */
+function entity_id($entity_type, $entity) {
+  if (method_exists($entity, 'identifier')) {
+    return $entity->identifier();
+  }
+  $info = entity_get_info($entity_type);
+  $key = isset($info['entity keys']['name']) ? $info['entity keys']['name'] : $info['entity keys']['id'];
+  return isset($entity->$key) ? $entity->$key : NULL;
+}
+
+/**
+ * Generate an array for rendering the given entities.
+ *
+ * Entities being viewed, are generally expected to be fully-loaded entity
+ * objects, thus have their name or id key set. However, it is possible to
+ * view a single entity without any id, e.g. for generating a preview during
+ * creation.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entities
+ *   An array of entities to render.
+ * @param $view_mode
+ *   A view mode as used by this entity type, e.g. 'full', 'teaser'...
+ * @param $langcode
+ *   (optional) A language code to use for rendering. Defaults to the global
+ *   content language of the current request.
+ * @param $page
+ *   (optional) If set will control if the entity is rendered: if TRUE
+ *   the entity will be rendered without its title, so that it can be embeded
+ *   in another context. If FALSE the entity will be displayed with its title
+ *   in a mode suitable for lists.
+ *   If unset, the page mode will be enabled if the current path is the URI
+ *   of the entity, as returned by entity_uri().
+ *   This parameter is only supported for entities which controller is a
+ *   EntityAPIControllerInterface.
+ * @return
+ *   The renderable array, keyed by the entity type and by entity identifiers,
+ *   for which the entity name is used if existing - see entity_id(). If there
+ *   is no information on how to view an entity, FALSE is returned.
+ */
+function entity_view($entity_type, $entities, $view_mode = 'full', $langcode = NULL, $page = NULL) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['view callback'])) {
+    $entities = entity_key_array_by_property($entities, $info['entity keys']['id']);
+    return $info['view callback']($entities, $view_mode, $langcode, $entity_type);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->view($entities, $view_mode, $langcode, $page);
+  }
+  return FALSE;
+}
+
+/**
+ * Determines whether the given user has access to an entity.
+ *
+ * @param $op
+ *   The operation being performed. One of 'view', 'update', 'create' or
+ *   'delete'.
+ * @param $entity_type
+ *   The entity type of the entity to check for.
+ * @param $entity
+ *   Optionally an entity to check access for. If no entity is given, it will be
+ *   determined whether access is allowed for all entities of the given type.
+ * @param $account
+ *   The user to check for. Leave it to NULL to check for the global user.
+ *
+ * @return boolean
+ *   Whether access is allowed or not. If the entity type does not specify any
+ *   access information, NULL is returned.
+ *
+ * @see entity_type_supports()
+ */
+function entity_access($op, $entity_type, $entity = NULL, $account = NULL) {
+  if (($info = entity_get_info()) && isset($info[$entity_type]['access callback'])) {
+    return $info[$entity_type]['access callback']($op, $entity, $account, $entity_type);
+  }
+}
+
+/**
+ * Gets the edit form for any entity.
+ *
+ * This helper makes use of drupal_get_form() and the regular form builder
+ * function of the entity type to retrieve and process the form as usual.
+ *
+ * In order to use this helper to show an entity add form, the new entity object
+ * can be created via entity_create() or entity_property_values_create_entity().
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity to show the edit form for.
+ * @return
+ *   The renderable array of the form. If there is no entity form or missing
+ *   metadata, FALSE is returned.
+ *
+ * @see entity_type_supports()
+ */
+function entity_form($entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (isset($info['form callback'])) {
+    return $info['form callback']($entity, $entity_type);
+  }
+  // If there is an UI controller, the providing module has to implement the
+  // entity form using entity_ui_get_form().
+  elseif (entity_ui_controller($entity_type)) {
+    return entity_metadata_form_entity_ui($entity, $entity_type);
+  }
+  return FALSE;
+}
+
+/**
+ * Converts an array of entities to be keyed by the values of a given property.
+ *
+ * @param array $entities
+ *   The array of entities to convert.
+ * @param $property
+ *   The name of entity property, by which the array should be keyed. To get
+ *   reasonable results, the property has to have unique values.
+ *
+ * @return array
+ *   The same entities in the same order, but keyed by their $property values.
+ */
+function entity_key_array_by_property(array $entities, $property) {
+  $ret = array();
+  foreach ($entities as $entity) {
+    $key = isset($entity->$property) ? $entity->$property : NULL;
+    $ret[$key] = $entity;
+  }
+  return $ret;
+}
+
+/**
+ * Get the entity info for the entity types provided via the entity CRUD API.
+ *
+ * @return
+ *  An array in the same format as entity_get_info(), containing the entities
+ *  whose controller class implements the EntityAPIControllerInterface.
+ */
+function entity_crud_get_info() {
+  $types = array();
+  foreach (entity_get_info() as $type => $info) {
+    if (isset($info['controller class']) && in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+      $types[$type] = $info;
+    }
+  }
+  return $types;
+}
+
+/**
+ * Checks if a given entity has a certain exportable status.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $entity
+ *   The entity to check the status on.
+ * @param $status
+ *   The constant status like ENTITY_CUSTOM, ENTITY_IN_CODE, ENTITY_OVERRIDDEN
+ *   or ENTITY_FIXED.
+ *
+ * @return
+ *   TRUE if the entity has the status, FALSE otherwise.
+ */
+function entity_has_status($entity_type, $entity, $status) {
+  $info = entity_get_info($entity_type);
+  $status_key = empty($info['entity keys']['status']) ? 'status' : $info['entity keys']['status'];
+  return isset($entity->{$status_key}) && ($entity->{$status_key} & $status) == $status;
+}
+
+/**
+ * Export a variable. Copied from ctools.
+ *
+ * This is a replacement for var_export(), allowing us to more nicely
+ * format exports. It will recurse down into arrays and will try to
+ * properly export bools when it can.
+ */
+function entity_var_export($var, $prefix = '') {
+  if (is_array($var)) {
+    if (empty($var)) {
+      $output = 'array()';
+    }
+    else {
+      $output = "array(\n";
+      foreach ($var as $key => $value) {
+        $output .= "  '$key' => " . entity_var_export($value, '  ') . ",\n";
+      }
+      $output .= ')';
+    }
+  }
+  elseif (is_bool($var)) {
+    $output = $var ? 'TRUE' : 'FALSE';
+  }
+  else {
+    $output = var_export($var, TRUE);
+  }
+
+  if ($prefix) {
+    $output = str_replace("\n", "\n$prefix", $output);
+  }
+  return $output;
+}
+
+/**
+ * Export a variable in pretty formatted JSON.
+ */
+function entity_var_json_export($var, $prefix = '') {
+  if (is_array($var) && $var) {
+    // Defines whether we use a JSON array or object.
+    $use_array = ($var == array_values($var));
+    $output = $use_array ? "[" : "{";
+
+    foreach ($var as $key => $value) {
+      if ($use_array) {
+        $values[] = entity_var_json_export($value, '  ');
+      }
+      else {
+        $values[] = entity_var_json_export((string) $key, '  ') . ' : ' . entity_var_json_export($value, '  ');
+      }
+    }
+    // Use several lines for long content. However for objects with a single
+    // entry keep the key in the first line.
+    if (strlen($content = implode(', ', $values)) > 70 && ($use_array || count($values) > 1)) {
+      $output .= "\n  " . implode(",\n  ", $values) . "\n";
+    }
+    elseif (strpos($content, "\n") !== FALSE) {
+      $output .= " " . $content . "\n";
+    }
+    else {
+      $output .= " " . $content . ' ';
+    }
+    $output .= $use_array ? ']' : '}';
+  }
+  else {
+    $output = drupal_json_encode($var);
+  }
+
+  if ($prefix) {
+    $output = str_replace("\n", "\n$prefix", $output);
+  }
+  return $output;
+}
+
+/**
+ * Rebuild the default entities provided in code.
+ *
+ * Exportable entities provided in code get saved to the database once a module
+ * providing defaults in code is activated. This allows module and entity_load()
+ * to easily deal with exportable entities just by relying on the database.
+ *
+ * The defaults get rebuilt if the cache is cleared or new modules providing
+ * defaults are enabled, such that the defaults in the database are up to date.
+ * A default entity gets updated with the latest defaults in code during rebuild
+ * as long as the default has not been overridden. Once a module providing
+ * defaults is disabled, its default entities get removed from the database
+ * unless they have been overridden. In that case the overridden entity is left
+ * in the database, but its status gets updated to 'custom'.
+ *
+ * @param $entity_types
+ *   (optional) If specified, only the defaults of the given entity types are
+ *   rebuilt.
+ */
+function entity_defaults_rebuild($entity_types = NULL) {
+  if (!isset($entity_types)) {
+    $entity_types = array();
+    foreach (entity_crud_get_info() as $type => $info) {
+      if (!empty($info['exportable'])) {
+        $entity_types[] = $type;
+      }
+    };
+  }
+  foreach ($entity_types as $type) {
+    _entity_defaults_rebuild($type);
+  }
+}
+
+/**
+ * Actually rebuild the defaults of a given entity type.
+ */
+function _entity_defaults_rebuild($entity_type) {
+  if (lock_acquire('entity_rebuild_' . $entity_type)) {
+    $info = entity_get_info($entity_type);
+    $hook = isset($info['export']['default hook']) ? $info['export']['default hook'] : 'default_' . $entity_type;
+    $keys = $info['entity keys'] + array('module' => 'module', 'status' => 'status', 'name' => $info['entity keys']['id']);
+
+    // Check for the existence of the module and status columns.
+    if (!in_array($keys['status'], $info['schema_fields_sql']['base table']) || !in_array($keys['module'], $info['schema_fields_sql']['base table'])) {
+      trigger_error("Missing database columns for the exportable entity $entity_type as defined by entity_exportable_schema_fields(). Update the according module and run update.php!", E_USER_WARNING);
+      return;
+    }
+
+    // Invoke the hook and collect default entities.
+    $entities = array();
+    foreach (module_implements($hook) as $module) {
+      foreach ((array) module_invoke($module, $hook) as $name => $entity) {
+        $entity->{$keys['name']} = $name;
+        $entity->{$keys['module']} = $module;
+        $entities[$name] = $entity;
+      }
+    }
+    drupal_alter($hook, $entities);
+
+    // Check for defaults that disappeared.
+    $existing_defaults = entity_load_multiple_by_name($entity_type, FALSE, array($keys['status'] => array(ENTITY_OVERRIDDEN, ENTITY_IN_CODE, ENTITY_FIXED)));
+
+    foreach ($existing_defaults as $name => $entity) {
+      if (empty($entities[$name])) {
+        $entity->is_rebuild = TRUE;
+        if (entity_has_status($entity_type, $entity, ENTITY_OVERRIDDEN)) {
+          $entity->{$keys['status']} = ENTITY_CUSTOM;
+          entity_save($entity_type, $entity);
+        }
+        else {
+          entity_delete($entity_type, $name);
+        }
+        unset($entity->is_rebuild);
+      }
+    }
+
+    // Load all existing entities.
+    $existing_entities = entity_load_multiple_by_name($entity_type, array_keys($entities));
+
+    foreach ($existing_entities as $name => $entity) {
+      if (entity_has_status($entity_type, $entity, ENTITY_CUSTOM)) {
+        // If the entity already exists but is not yet marked as overridden, we
+        // have to update the status.
+        if (!entity_has_status($entity_type, $entity, ENTITY_OVERRIDDEN)) {
+          $entity->{$keys['status']} |= ENTITY_OVERRIDDEN;
+          $entity->{$keys['module']} = $entities[$name]->{$keys['module']};
+          $entity->is_rebuild = TRUE;
+          entity_save($entity_type, $entity);
+          unset($entity->is_rebuild);
+        }
+
+        // The entity is overridden, so we do not need to save the default.
+        unset($entities[$name]);
+      }
+    }
+
+    // Save defaults.
+    $originals = array();
+    foreach ($entities as $name => $entity) {
+      if (!empty($existing_entities[$name])) {
+        // Make sure we are updating the existing default.
+        $entity->{$keys['id']} = $existing_entities[$name]->{$keys['id']};
+        unset($entity->is_new);
+      }
+      // Pre-populate $entity->original as we already have it. So we avoid
+      // loading it again.
+      $entity->original = !empty($existing_entities[$name]) ? $existing_entities[$name] : FALSE;
+      // Keep original entities for hook_{entity_type}_defaults_rebuild()
+      // implementations.
+      $originals[$name] = $entity->original;
+
+      $entity->{$keys['status']} |= ENTITY_IN_CODE;
+      $entity->is_rebuild = TRUE;
+      entity_save($entity_type, $entity);
+      unset($entity->is_rebuild);
+    }
+
+    // Invoke an entity type-specific hook so modules may apply changes, e.g.
+    // efficiently rebuild caches.
+    module_invoke_all($entity_type . '_defaults_rebuild', $entities, $originals);
+
+    lock_release('entity_rebuild_' . $entity_type);
+  }
+}
+
+/**
+ * Implements hook_modules_enabled().
+ */
+function entity_modules_enabled($modules) {
+  foreach (_entity_modules_get_default_types($modules) as $type) {
+    _entity_defaults_rebuild($type);
+  }
+}
+
+/**
+ * Implements hook_modules_disabled().
+ */
+function entity_modules_disabled($modules) {
+  foreach (_entity_modules_get_default_types($modules) as $entity_type) {
+    $info = entity_get_info($entity_type);
+
+    // Do nothing if the module providing the entity type has been disabled too.
+    if (isset($info['module']) && in_array($info['module'], $modules)) {
+      return;
+    }
+
+    $keys = $info['entity keys'] + array('module' => 'module', 'status' => 'status', 'name' => $info['entity keys']['id']);
+    // Remove entities provided in code by one of the disabled modules.
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $entity_type, '=')
+          ->propertyCondition($keys['module'], $modules, 'IN')
+          ->propertyCondition($keys['status'], array(ENTITY_IN_CODE, ENTITY_FIXED), 'IN');
+    $result = $query->execute();
+    if (isset($result[$entity_type])) {
+      $entities = entity_load($entity_type, array_keys($result[$entity_type]));
+      entity_delete_multiple($entity_type, array_keys($entities));
+    }
+
+    // Update overridden entities to be now custom.
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $entity_type, '=')
+          ->propertyCondition($keys['module'], $modules, 'IN')
+          ->propertyCondition($keys['status'], ENTITY_OVERRIDDEN, '=');
+    $result = $query->execute();
+    if (isset($result[$entity_type])) {
+      foreach (entity_load($entity_type, array_keys($result[$entity_type])) as $name => $entity) {
+        $entity->{$keys['status']} = ENTITY_CUSTOM;
+        $entity->{$keys['module']} = NULL;
+        entity_save($entity_type, $entity);
+      }
+    }
+
+    // Rebuild the remaining defaults so any alterations of the disabled modules
+    // are gone.
+    _entity_defaults_rebuild($entity_type);
+  }
+}
+
+/**
+ * Gets all entity types for which defaults are provided by the $modules.
+ */
+function _entity_modules_get_default_types($modules) {
+  $types = array();
+  foreach (entity_crud_get_info() as $entity_type => $info) {
+    if (!empty($info['exportable'])) {
+      $hook = isset($info['export']['default hook']) ? $info['export']['default hook'] : 'default_' . $entity_type;
+      foreach ($modules as $module) {
+        if (module_hook($module, $hook) || module_hook($module, $hook . '_alter')) {
+          $types[] = $entity_type;
+        }
+      }
+    }
+  }
+  return $types;
+}
+
+/**
+ * Defines schema fields required for exportable entities.
+ *
+ * Warning: Do not call this function in your module's hook_schema()
+ * implementation or update functions. It is not safe to call functions of
+ * dependencies at this point. Instead of calling the function, just copy over
+ * the content.
+ * For more details see the issue http://drupal.org/node/1122812.
+ */
+function entity_exportable_schema_fields($module_col = 'module', $status_col = 'status') {
+  return array(
+    $status_col => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      // Set the default to ENTITY_CUSTOM without using the constant as it is
+      // not safe to use it at this point.
+      'default' => 0x01,
+      'size' => 'tiny',
+      'description' => 'The exportable status of the entity.',
+    ),
+    $module_col => array(
+      'description' => 'The name of the providing module if the entity has been defined in code.',
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => FALSE,
+    ),
+  );
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function entity_flush_caches() {
+  entity_property_info_cache_clear();
+  // Re-build defaults in code, however skip it on the admin modules page. In
+  // case of enabling or disabling modules we already rebuild defaults in
+  // entity_modules_enabled() and entity_modules_disabled(), so we do not need
+  // to do it again.
+  if (current_path() != 'admin/modules/list/confirm') {
+    entity_defaults_rebuild();
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function entity_theme() {
+  // Build a pattern in the form of "(type1|type2|...)(\.|__)" such that all
+  // templates starting with an entity type or named like the entity type
+  // are found.
+  // This has to match the template suggestions provided in
+  // template_preprocess_entity().
+  $types = array_keys(entity_crud_get_info());
+  $pattern = '(' . implode('|', $types) . ')(\.|__)';
+
+  return array(
+    'entity_status' => array(
+      'variables' => array('status' => NULL, 'html' => TRUE),
+      'file' => 'theme/entity.theme.inc',
+    ),
+    'entity' => array(
+      'render element' => 'elements',
+      'template' => 'entity',
+      'pattern' => $pattern,
+      'path' => drupal_get_path('module', 'entity') . '/theme',
+      'file' => 'entity.theme.inc',
+    ),
+    'entity_property' => array(
+      'render element' => 'elements',
+      'file' => 'theme/entity.theme.inc',
+    ),
+    'entity_ui_overview_item' => array(
+      'variables' => array('label' => NULL, 'entity_type' => NULL, 'url' => FALSE, 'name' => FALSE),
+      'file' => 'includes/entity.ui.inc'
+    ),
+  );
+}
+
+/**
+ * Label callback that refers to the entity classes label method.
+ */
+function entity_class_label($entity) {
+  return $entity->label();
+}
+
+/**
+ * URI callback that refers to the entity classes uri method.
+ */
+function entity_class_uri($entity) {
+  return $entity->uri();
+}
+
+/**
+ * Implements hook_file_download_access() for entity types provided by the CRUD API.
+ */
+function entity_file_download_access($field, $entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_access('view', $entity_type, $entity);
+  }
+}
+
+/**
+ * Determines the UI controller class for a given entity type.
+ *
+ * @return EntityDefaultUIController
+ *   If a type is given, the controller for the given entity type. Else an array
+ *   of all enabled UI controllers keyed by entity type is returned.
+ */
+function entity_ui_controller($type = NULL) {
+  $static = &drupal_static(__FUNCTION__);
+
+  if (!isset($type)) {
+    // Invoke the function for each type to ensure we have fully populated the
+    // static variable.
+    foreach (entity_get_info() as $entity_type => $info) {
+      entity_ui_controller($entity_type);
+    }
+    return array_filter($static);
+  }
+
+  if (!isset($static[$type])) {
+    $info = entity_get_info($type);
+    $class = isset($info['admin ui']['controller class']) ? $info['admin ui']['controller class'] : 'EntityDefaultUIController';
+    $static[$type] = (isset($info['admin ui']['path']) && $class) ? new $class($type, $info) : FALSE;
+  }
+
+  return $static[$type];
+}
+
+/**
+ * Implements hook_menu().
+ *
+ * @see EntityDefaultUIController::hook_menu()
+ */
+function entity_menu() {
+  $items = array();
+  foreach (entity_ui_controller() as $controller) {
+    $items += $controller->hook_menu();
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_forms().
+ *
+ * @see EntityDefaultUIController::hook_forms()
+ * @see entity_ui_get_form()
+ */
+function entity_forms($form_id, $args) {
+  // For efficiency only invoke an entity types controller, if a form of it is
+  // requested. Thus if the first (overview and operation form) or the third
+  // argument (edit form) is an entity type name, add in the types forms.
+  if (isset($args[0]) && is_string($args[0]) && entity_get_info($args[0])) {
+    $type = $args[0];
+  }
+  elseif (isset($args[2]) && is_string($args[2]) && entity_get_info($args[2])) {
+    $type = $args[2];
+  }
+  if (isset($type) && $controller = entity_ui_controller($type)) {
+    return $controller->hook_forms();
+  }
+}
+
+/**
+ * A wrapper around drupal_get_form() that helps building entity forms.
+ *
+ * This function may be used by entities to build their entity form. It has to
+ * be used instead of calling drupal_get_form().
+ * Entity forms built with this helper receive useful defaults suiting for
+ * editing a single entity, whereas the special cases of adding and cloning
+ * of entities are supported too.
+ *
+ * While this function is intended to be used to get entity forms for entities
+ * using the entity ui controller, it may be used for entity types not using
+ * the ui controller too.
+ *
+ * @param $entity_type
+ *   The entity type for which to get the form.
+ * @param $entity
+ *   The entity for which to return the form.
+ *   If $op is 'add' the entity has to be either initialized before calling this
+ *   function, or NULL may be passed. If NULL is passed, an entity will be
+ *   initialized with empty values using entity_create(). Thus entities, for
+ *   which this is problematic have to care to pass in an initialized entity.
+ * @param $op
+ *   (optional) One of 'edit', 'add' or 'clone'. Defaults to edit.
+ * @param $form_state
+ *   (optional) A pre-populated form state, e.g. to add in form include files.
+ *   See entity_metadata_form_entity_ui().
+ *
+ * @return
+ *   The fully built and processed form, ready to be rendered.
+ *
+ * @see EntityDefaultUIController::hook_forms()
+ * @see entity_ui_form_submit_build_entity()
+ */
+function entity_ui_get_form($entity_type, $entity, $op = 'edit', $form_state = array()) {
+  if (isset($entity)) {
+    list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  }
+  $form_id = (!isset($bundle) || $bundle == $entity_type) ? $entity_type . '_form' : $entity_type . '_edit_' . $bundle . '_form';
+
+  if (!isset($entity) && $op == 'add') {
+    $entity = entity_create($entity_type, array());
+  }
+
+  // Do not use drupal_get_form(), but invoke drupal_build_form() ourself so
+  // we can prepulate the form state.
+  $form_state['wrapper_callback'] = 'entity_ui_main_form_defaults';
+  $form_state['entity_type'] = $entity_type;
+  form_load_include($form_state, 'inc', 'entity', 'includes/entity.ui');
+
+  // Handle cloning. We cannot do that in the wrapper callback as it is too late
+  // for changing arguments.
+  if ($op == 'clone') {
+    $entity = entity_ui_clone_entity($entity_type, $entity);
+  }
+
+  // We don't pass the entity type as first parameter, as the implementing
+  // module knows the type anyway. However, in order to allow for efficient
+  // hook_forms() implementiations we append the entity type as last argument,
+  // which the module implementing the form constructor may safely ignore.
+  // @see entity_forms()
+  $form_state['build_info']['args'] = array($entity, $op, $entity_type);
+  return drupal_build_form($form_id, $form_state);
+}
+
+/**
+ * Helper for using i18n_string().
+ *
+ * @param $name
+ *   Textgroup and context glued with ':'.
+ * @param $default
+ *   String in default language. Default language may or may not be English.
+ * @param $langcode
+ *   (optional) The code of a certain language to translate the string into.
+ *   Defaults to the i18n_string() default, i.e. the current language.
+ *
+ * @see i18n_string()
+ */
+function entity_i18n_string($name, $default, $langcode = NULL) {
+  return function_exists('i18n_string') ? i18n_string($name, $default, array('langcode' => $langcode)) : $default;
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function entity_views_api() {
+  return array(
+    'api' => '3.0-alpha1',
+    'path' => drupal_get_path('module', 'entity') . '/views',
+  );
+}
+
+/**
+ * Implements hook_field_extra_fields().
+ */
+function entity_field_extra_fields() {
+  // Invoke specified controllers for entity types provided by the CRUD API.
+  $items = array();
+  foreach (entity_crud_get_info() as $type => $info) {
+    if (!empty($info['extra fields controller class'])) {
+      $items = array_merge_recursive($items, entity_get_extra_fields_controller($type)->fieldExtraFields());
+    }
+  }
+  return $items;
+}
+
+/**
+ * Gets the extra field controller class for a given entity type.
+ *
+ * @return EntityExtraFieldsControllerInterface|false
+ *   The controller for the given entity type or FALSE if none is specified.
+ */
+function entity_get_extra_fields_controller($type = NULL) {
+  $static = &drupal_static(__FUNCTION__);
+
+  if (!isset($static[$type])) {
+    $static[$type] = FALSE;
+    $info = entity_get_info($type);
+    if (!empty($info['extra fields controller class'])) {
+      $static[$type] = new $info['extra fields controller class']($type);
+    }
+  }
+  return $static[$type];
+}
+
+/**
+ * Returns a property wrapper for the given data.
+ *
+ * If an entity is wrapped, the wrapper can be used to retrieve further wrappers
+ * for the entitity properties. For that the wrapper support chaining, e.g. you
+ * can use a node wrapper to get the node authors mail address:
+ *
+ * @code
+ *   echo $wrappedNode->author->mail->value();
+ * @endcode
+ *
+ * @param $type
+ *   The type of the passed data.
+ * @param $data
+ *   The data to wrap. It may be set to NULL, so the wrapper can be used
+ *   without any data for getting information about properties.
+ * @param $info
+ *   (optional) Specify additional information for the passed data:
+ *    - langcode: (optional) If the data is language specific, its langauge
+ *      code. Defaults to NULL, what means language neutral.
+ *    - bundle: (optional) If an entity is wrapped but not passed, use this key
+ *      to specify the bundle to return a wrapper for.
+ *    - property info: (optional) May be used to use a wrapper with an arbitrary
+ *      data structure (type 'struct'). Use this key for specifying info about
+ *      properties in the same structure as used by hook_entity_property_info().
+ *    - property info alter: (optional) A callback for altering the property
+ *      info before it is utilized by the wrapper.
+ *    - property defaults: (optional) An array of defaults for the info of
+ *      each property of the wrapped data item.
+ * @return EntityMetadataWrapper
+ *   Dependend on the passed data the right wrapper is returned.
+ */
+function entity_metadata_wrapper($type, $data = NULL, array $info = array()) {
+  if ($type == 'entity' || (($entity_info = entity_get_info()) && isset($entity_info[$type]))) {
+    // If the passed entity is the global $user, we load the user object by only
+    // passing on the user id. The global user is not a fully loaded entity.
+    if ($type == 'user' && is_object($data) && $data == $GLOBALS['user']) {
+      $data = $data->uid;
+    }
+    return new EntityDrupalWrapper($type, $data, $info);
+  }
+  elseif ($type == 'list' || entity_property_list_extract_type($type)) {
+    return new EntityListWrapper($type, $data, $info);
+  }
+  elseif (isset($info['property info'])) {
+    return new EntityStructureWrapper($type, $data, $info);
+  }
+  else {
+    return new EntityValueWrapper($type, $data, $info);
+  }
+}
+
+/**
+ * Returns a metadata wrapper for accessing site-wide properties.
+ *
+ * Although there is no 'site' entity or such, modules may provide info about
+ * site-wide properties using hook_entity_property_info(). This function returns
+ * a wrapper for making use of this properties.
+ *
+ * @return EntityMetadataWrapper
+ *   A wrapper for accessing site-wide properties.
+ *
+ * @see entity_metadata_system_entity_property_info()
+ */
+function entity_metadata_site_wrapper() {
+  $site_info = entity_get_property_info('site');
+  $info['property info'] = $site_info['properties'];
+  return entity_metadata_wrapper('site', FALSE, $info);
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ *
+ * Moves the hook_entity_info_alter() implementation to the bottom so it is
+ * invoked after all modules relying on the entity API.
+ * That way we ensure to run last and clear the field-info cache after the
+ * others added in their bundle information.
+ *
+ * @see entity_entity_info_alter()
+ */
+function entity_module_implements_alter(&$implementations, $hook) {
+  if ($hook == 'entity_info_alter') {
+    // Move our hook implementation to the bottom.
+    $group = $implementations['entity'];
+    unset($implementations['entity']);
+    $implementations['entity'] = $group;
+  }
+}
+
+/**
+ * Implements hook_entity_info_alter().
+ *
+ * @see entity_module_implements_alter()
+ */
+function entity_entity_info_alter(&$entity_info) {
+  _entity_info_add_metadata($entity_info);
+
+  // Populate a default value for the 'configuration' key of all entity types.
+  foreach ($entity_info as $type => $info) {
+    if (!isset($info['configuration'])) {
+      $entity_info[$type]['configuration'] = !empty($info['exportable']);
+    }
+  }
+}
+
+/**
+ * Adds metadata and callbacks for core entities to the entity info.
+ */
+function _entity_info_add_metadata(&$entity_info) {
+  // Set plural labels.
+  $entity_info['node']['plural label'] = t('Nodes');
+  $entity_info['user']['plural label'] = t('Users');
+  $entity_info['file']['plural label'] = t('Files');
+
+  // Set descriptions.
+  $entity_info['node']['description'] = t('Nodes represent the main site content items.');
+  $entity_info['user']['description'] = t('Users who have created accounts on your site.');
+  $entity_info['file']['description'] = t('Uploaded file.');
+
+  // Set access callbacks.
+  $entity_info['node']['access callback'] = 'entity_metadata_no_hook_node_access';
+  $entity_info['user']['access callback'] = 'entity_metadata_user_access';
+  // File entity has it's own entity_access function.
+  if (!module_exists('file_entity')) {
+    $entity_info['file']['access callback'] = 'entity_metadata_file_access';
+  }
+
+  // CRUD function callbacks.
+  $entity_info['node']['creation callback'] = 'entity_metadata_create_node';
+  $entity_info['node']['save callback'] = 'node_save';
+  $entity_info['node']['deletion callback'] = 'node_delete';
+  $entity_info['node']['revision deletion callback'] = 'node_revision_delete';
+  $entity_info['user']['creation callback'] = 'entity_metadata_create_object';
+  $entity_info['user']['save callback'] = 'entity_metadata_user_save';
+  $entity_info['user']['deletion callback'] = 'user_delete';
+  $entity_info['file']['save callback'] = 'file_save';
+  $entity_info['file']['deletion callback'] = 'entity_metadata_delete_file';
+
+  // Form callbacks.
+  $entity_info['node']['form callback'] = 'entity_metadata_form_node';
+  $entity_info['user']['form callback'] = 'entity_metadata_form_user';
+
+  // View callbacks.
+  $entity_info['node']['view callback'] = 'entity_metadata_view_node';
+  $entity_info['user']['view callback'] = 'entity_metadata_view_single';
+
+  if (module_exists('comment')) {
+    $entity_info['comment']['plural label'] = t('Comments');
+    $entity_info['comment']['description'] = t('Remark or note that refers to a node.');
+    $entity_info['comment']['access callback'] = 'entity_metadata_comment_access';
+    $entity_info['comment']['creation callback'] = 'entity_metadata_create_comment';
+    $entity_info['comment']['save callback'] = 'comment_save';
+    $entity_info['comment']['deletion callback'] = 'comment_delete';
+    $entity_info['comment']['view callback'] = 'entity_metadata_view_comment';
+    $entity_info['comment']['form callback'] = 'entity_metadata_form_comment';
+  }
+  if (module_exists('taxonomy')) {
+    $entity_info['taxonomy_term']['plural label'] = t('Taxonomy terms');
+    $entity_info['taxonomy_term']['description'] = t('Taxonomy terms are used for classifying content.');
+    $entity_info['taxonomy_term']['access callback'] = 'entity_metadata_taxonomy_access';
+    $entity_info['taxonomy_term']['creation callback'] = 'entity_metadata_create_object';
+    $entity_info['taxonomy_term']['save callback'] = 'taxonomy_term_save';
+    $entity_info['taxonomy_term']['deletion callback'] = 'taxonomy_term_delete';
+    $entity_info['taxonomy_term']['view callback'] = 'entity_metadata_view_single';
+    $entity_info['taxonomy_term']['form callback'] = 'entity_metadata_form_taxonomy_term';
+
+    $entity_info['taxonomy_vocabulary']['plural label'] = t('Taxonomy vocabularies');
+    $entity_info['taxonomy_vocabulary']['description'] = t('Vocabularies contain related taxonomy terms, which are used for classifying content.');
+    $entity_info['taxonomy_vocabulary']['access callback'] = 'entity_metadata_taxonomy_access';
+    $entity_info['taxonomy_vocabulary']['creation callback'] = 'entity_metadata_create_object';
+    $entity_info['taxonomy_vocabulary']['save callback'] = 'taxonomy_vocabulary_save';
+    $entity_info['taxonomy_vocabulary']['deletion callback'] = 'taxonomy_vocabulary_delete';
+    $entity_info['taxonomy_vocabulary']['form callback'] = 'entity_metadata_form_taxonomy_vocabulary';
+    // Token type mapping.
+    $entity_info['taxonomy_term']['token type'] = 'term';
+    $entity_info['taxonomy_vocabulary']['token type'] = 'vocabulary';
+  }
+}
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function entity_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'ctools' && $plugin == 'content_types') {
+    return 'ctools/content_types';
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Provides Rules integration for entities provided via the CRUD API.
+ *
+ * Rules automatically provides us with actions for CRUD and a suiting entity
+ * data type. For events the controller automatically invokes Rules events once
+ * Rules is active, so we just have to provide the appropriate info.
+ */
+
+/**
+ * Default controller for generating Rules integration.
+ */
+class EntityDefaultRulesController {
+
+  protected $type, $info;
+
+  public function __construct($type) {
+    $this->type = $type;
+    $this->info = entity_get_info($type);
+  }
+
+  public function eventInfo() {
+    $info = $this->info;
+    $type = $this->type;
+
+    $label = $info['label'];
+    $defaults = array(
+      'module' => isset($info['module']) ? $info['module'] : 'entity',
+      'group' => $label,
+      'access callback' => 'entity_rules_integration_event_access',
+    );
+
+    $items[$type . '_insert'] = $defaults + array(
+      'label' => t('After saving a new @entity', array('@entity' => drupal_strtolower($label))),
+      'variables' => entity_rules_events_variables($type, t('created @entity', array('@entity' => drupal_strtolower($label)))),
+    );
+    $items[$type . '_update'] = $defaults + array(
+      'label' => t('After updating an existing @entity', array('@entity' => drupal_strtolower($label))),
+      'variables' => entity_rules_events_variables($type, t('updated @entity', array('@entity' => drupal_strtolower($label))), TRUE),
+    );
+    $items[$type . '_presave'] = $defaults + array(
+      'label' => t('Before saving a @entity', array('@entity' => drupal_strtolower($label))),
+      'variables' => entity_rules_events_variables($type, t('saved @entity', array('@entity' => drupal_strtolower($label))), TRUE),
+    );
+    $items[$type . '_delete'] = $defaults + array(
+      'label' => t('After deleting a @entity', array('@entity' => drupal_strtolower($label))),
+      'variables' => entity_rules_events_variables($type, t('deleted @entity', array('@entity' => drupal_strtolower($label)))),
+    );
+    if (count($info['view modes'])) {
+      $items[$type . '_view'] = $defaults + array(
+        'label' => t('@entity is viewed', array('@entity' => $label)),
+        'variables' => entity_rules_events_variables($type, t('viewed @entity', array('@entity' => drupal_strtolower($label)))) + array(
+          'view_mode' => array(
+            'type' => 'text',
+            'label' => t('view mode'),
+            'options list' => 'rules_get_entity_view_modes',
+             // Add the entity-type for the options list callback.
+            'options list entity type' => $type,
+          ),
+        ),
+      );
+    }
+    // Specify that on presave the entity is saved anyway.
+    $items[$type . '_presave']['variables'][$type]['skip save'] = TRUE;
+    return $items;
+  }
+
+}
+
+/**
+ * Returns some parameter info suiting for the specified entity type.
+ */
+function entity_rules_events_variables($type, $label, $update = FALSE) {
+  $args = array(
+    $type => array('type' => $type, 'label' => $label),
+  );
+  if ($update) {
+    $args += array(
+      $type . '_unchanged' => array(
+        'type' => $type,
+        'label' => t('unchanged entity'),
+        'handler' => 'rules_events_entity_unchanged',
+      ),
+    );
+  }
+  return $args;
+}
+
+/**
+ * Implements hook_rules_event_info().
+ */
+function entity_rules_event_info() {
+  $items = array();
+  foreach (entity_crud_get_info() as $type => $info) {
+    // By default we enable the controller only for non-configuration.
+    $configuration = !empty($info['configuration']) || !empty($info['exportable']);
+    $info += array('rules controller class' => $configuration ? FALSE : 'EntityDefaultRulesController');
+    if ($info['rules controller class']) {
+      $controller = new $info['rules controller class']($type);
+      $items += $controller->eventInfo();
+    }
+  }
+  return $items;
+}
+
+/**
+ * Rules integration access callback.
+ */
+function entity_rules_integration_event_access($type, $event_name) {
+  // Cut of _insert/_update/.. from the event name.
+  $entity_type = substr($event_name, 0, strrpos($event_name, '_'));
+
+  $result = entity_access('view', $entity_type);
+  // If no access callback is given, just grant access for viewing.
+  return isset($result) ? $result : TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1672 @@
+<?php
+
+/**
+ * @file
+ * Entity CRUD API tests.
+ */
+
+/**
+ * Common parent class containing common helpers.
+ */
+abstract class EntityWebTestCase extends DrupalWebTestCase {
+
+  /**
+   * Creates a new vocabulary.
+   */
+  protected function createVocabulary() {
+    $vocab = entity_create('taxonomy_vocabulary', array(
+      'name' => $this->randomName(),
+      'machine_name' => drupal_strtolower($this->randomName()),
+      'description' => $this->randomName(),
+    ));
+    entity_save('taxonomy_vocabulary', $vocab);
+    return $vocab;
+  }
+
+  /**
+   * Creates a random file of the given type.
+   */
+  protected function createFile($file_type = 'text') {
+    // Create a managed file.
+    $file = current($this->drupalGetTestFiles($file_type));
+
+    // Set additional file properties and save it.
+    $file->filemime = file_get_mimetype($file->filename);
+    $file->uid = 1;
+    $file->timestamp = REQUEST_TIME;
+    $file->filesize = filesize($file->uri);
+    $file->status = 0;
+    file_save($file);
+    return $file;
+  }
+}
+
+/**
+ * Test basic API.
+ */
+class EntityAPITestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity CRUD',
+      'description' => 'Tests basic CRUD API functionality.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity', 'entity_test');
+  }
+
+  /**
+   * Tests CRUD.
+   */
+  function testCRUD() {
+    module_enable(array('entity_feature'));
+
+    $user1 = $this->drupalCreateUser();
+    // Create test entities for the user1 and unrelated to a user.
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
+    $entity->save();
+    $entity = entity_create('entity_test', array('name' => 'test2', 'uid' => $user1->uid));
+    $entity->save();
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
+    $entity->save();
+
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test')));
+
+    $this->assertEqual($entities[0]->name, 'test', 'Created and loaded entity.');
+    $this->assertEqual($entities[1]->name, 'test', 'Created and loaded entity.');
+
+    $results = entity_test_load_multiple(array($entity->pid));
+    $loaded = array_pop($results);
+    $this->assertEqual($loaded->pid, $entity->pid, 'Loaded the entity unrelated to a user.');
+
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
+    $entities[0]->delete();
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
+    $this->assertEqual($entities, array(), 'Entity successfully deleted.');
+
+    $entity->save();
+    $this->assertEqual($entity->pid, $loaded->pid, 'Entity successfully updated.');
+
+    // Try deleting multiple test entities by deleting all.
+    $pids = array_keys(entity_test_load_multiple(FALSE));
+    entity_test_delete_multiple($pids);
+  }
+
+  /**
+   * Tests CRUD for entities supporting revisions.
+   */
+  function testCRUDRevisisions() {
+    module_enable(array('entity_feature'));
+
+    // Add text field to entity.
+    $field_info = array(
+      'field_name' => 'field_text',
+      'type' => 'text',
+      'entity_types' => array('entity_test2'),
+    );
+    field_create_field($field_info);
+
+    $instance = array(
+      'label' => 'Text Field',
+      'field_name' => 'field_text',
+      'entity_type' => 'entity_test2',
+      'bundle' => 'entity_test2',
+      'settings' => array(),
+      'required' => FALSE,
+    );
+    field_create_instance($instance);
+
+    // Create a test entity.
+    $entity_first_revision = entity_create('entity_test2', array('title' => 'first revision', 'name' => 'main', 'uid' => 1));
+    $entity_first_revision->field_text[LANGUAGE_NONE][0]['value'] = 'first revision text';
+    entity_save('entity_test2', $entity_first_revision);
+
+    $entities = array_values(entity_load('entity_test2', FALSE));
+    $this->assertEqual(count($entities), 1, 'Entity created.');
+    $this->assertTrue($entities[0]->default_revision, 'Initial entity revision is marked as default revision.');
+
+    // Saving the entity in revision mode should create a new revision.
+    $entity_second_revision = clone $entity_first_revision;
+    $entity_second_revision->title = 'second revision';
+    $entity_second_revision->is_new_revision = TRUE;
+    $entity_second_revision->default_revision = TRUE;
+    $entity_second_revision->field_text[LANGUAGE_NONE][0]['value'] = 'second revision text';
+
+    entity_save('entity_test2', $entity_second_revision);
+    $this->assertNotEqual($entity_second_revision->revision_id, $entity_first_revision->revision_id, 'Saving an entity in new revision mode creates a revision.');
+    $this->assertTrue($entity_second_revision->default_revision, 'New entity revision is marked as default revision.');
+
+    // Check the saved entity.
+    $entity = current(entity_load('entity_test2', array($entity_first_revision->pid), array(), TRUE));
+    $this->assertNotEqual($entity->title, $entity_first_revision->title, 'Default revision was changed.');
+
+    // Create third revision that is not default.
+    $entity_third_revision = clone $entity_first_revision;
+    $entity_third_revision->title = 'third revision';
+    $entity_third_revision->is_new_revision = TRUE;
+    $entity_third_revision->default_revision = FALSE;
+    $entity_third_revision->field_text[LANGUAGE_NONE][0]['value'] = 'third revision text';
+    entity_save('entity_test2', $entity_third_revision);
+    $this->assertNotEqual($entity_second_revision->revision_id, $entity_third_revision->revision_id, 'Saving an entity in revision mode creates a revision.');
+    $this->assertFalse($entity_third_revision->default_revision, 'Entity revision is not marked as default revision.');
+
+    $entity = current(entity_load('entity_test2', array($entity_first_revision->pid), array(), TRUE));
+    $this->assertEqual($entity->title, $entity_second_revision->title, 'Default revision was not changed.');
+    $this->assertEqual($entity->field_text[LANGUAGE_NONE][0]['value'], $entity_second_revision->field_text[LANGUAGE_NONE][0]['value'], 'Default revision text field was not changed.');
+
+    // Load not default revision.
+    $revision = entity_revision_load('entity_test2', $entity_third_revision->revision_id);
+    $this->assertEqual($revision->revision_id, $entity_third_revision->revision_id, 'Revision successfully loaded.');
+    $this->assertFalse($revision->default_revision, 'Entity revision is not marked as default revision after loading.');
+
+    // Save not default revision.
+    $entity_third_revision->title = 'third revision updated';
+    $entity_third_revision->field_text[LANGUAGE_NONE][0]['value'] = 'third revision text updated';
+    entity_save('entity_test2', $entity_third_revision);
+
+    // Ensure that not default revision has been changed.
+    $entity = entity_revision_load('entity_test2', $entity_third_revision->revision_id);
+    $this->assertEqual($entity->title, 'third revision updated', 'Not default revision was updated successfully.');
+    $this->assertEqual($entity->field_text[LANGUAGE_NONE][0]['value'], 'third revision text updated', 'Not default revision field was updated successfully.');
+
+    // Ensure that default revision has not been changed.
+    $entity = current(entity_load('entity_test2', array($entity_first_revision->pid), array(), TRUE));
+    $this->assertEqual($entity->title, $entity_second_revision->title, 'Default revision was not changed.');
+
+    // Try to delete default revision.
+    $result = entity_revision_delete('entity_test2', $entity_second_revision->revision_id);
+    $this->assertFalse($result, 'Default revision cannot be deleted.');
+
+    // Make sure default revision is still set after trying to delete it.
+    $entity = current(entity_load('entity_test2', array($entity_first_revision->pid), array(), TRUE));
+    $this->assertEqual($entity->revision_id, $entity_second_revision->revision_id, 'Second revision is still default.');
+
+    // Delete first revision.
+    $result = entity_revision_delete('entity_test2', $entity_first_revision->revision_id);
+    $this->assertTrue($result, 'Not default revision deleted.');
+
+    $entity = entity_revision_load('entity_test2', $entity_first_revision->revision_id);
+    $this->assertFalse($entity, 'First revision deleted.');
+
+    // Delete the entity and make sure third revision has been deleted as well.
+    entity_delete('entity_test2', $entity_second_revision->pid);
+    $entity_info = entity_get_info('entity_test2');
+    $result = db_select($entity_info['revision table'])
+      ->condition('revision_id', $entity_third_revision->revision_id)
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+    $this->assertEqual($result, 0, 'Entity deleted with its all revisions.');
+  }
+
+  /**
+   * Tests CRUD API functions: entity_(create|delete|save)
+   */
+  function testCRUDAPIfunctions() {
+    module_enable(array('entity_feature'));
+
+    $user1 = $this->drupalCreateUser();
+    // Create test entities for the user1 and unrelated to a user.
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
+    entity_save('entity_test', $entity);
+    $entity = entity_create('entity_test', array('name' => 'test2', 'uid' => $user1->uid));
+    entity_save('entity_test', $entity);
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => NULL));
+    entity_save('entity_test', $entity);
+
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test')));
+    $this->assertEqual($entities[0]->name, 'test', 'Created and loaded entity.');
+    $this->assertEqual($entities[1]->name, 'test', 'Created and loaded entity.');
+
+    // Test getting the entity label, which is the used test-type's label.
+    $label = entity_label('entity_test', $entities[0]);
+    $this->assertEqual($label, 'label', 'Default label returned.');
+
+    $results = entity_test_load_multiple(array($entity->pid));
+    $loaded = array_pop($results);
+    $this->assertEqual($loaded->pid, $entity->pid, 'Loaded the entity unrelated to a user.');
+
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
+
+    entity_delete('entity_test', $entities[0]->pid);
+    $entities = array_values(entity_test_load_multiple(FALSE, array('name' => 'test2')));
+    $this->assertEqual($entities, array(), 'Entity successfully deleted.');
+
+    entity_save('entity_test', $entity);
+    $this->assertEqual($entity->pid, $loaded->pid, 'Entity successfully updated.');
+
+    // Try deleting multiple test entities by deleting all.
+    $pids = array_keys(entity_test_load_multiple(FALSE));
+    entity_delete_multiple('entity_test', $pids);
+  }
+
+  /**
+   * Test loading entities defined in code.
+   */
+  function testExportables() {
+    module_enable(array('entity_feature'));
+
+    $types = entity_load_multiple_by_name('entity_test_type', array('test2', 'test'));
+
+    $this->assertEqual(array_keys($types), array('test2', 'test'), 'Entities have been loaded in the order as specified.');
+    $this->assertEqual($types['test']->label, 'label', 'Default type loaded.');
+    $this->assertTrue($types['test']->status & ENTITY_IN_CODE && !($types['test']->status & ENTITY_CUSTOM), 'Default type status is correct.');
+
+    // Test using a condition, which has to be applied on the defaults.
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'label'));
+    $this->assertEqual($types['test']->label, 'label', 'Condition to default type applied.');
+
+    $types['test']->label = 'modified';
+    $types['test']->save();
+
+    // Ensure loading the changed entity works.
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'modified'));
+    $this->assertEqual($types['test']->label, 'modified', 'Modified type loaded.');
+
+    // Clear the cache to simulate a new page load.
+    entity_get_controller('entity_test_type')->resetCache();
+
+    // Test loading using a condition again, now they default may not appear any
+    // more as it's overridden by an entity with another label.
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'label'));
+    $this->assertTrue(empty($types), 'Conditions are applied to the overridden entity only.');
+
+    // But the overridden entity has to appear with another condition.
+    $types = entity_load_multiple_by_name('entity_test_type', FALSE, array('label' => 'modified'));
+    $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by condition.');
+
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
+    $this->assertEqual($types['test']->label, 'modified', 'Modified default type loaded by id.');
+    $this->assertTrue(entity_has_status('entity_test_type', $types['test'], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
+
+    // Test rebuilding the defaults and make sure overridden entities stay.
+    entity_defaults_rebuild();
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
+    $this->assertEqual($types['test']->label, 'modified', 'Overridden entity is still overridden.');
+    $this->assertTrue(entity_has_status('entity_test_type', $types['test'], ENTITY_OVERRIDDEN), 'Status of overridden type is correct.');
+
+    // Test reverting.
+    $types['test']->delete();
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
+    $this->assertEqual($types['test']->label, 'label', 'Entity has been reverted.');
+
+    // Test loading an exportable by its numeric id.
+    $result = entity_load_multiple_by_name('entity_test_type', array($types['test']->id));
+    $this->assertTrue(isset($result['test']), 'Exportable entity loaded by the numeric id.');
+
+    // Test exporting an entity to JSON.
+    $serialized_string = $types['test']->export();
+    $data = drupal_json_decode($serialized_string);
+    $this->assertNotNull($data, 'Exported entity is valid JSON.');
+    $import = entity_import('entity_test_type', $serialized_string);
+    $this->assertTrue(get_class($import) == get_class($types['test']) && $types['test']->label == $import->label, 'Successfully exported entity to code.');
+    $this->assertTrue(!isset($import->status), 'Exportable status has not been exported to code.');
+
+    // Test disabling the module providing the defaults in code.
+    $types = entity_load_multiple_by_name('entity_test_type', array('test', 'test2'));
+    $types['test']->label = 'modified';
+    $types['test']->save();
+
+    module_disable(array('entity_feature'));
+
+    // Make sure the overridden entity stays and the other one is deleted.
+    entity_get_controller('entity_test_type')->resetCache();
+    $test = entity_load_single('entity_test_type', 'test');
+    $this->assertTrue(!empty($test) && $test->label == 'modified', 'Overidden entity is still available.');
+    $this->assertTrue(!empty($test) && !entity_has_status('entity_test_type', $test, ENTITY_IN_CODE) && entity_has_status('entity_test_type', $test, ENTITY_CUSTOM), 'Overidden entity is now marked as custom.');
+
+    $test2 = entity_load_single('entity_test_type', 'test2');
+    $this->assertFalse($test2, 'Default entity has disappeared.');
+  }
+
+  /**
+   * Make sure insert() and update() hooks for exportables are invoked.
+   */
+  function testExportableHooks() {
+    $_SESSION['entity_hook_test'] = array();
+    // Enabling the module should invoke the enabled hook for the other
+    // entities provided in code.
+    module_enable(array('entity_feature'));
+
+    $insert = array('main', 'test', 'test2');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_insert'] == $insert, 'Hook entity_insert has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_insert'] == $insert, 'Hook entity_test_type_insert has been invoked.');
+
+    // Load a default entity and make sure the rebuilt logic only ran once.
+    entity_load_single('entity_test_type', 'test');
+    $this->assertTrue(!isset($_SESSION['entity_hook_test']['entity_test_type_update']), '"Entity-test-type" defaults have been rebuilt only once.');
+
+    // Add a new test entity in DB and make sure the hook is invoked too.
+    $test3 = entity_create('entity_test_type', array(
+      'name' => 'test3',
+      'label' => 'label',
+      'weight' => 0,
+    ));
+    $test3->save();
+
+    $insert[] = 'test3';
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_insert'] == $insert, 'Hook entity_insert has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_insert'] == $insert, 'Hook entity_test_type_insert has been invoked.');
+
+    // Now override the 'test' entity and make sure it invokes the update hook.
+    $result = entity_load_multiple_by_name('entity_test_type', array('test'));
+    $result['test']->label = 'modified';
+    $result['test']->save();
+
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_update'] == array('test'), 'Hook entity_update has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_update'] == array('test'), 'Hook entity_test_type_update has been invoked.');
+
+    // 'test' has to remain enabled, as it has been overridden.
+    $delete = array('main', 'test2');
+    module_disable(array('entity_feature'));
+
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_delete'] == $delete, 'Hook entity_deleted has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_delete'] == $delete, 'Hook entity_test_type_deleted has been invoked.');
+
+    // Now make sure 'test' is not overridden any more, but custom.
+    $result = entity_load_multiple_by_name('entity_test_type', array('test'));
+    $this->assertTrue(!$result['test']->hasStatus(ENTITY_OVERRIDDEN), 'Entity is not marked as overridden any more.');
+    $this->assertTrue(entity_has_status('entity_test_type', $result['test'], ENTITY_CUSTOM), 'Entity is marked as custom.');
+
+    // Test deleting the remaining entities from DB.
+    entity_delete_multiple('entity_test_type', array('test', 'test3'));
+    $delete[] = 'test';
+    $delete[] = 'test3';
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_delete'] == $delete, 'Hook entity_deleted has been invoked.');
+    $this->assertTrue($_SESSION['entity_hook_test']['entity_test_type_delete'] == $delete, 'Hook entity_test_type_deleted has been invoked.');
+  }
+
+  /**
+   * Tests determining changes.
+   */
+  function testChanges() {
+    module_enable(array('entity_feature'));
+    $types = entity_load_multiple_by_name('entity_test_type');
+
+    // Override the default entity, such it gets saved in the DB.
+    $types['test']->label ='test_changes';
+    $types['test']->save();
+
+    // Now test an update without applying any changes.
+    $types['test']->save();
+    $this->assertEqual($types['test']->label, 'test_changes', 'No changes have been determined.');
+
+    // Apply changes.
+    $types['test']->label = 'updated';
+    $types['test']->save();
+
+    // The hook implementations entity_test_entity_test_type_presave() and
+    // entity_test_entity_test_type_update() determine changes and change the
+    // label.
+    $this->assertEqual($types['test']->label, 'updated_presave_update', 'Changes have been determined.');
+
+    // Test the static load cache to be cleared.
+    $types = entity_load_multiple_by_name('entity_test_type');
+    $this->assertEqual($types['test']->label, 'updated_presave', 'Static cache has been cleared.');
+  }
+
+
+  /**
+   * Tests viewing entites.
+   */
+  function testRendering() {
+    module_enable(array('entity_feature'));
+
+    $user1 = $this->drupalCreateUser();
+    // Create test entities for the user1 and unrelated to a user.
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
+
+    $render = $entity->view();
+    $output = drupal_render($render);
+    // The entity class adds the user name to the output. Verify it is there.
+    $this->assertTrue(strpos($output, format_username($user1)) !== FALSE, 'Entity has been rendered');
+  }
+
+  /**
+   * Test uninstall of the entity_test module.
+   */
+  function testUninstall() {
+    // Add a test type and add a field instance, uninstall, then re-install and
+    // make sure the field instance can be re-created.
+    $test_type = entity_create('entity_test_type', array(
+      'name' => 'test',
+      'label' => 'label',
+      'weight' => 0,
+    ));
+    $test_type->save();
+
+    $field = array(
+      'field_name' => 'field_test_fullname',
+      'type' => 'text',
+      'cardinality' => 1,
+      'translatable' => FALSE,
+    );
+    field_create_field($field);
+
+    $instance = array(
+      'entity_type' => 'entity_test',
+      'field_name' => 'field_test_fullname',
+      'bundle' => 'test',
+      'label' => 'Full name',
+      'description' => 'Specify your first and last name.',
+      'widget' => array(
+        'type' => 'text_textfield',
+        'weight' => 0,
+      ),
+    );
+    field_create_instance($instance);
+
+    // Uninstallation has to remove all bundles, thus also field instances.
+    module_disable(array('entity_test'));
+    require_once DRUPAL_ROOT . '/includes/install.inc';
+    drupal_uninstall_modules(array('entity_test'));
+
+    // Make sure the instance has been deleted.
+    $instance_read = field_read_instance('entity_test', 'field_test_fullname', 'test', array('include_inactive' => 1));
+    $this->assertFalse((bool) $instance_read, 'Field instance has been deleted.');
+
+    // Ensure re-creating the same instance now works.
+    module_enable(array('entity_test'));
+    $test_type = entity_create('entity_test_type', array(
+      'name' => 'test',
+      'label' => 'label',
+      'weight' => 0,
+    ));
+    $test_type->save();
+    field_create_field($field);
+    field_create_instance($instance);
+
+    $instance_read = field_info_instance('entity_test', 'field_test_fullname', 'test');
+    $this->assertTrue((bool) $instance_read, 'Field instance has been re-created.');
+  }
+}
+
+/**
+ * Test the generated Rules integration.
+ */
+class EntityAPIRulesIntegrationTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity CRUD Rules integration',
+      'description' => 'Tests the Rules integration provided by the Entity CRUD API.',
+      'group' => 'Entity API',
+      'dependencies' => array('rules'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity', 'entity_test', 'rules');
+    // Make sure the logger is enabled so the debug log is saved.
+    variable_set('rules_debug_log', 1);
+  }
+
+  /**
+   * Test the events.
+   */
+  function testEvents() {
+    $rule = rules_reaction_rule();
+    $rule->event('entity_test_presave');
+    $rule->event('entity_test_insert');
+    $rule->event('entity_test_update');
+    $rule->event('entity_test_delete');
+    $rule->action('drupal_message', array('message' => 'hello!'));
+    $rule->save();
+    rules_clear_cache(TRUE);
+
+    // Let the events occur.
+    $user1 = $this->drupalCreateUser();
+    RulesLog::logger()->clear();
+
+    $entity = entity_create('entity_test', array('name' => 'test', 'uid' => $user1->uid));
+    $entity->save();
+    $entity->name = 'update';
+    $entity->save();
+    $entity->delete();
+
+    // Now there should have been 5 events, 2 times presave and once insert,
+    // update and delete.
+    $count = substr_count(RulesLog::logger()->render(), '0 ms Reacting on event');
+    $this->assertTrue($count == 5, 'Events have been properly invoked.');
+    RulesLog::logger()->checkLog();
+  }
+}
+
+/**
+ * Tests comments with node access.
+ */
+class EntityAPICommentNodeAccessTestCase extends CommentHelperCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity API comment node access',
+      'description' => 'Test viewing comments on nodes with node access.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    DrupalWebTestCase::setUp('comment', 'entity', 'node_access_test');
+    node_access_rebuild();
+
+    // Create test node and user with simple node access permission. The
+    // 'node test view' permission is implemented and granted by the
+    // node_access_test module.
+    $this->accessUser = $this->drupalCreateUser(array('access comments', 'post comments', 'edit own comments', 'node test view'));
+    $this->noAccessUser = $this->drupalCreateUser(array('administer comments'));
+    $this->node = $this->drupalCreateNode(array('type' => 'article', 'uid' => $this->accessUser->uid));
+  }
+
+  /**
+   * Tests comment access when node access is enabled.
+   */
+  function testCommentNodeAccess() {
+    // Post comment.
+    $this->drupalLogin($this->accessUser);
+    $comment_text = $this->randomName();
+    $comment = $this->postComment($this->node, $comment_text);
+    $comment_loaded = comment_load($comment->id);
+    $this->assertTrue($this->commentExists($comment), 'Comment found.');
+    $this->drupalLogout();
+
+    // Check access to node and associated comment for access user.
+    $this->assertTrue(entity_access('view', 'node', $this->node, $this->accessUser), 'Access to view node was granted for access user');
+    $this->assertTrue(entity_access('view', 'comment', $comment_loaded, $this->accessUser), 'Access to view comment was granted for access user');
+    $this->assertTrue(entity_access('update', 'comment', $comment_loaded, $this->accessUser), 'Access to update comment was granted for access user');
+    $this->assertFalse(entity_access('delete', 'comment', $comment_loaded, $this->accessUser), 'Access to delete comment was denied for access user');
+
+    // Check access to node and associated comment for no access user.
+    $this->assertFalse(entity_access('view', 'node', $this->node, $this->noAccessUser), 'Access to view node was denied for no access user');
+    $this->assertFalse(entity_access('view', 'comment', $comment_loaded, $this->noAccessUser), 'Access to view comment was denied for no access user');
+    $this->assertFalse(entity_access('update', 'comment', $comment_loaded, $this->noAccessUser), 'Access to update comment was denied for no access user');
+    $this->assertFalse(entity_access('delete', 'comment', $comment_loaded, $this->noAccessUser), 'Access to delete comment was denied for no access user');
+  }
+}
+
+/**
+ * Test the i18n integration.
+ */
+class EntityAPIi18nItegrationTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity CRUD i18n integration',
+      'description' => 'Tests the i18n integration provided by the Entity CRUD API.',
+      'group' => 'Entity API',
+      'dependencies' => array('i18n_string'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity_test_i18n');
+    $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages'));
+    $this->drupalLogin($this->admin_user);
+    $this->addLanguage('de');
+  }
+
+  /**
+   * Copied from i18n module (class Drupali18nTestCase).
+   *
+   * We cannot extend from Drupali18nTestCase as else the test-bot would die.
+   */
+  public function addLanguage($language_code) {
+    // Check to make sure that language has not already been installed.
+    $this->drupalGet('admin/config/regional/language');
+
+    if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
+      // Doesn't have language installed so add it.
+      $edit = array();
+      $edit['langcode'] = $language_code;
+      $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
+
+      // Make sure we are not using a stale list.
+      drupal_static_reset('language_list');
+      $languages = language_list('language');
+      $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
+
+      if (array_key_exists($language_code, $languages)) {
+        $this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
+      }
+    }
+    elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $language_code . ']'))) {
+      // It's installed and enabled. No need to do anything.
+      $this->assertTrue(true, 'Language [' . $language_code . '] already installed and enabled.');
+    }
+    else {
+      // It's installed but not enabled. Enable it.
+      $this->assertTrue(true, 'Language [' . $language_code . '] already installed.');
+      $this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
+      $this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
+    }
+  }
+
+  /**
+   * Tests the provided default controller.
+   */
+  function testDefaultController() {
+    // Create test entities for the user1 and unrelated to a user.
+    $entity = entity_create('entity_test_type', array(
+      'name' => 'test',
+      'uid' => $GLOBALS['user']->uid,
+      'label' => 'label-en',
+    ));
+    $entity->save();
+
+    // Add a translation.
+    i18n_string_textgroup('entity_test')->update_translation("entity_test_type:{$entity->name}:label", 'de', 'label-de');
+
+    $default = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en');
+    $translation = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en', 'de');
+
+    $this->assertEqual($translation, 'label-de', 'Label has been translated.');
+    $this->assertEqual($default, 'label-en', 'Default label retrieved.');
+
+    // Test the helper method.
+    $translation = $entity->getTranslation('label', 'de');
+    $default = $entity->getTranslation('label');
+    $this->assertEqual($translation, 'label-de', 'Label has been translated via the helper method.');
+    $this->assertEqual($default, 'label-en', 'Default label retrieved via the helper method.');
+
+    // Test updating and make sure the translation stays.
+    $entity->name = 'test2';
+    $entity->save();
+    $translation = $entity->getTranslation('label', 'de');
+    $this->assertEqual($translation, 'label-de', 'Translation survives a name change.');
+
+    // Test using the wrapper to retrieve a translation.
+    $wrapper = entity_metadata_wrapper('entity_test_type', $entity);
+    $translation = $wrapper->language('de')->label->value();
+    $this->assertEqual($translation, 'label-de', 'Translation retrieved via the wrapper.');
+
+    // Test deleting.
+    $entity->delete();
+    $translation = entity_i18n_string("entity_test:entity_test_type:{$entity->name}:label", 'label-en', 'de');
+    $this->assertEqual($translation, 'label-en', 'Translation has been deleted.');
+  }
+}
+
+/**
+ * Tests metadata wrappers.
+ */
+class EntityMetadataTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Metadata Wrapper',
+      'description' => 'Makes sure metadata wrapper are working right.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity', 'entity_test', 'locale');
+    // Create a field having 4 values for testing multiple value support.
+    $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $this->field = array('field_name' => $this->field_name, 'type' => 'text', 'cardinality' => 4);
+    $this->field = field_create_field($this->field);
+    $this->field_id = $this->field['id'];
+    $this->instance = array(
+      'field_name' => $this->field_name,
+      'entity_type' => 'node',
+      'bundle' => 'page',
+      'label' => $this->randomName() . '_label',
+      'description' => $this->randomName() . '_description',
+      'weight' => mt_rand(0, 127),
+      'settings' => array(
+        'text_processing' => FALSE,
+      ),
+      'widget' => array(
+        'type' => 'text_textfield',
+        'label' => 'Test Field',
+        'settings' => array(
+          'size' => 64,
+        )
+      )
+    );
+    field_create_instance($this->instance);
+
+    // Make the body field and the node type 'page' translatable.
+    $field = field_info_field('body');
+    $field['translatable'] = TRUE;
+    field_update_field($field);
+    variable_set('language_content_type_page', 1);
+  }
+
+  /**
+   * Creates a user and a node, then tests getting the properties.
+   */
+  function testEntityMetadataWrapper() {
+    $account = $this->drupalCreateUser();
+    // For testing sanitizing give the user a malicious user name
+    $account = user_save($account, array('name' => '<b>BadName</b>'));
+    $title = '<b>Is it bold?<b>';
+    $body[LANGUAGE_NONE][0] = array('value' => '<b>The body & nothing.</b>', 'summary' => '<b>The body.</b>');
+    $node = $this->drupalCreateNode(array('uid' => $account->uid, 'name' => $account->name, 'body' => $body, 'title' => $title, 'summary' => '', 'type' => 'page'));
+
+    // First test without sanitizing.
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual('<b>Is it bold?<b>', $wrapper->title->value(), 'Getting a field value.');
+    $this->assertEqual($node->title, $wrapper->title->raw(), 'Getting a raw property value.');
+
+    // Test chaining.
+    $this->assertEqual($account->mail, $wrapper->author->mail->value(), 'Testing chained usage.');
+    $this->assertEqual($account->name, $wrapper->author->name->value(), 'Testing chained usage with callback and sanitizing.');
+
+    // Test sanitized output.
+    $options = array('sanitize' => TRUE);
+    $this->assertEqual(check_plain('<b>Is it bold?<b>'), $wrapper->title->value($options), 'Getting sanitized field.');
+    $this->assertEqual(filter_xss($node->name), $wrapper->author->name->value($options), 'Getting sanitized property with getter callback.');
+
+    // Test getting an not existing property.
+    try {
+      echo $wrapper->dummy;
+      $this->fail('Getting an not existing property.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Getting an not existing property.');
+    }
+
+    // Test setting.
+    $wrapper->author = 0;
+    $this->assertEqual(0, $wrapper->author->uid->value(), 'Setting a property.');
+    try {
+      $wrapper->url = 'dummy';
+      $this->fail('Setting an unsupported property.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Setting an unsupported property.');
+    }
+
+    // Test value validation.
+    $this->assertFalse($wrapper->author->name->validate(array(3)), 'Validation correctly checks for valid data types.');
+    try {
+      $wrapper->author->mail = 'foo';
+      $this->fail('An invalid mail address has been set.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Setting an invalid mail address throws exception.');
+    }
+    // Test unsetting a required property.
+    try {
+      $wrapper->author = NULL;
+      $this->fail('The required node author has been unset.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Unsetting the required node author throws an exception.');
+    }
+
+    // Test setting a referenced entity by id.
+    $wrapper->author->set($GLOBALS['user']->uid);
+    $this->assertEqual($wrapper->author->getIdentifier(), $GLOBALS['user']->uid, 'Get the identifier of a referenced entity.');
+    $this->assertEqual($wrapper->author->uid->value(), $GLOBALS['user']->uid, 'Successfully set referenced entity using the identifier.');
+    // Set by object.
+    $wrapper->author->set($GLOBALS['user']);
+    $this->assertEqual($wrapper->author->uid->value(), $GLOBALS['user']->uid, 'Successfully set referenced entity using the entity.');
+
+
+    // Test getting by the field API processed values like the node body.
+    $body_value = $wrapper->body->value;
+    $this->assertEqual("<p>The body &amp; nothing.</p>\n", $body_value->value(), "Getting processed value.");
+    $this->assertEqual("The body & nothing.\n", $body_value->value(array('decode' => TRUE)), "Decoded value.");
+    $this->assertEqual("<b>The body & nothing.</b>", $body_value->raw(), "Raw body returned.");
+
+    // Test getting the summary.
+    $this->assertEqual("<p>The body.</p>\n", $wrapper->body->summary->value(), "Getting body summary.");
+
+    $wrapper->body->set(array('value' => "<b>The second body.</b>"));
+    $this->assertEqual("<p>The second body.</p>\n", $wrapper->body->value->value(), "Setting a processed field value and reading it again.");
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], "<b>The second body.</b>", 'Update appears in the wrapped entity.');
+    $this->assert(isset($node->body[LANGUAGE_NONE][0]['safe_value']), 'Formatted text has been processed.');
+
+    // Test translating the body on an English node.
+    locale_add_language('de');
+    $body['en'][0] = array('value' => '<b>English body.</b>', 'summary' => '<b>The body.</b>');
+    $node = $this->drupalCreateNode(array('body' => $body, 'language' => 'en', 'type' => 'page'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->language('de');
+
+    $languages = language_list();
+    $this->assertEqual($wrapper->getPropertyLanguage(), $languages['de'], 'Wrapper language has been set to German');
+    $this->assertEqual($wrapper->body->value->value(), "<p>English body.</p>\n", 'Language fallback on default language.');
+
+    // Set a German text using the wrapper.
+    $wrapper->body->set(array('value' => "<b>Der zweite Text.</b>"));
+    $this->assertEqual($wrapper->body->value->value(), "<p>Der zweite Text.</p>\n", 'German body set and retrieved.');
+
+    $wrapper->language(LANGUAGE_NONE);
+    $this->assertEqual($wrapper->body->value->value(), "<p>English body.</p>\n", 'Default language text is still there.');
+
+    // Test iterator.
+    $type_info = entity_get_property_info('node');
+    $this->assertFalse(array_diff_key($type_info['properties'], iterator_to_array($wrapper->getIterator())), 'Iterator is working.');
+    foreach ($wrapper as $property) {
+      $this->assertTrue($property instanceof EntityMetadataWrapper, 'Iterate over wrapper properties.');
+    }
+
+    // Test setting a new node.
+    $node->title = 'foo';
+    $wrapper->set($node);
+    $this->assertEqual($wrapper->title->value(), 'foo', 'Changed the wrapped node.');
+
+    // Test getting options lists.
+    $this->assertEqual($wrapper->type->optionsList(), node_type_get_names(), 'Options list returned.');
+
+    // Test making use of a generic 'entity' reference property the
+    // 'entity_test' module provides. The property defaults to the node author.
+    $this->assertEqual($wrapper->reference->uid->value(), $wrapper->author->getIdentifier(), 'Used generic entity reference property.');
+    // Test updating a property of the generic entity reference.
+    $wrapper->reference->name->set('foo');
+    $this->assertEqual($wrapper->reference->name->value(), 'foo', 'Updated property of generic entity reference');
+    // For testing, just point the reference to the node itself now.
+    $wrapper->reference->set($wrapper);
+    $this->assertEqual($wrapper->reference->nid->value(), $wrapper->getIdentifier(), 'Correctly updated the generic entity referenced property.');
+
+    // Test saving and deleting.
+    $wrapper->save();
+    $wrapper->delete();
+    $return = node_load($wrapper->getIdentifier());
+    $this->assertFalse($return, "Node has been successfully deleted.");
+
+    // Ensure changing the bundle changes available wrapper properties.
+    $wrapper->type->set('article');
+    $this->assertTrue(isset($wrapper->field_tags), 'Changing bundle changes available wrapper properties.');
+
+    // Test labels.
+    $user = $this->drupalCreateUser();
+    user_save($user, array('roles' => array()));
+    $wrapper->author = $user->uid;
+    $this->assertEqual($wrapper->label(), $node->title, 'Entity label returned.');
+    $this->assertEqual($wrapper->author->roles[0]->label(), t('authenticated user'), 'Label from options list returned');
+    $this->assertEqual($wrapper->author->roles->label(), t('authenticated user'), 'Label for a list from options list returned');
+  }
+
+  /**
+   * Test supporting multi-valued fields.
+   */
+  function testListMetadataWrappers() {
+    $property = $this->field_name;
+    $values = array();
+    $values[LANGUAGE_NONE][0] = array('value' => '<b>2009-09-05</b>');
+    $values[LANGUAGE_NONE][1] = array('value' => '2009-09-05');
+    $values[LANGUAGE_NONE][2] = array('value' => '2009-08-05');
+
+    $node = $this->drupalCreateNode(array('type' => 'page', $property => $values));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual('<b>2009-09-05</b>', $wrapper->{$property}[0]->value(), 'Getting array entry.');
+    $this->assertEqual('2009-09-05', $wrapper->{$property}->get(1)->value(), 'Getting array entry.');
+    $this->assertEqual(3, count($wrapper->{$property}->value()), 'Getting the whole array.');
+
+    // Test sanitizing
+    $this->assertEqual(check_plain('<b>2009-09-05</b>'), $wrapper->{$property}[0]->value(array('sanitize' => TRUE)), 'Getting array entry.');
+
+    // Test iterator
+    $this->assertEqual(array_keys(iterator_to_array($wrapper->$property->getIterator())), array_keys($wrapper->$property->value()), 'Iterator is working.');
+    foreach ($wrapper->$property as $p) {
+      $this->assertTrue($p instanceof EntityMetadataWrapper, 'Iterate over list wrapper properties.');
+    }
+
+    // Make sure changing the array changes the actual entity property.
+    $wrapper->{$property}[0] = '2009-10-05';
+    unset($wrapper->{$property}[1], $wrapper->{$property}[2]);
+    $this->assertEqual($wrapper->{$property}->value(), array('2009-10-05'), 'Setting multiple property values.');
+
+    // Test setting an arbitrary list item.
+    $list = array(0 => REQUEST_TIME);
+    $wrapper = entity_metadata_wrapper('list<date>', $list);
+    $wrapper[1] = strtotime('2009-09-05');
+    $this->assertEqual($wrapper->value(), array(REQUEST_TIME, strtotime('2009-09-05')), 'Setting a list item.');
+    $this->assertEqual($wrapper->count(), 2, 'List count is correct.');
+
+    // Test using a list wrapper without data.
+    $wrapper = entity_metadata_wrapper('list<date>');
+    $info = array();
+    foreach ($wrapper as $item) {
+      $info[] = $item->info();
+    }
+    $this->assertTrue($info[0]['type'] == 'date', 'Iterated over empty list wrapper.');
+
+    // Test using a list of entities with a list of term objects.
+    $list = array();
+    $list[] = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => 'term 1',
+      'vocabulary' => 1,
+    ))->save()->value();
+    $list[] = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => 'term 2',
+      'vocabulary' => 1,
+    ))->save()->value();
+    $wrapper = entity_metadata_wrapper('list<taxonomy_term>', $list);
+    $this->assertTrue($wrapper[0]->name->value() == 'term 1', 'Used a list of entities.');
+    // Test getting a list of identifiers.
+    $ids = $wrapper->value(array('identifier' => TRUE));
+    $this->assertTrue(!is_object($ids[0]), 'Get a list of entity ids.');
+
+    $wrapper = entity_metadata_wrapper('list<taxonomy_term>', $ids);
+    $this->assertTrue($wrapper[0]->name->value() == 'term 1', 'Created a list of entities with ids.');
+
+    // Test with a list of generic entities. The list is expected to be a list
+    // of entity wrappers, otherwise the entity type is unknown.
+    $node = $this->drupalCreateNode(array('title' => 'node 1'));
+    $list = array();
+    $list[] = entity_metadata_wrapper('node', $node);
+    $wrapper = entity_metadata_wrapper('list<entity>', $list);
+    $this->assertEqual($wrapper[0]->title->value(), 'node 1', 'Wrapped node was found in generic list of entities.');
+  }
+
+  /**
+   * Tests using the wrapper without any data.
+   */
+  function testWithoutData() {
+    $wrapper = entity_metadata_wrapper('node', NULL, array('bundle' => 'page'));
+    $this->assertTrue(isset($wrapper->title), 'Bundle properties have been added.');
+    $info = $wrapper->author->mail->info();
+    $this->assertTrue(!empty($info) && is_array($info) && isset($info['label']), 'Property info returned.');
+  }
+
+  /**
+   * Test using access() method.
+   */
+  function testAccess() {
+    // Test without data.
+    $account = $this->drupalCreateUser(array('bypass node access'));
+    $this->assertTrue(entity_access('view', 'node', NULL, $account), 'Access without data checked.');
+
+    // Test with actual data.
+    $values[LANGUAGE_NONE][0] = array('value' => '<b>2009-09-05</b>');
+    $values[LANGUAGE_NONE][1] = array('value' => '2009-09-05');
+    $node = $this->drupalCreateNode(array('type' => 'page', $this->field_name => $values));
+    $this->assertTrue(entity_access('delete', 'node', $node, $account), 'Access with data checked.');
+
+    // Test per property access without data.
+    $account2 = $this->drupalCreateUser(array('bypass node access', 'administer nodes'));
+    $wrapper = entity_metadata_wrapper('node', NULL, array('bundle' => 'page'));
+    $this->assertTrue($wrapper->access('edit', $account), 'Access to node granted.');
+    $this->assertFalse($wrapper->status->access('edit', $account), 'Access for admin property denied.');
+    $this->assertTrue($wrapper->status->access('edit', $account2), 'Access for admin property allowed for the admin.');
+
+    // Test per property access with data.
+    $wrapper = entity_metadata_wrapper('node', $node, array('bundle' => 'page'));
+    $this->assertFalse($wrapper->status->access('edit', $account), 'Access for admin property denied.');
+    $this->assertTrue($wrapper->status->access('edit', $account2), 'Access for admin property allowed for the admin.');
+
+    // Test field level access.
+    $this->assertTrue($wrapper->{$this->field_name}->access('view'), 'Field access granted.');
+  }
+
+  /**
+   * Tests using a data structure with passed in metadata.
+   */
+  function testDataStructureWrapper() {
+    $log_entry = array(
+      'type'        => 'entity',
+      'message'     => $this->randomName(8),
+      'variables'   => array(),
+      'severity'    => WATCHDOG_NOTICE,
+      'link'        => '',
+      'user'        => $GLOBALS['user'],
+    );
+    $info['property info'] = array(
+      'type' => array('type' => 'text', 'label' => 'The category to which this message belongs.'),
+      'message' => array('type' => 'text', 'label' => 'The log message.'),
+      'user' => array('type' => 'user', 'label' => 'The user causing the log entry.'),
+    );
+    $wrapper = entity_metadata_wrapper('log_entry', $log_entry, $info);
+    $this->assertEqual($wrapper->user->name->value(), $GLOBALS['user']->name, 'Wrapped custom entity.');
+  }
+
+  /**
+   * Tests using entity_property_query().
+   */
+  function testEntityQuery() {
+    // Creat a test node.
+    $title = '<b>Is it bold?<b>';
+    $values[LANGUAGE_NONE][0] = array('value' => 'foo');
+    $node = $this->drupalCreateNode(array($this->field_name => $values, 'title' => $title, 'uid' => $GLOBALS['user']->uid));
+
+    $results = entity_property_query('node', 'title', $title);
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given title.');
+
+    $results = entity_property_query('node', $this->field_name, 'foo');
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given field value.');
+
+    $results = entity_property_query('node', $this->field_name, array('foo', 'bar'));
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a list of possible values.');
+
+    $results = entity_property_query('node', 'author', $GLOBALS['user']);
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given auhtor.');
+
+    // Create another test node and try querying for tags.
+    $tag = entity_property_values_create_entity('taxonomy_term', array(
+          'name' => $this->randomName(),
+          'vocabulary' => 1,
+    ))->save();
+    $field_tag_value[LANGUAGE_NONE][0]['tid'] = $tag->getIdentifier();
+    $node = $this->drupalCreateNode(array('type' => 'article', 'field_tags' => $field_tag_value));
+
+    // Try query-ing with a single value.
+    $results = entity_property_query('node', 'field_tags', $tag->getIdentifier());
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given term id.');
+
+    $results = entity_property_query('node', 'field_tags', $tag->value());
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a given term object.');
+
+    // Try query-ing with a list of possible values.
+    $results = entity_property_query('node', 'field_tags', array($tag->getIdentifier()));
+    $this->assertEqual($results, array($node->nid), 'Queried nodes with a list of term ids.');
+  }
+
+  /**
+   * Tests serializing data wrappers, in particular for EntityDrupalWrapper.
+   */
+  function testWrapperSerialization() {
+    $node = $this->drupalCreateNode();
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $this->assertTrue($wrapper->value() == $node, 'Data correctly wrapped.');
+
+    // Test serializing and make sure only the node id is stored.
+    $this->assertTrue(strpos(serialize($wrapper), $node->title) === FALSE, 'Node has been correctly serialized.');
+    $this->assertEqual(unserialize(serialize($wrapper))->title->value(), $node->title, 'Serializing works right.');
+
+    $wrapper2 = unserialize(serialize($wrapper));
+    // Test serializing the unloaded wrapper.
+    $this->assertEqual(unserialize(serialize($wrapper2))->title->value(), $node->title, 'Serializing works right.');
+
+    // Test loading a not more existing node.
+    $s = serialize($wrapper2);
+    node_delete($node->nid);
+    $this->assertFalse(node_load($node->nid), 'Node deleted.');
+
+    $value = unserialize($s)->value();
+    $this->assertNull($value, 'Tried to load not existing node.');
+  }
+}
+
+/**
+ * Tests provided entity property info of the core modules.
+ */
+class EntityTokenTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity tokens',
+      'description' => 'Tests provided tokens for entity properties.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity_token');
+  }
+
+  /**
+   * Tests whether token support is basically working.
+   */
+  function testTokenSupport() {
+    // Test basic tokens.
+    $node = $this->drupalCreateNode(array('sticky' => TRUE, 'promote' => FALSE));
+    $text = "Sticky: [node:sticky] Promote: [node:promote] User: [site:current-user:name]";
+    $true = t('true');
+    $false = t('false');
+    $user_name = $GLOBALS['user']->name;
+    $target = "Sticky: $true Promote: $false User: $user_name";
+    $replace = token_replace($text, array('node' => $node));
+    $this->assertEqual($replace, $target, 'Provided tokens basically work.');
+
+    // Test multiple-value tokens using the tags field of articles.
+    for ($i = 0; $i < 4; $i++) {
+      $tags[$i] = entity_property_values_create_entity('taxonomy_term', array(
+        'name' => $this->randomName(),
+        'vocabulary' => 1,
+      ))->save();
+      $field_value[LANGUAGE_NONE][$i]['tid'] = $tags[$i]->getIdentifier();
+      $labels[$i] = $tags[$i]->label();
+    }
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', 'field_tags' => $field_value));
+
+    $text = "Tags: [node:field-tags] First: [node:field-tags:0] 2nd name: [node:field-tags:1:name] 1st vocab [node:field-tags:0:vocabulary]";
+    $tag_labels = implode(', ', $labels);
+    $target = "Tags: $tag_labels First: $labels[0] 2nd name: $labels[1] 1st vocab {$tags[0]->vocabulary->label()}";
+    $replace = token_replace($text, array('node' => $node));
+    $this->assertEqual($replace, $target, 'Multiple-value token replacements have been replaced.');
+
+    // Make sure not existing values are not handled.
+    $replace = token_replace("[node:field-tags:43]", array('node' => $node));
+    $this->assertEqual($replace, "[node:field-tags:43]", 'Not existing values are not replaced.');
+
+    // Test data-structure tokens like [site:current-page:url].
+    $replace = token_replace("[site:current-page:url]", array());
+    $this->assertEqual($replace, $GLOBALS['base_root'] . request_uri(), 'Token replacements of data structure properties replaced.');
+
+    // Test chaining of data-structure tokens using an image-field.
+    $file = $this->createFile('image');
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_image = array('fid' => $file->fid);
+    $replace = token_replace("[node:field-image:file:name]", array('node' => $node));
+    $this->assertEqual($replace, $wrapper->field_image->file->name->value(), 'Token replacements of an image field have been replaced.');
+  }
+}
+
+/**
+ * Tests provided entity property info of the core modules.
+ */
+class EntityMetadataIntegrationTestCase extends EntityWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Property info core integration',
+      'description' => 'Tests using metadata wrapper for drupal core.',
+      'group' => 'Entity API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('entity', 'book', 'statistics', 'locale');
+  }
+
+  protected function assertException($wrapper, $name, $text = NULL) {
+    $this->assertTrue(isset($wrapper->$name), 'Property wrapper ' . check_plain($name) . ' exists.');
+    $text = isset($text) ? $text : 'Getting the not existing property ' . $name . ' throws exception.';
+    try {
+      $wrapper->$name->value();
+      $this->fail($text);
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass($text);
+    }
+  }
+
+  protected function assertEmpty($wrapper, $name) {
+    $this->assertTrue(isset($wrapper->$name), 'Property ' . check_plain($name) . ' exists.');
+    $this->assertTrue($wrapper->$name->value() === NULL, 'Property ' . check_plain($name) . ' is empty.');
+  }
+
+  protected function assertValue($wrapper, $key) {
+    $this->assertTrue($wrapper->$key->value() !== NULL, check_plain($key) . ' property returned.');
+    $info = $wrapper->$key->info();
+    if (!empty($info['raw getter callback'])) {
+      // Also test getting the raw value
+      $this->assertTrue($wrapper->$key->raw() !== NULL, check_plain($key) . ' raw value returned.');
+    }
+  }
+
+  /**
+   * Test book module integration.
+   */
+  function testBookModule() {
+    $title = 'Book 1';
+    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'book'));
+    $node2 = $this->drupalCreateNode(array('type' => 'book', 'book' => array('bid' => $node->nid)));
+    $node3 = $this->drupalCreateNode(array('type' => 'page'));
+
+    // Test whether the properties work.
+    $wrapper = entity_metadata_wrapper('node', $node2);
+    $this->assertEqual("Book 1", $wrapper->book->title->value(), "Book title returned.");
+    $this->assertEqual($node->nid, $wrapper->book->nid->value(), "Book id returned.");
+
+    // Try using book properties for no book nodes.
+    $wrapper = entity_metadata_wrapper('node', $node3);
+    $this->assertException($wrapper, 'book');
+  }
+
+  /**
+   * Test properties of a comment.
+   */
+  function testComments() {
+    $title = 'Node 1';
+    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page'));
+    $account = $this->drupalCreateUser();
+    $comment = (object)array(
+      'subject' => 'topic',
+      'nid' => $node->nid,
+      'uid' => $account->uid,
+      'cid' => FALSE,
+      'pid' => 0,
+      'homepage' => '',
+      'language' => LANGUAGE_NONE,
+      'hostname' => ip_address(),
+    );
+    $comment->comment_body[LANGUAGE_NONE][0] = array('value' => 'text', 'format' => 0);
+    comment_save($comment);
+    $wrapper = entity_metadata_wrapper('comment', $comment);
+    foreach ($wrapper as $key => $value) {
+      if ($key != 'parent') {
+        $this->assertValue($wrapper, $key);
+      }
+    }
+    $this->assertEmpty($wrapper, 'parent');
+  }
+
+  /**
+   * Test all properties of a node.
+   */
+  function testNodeProperties() {
+    $title = 'Book 1';
+    $node = $this->drupalCreateNode(array('title' => $title, 'type' => 'page'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+    foreach ($wrapper as $key => $value) {
+      if ($key != 'book' && $key != 'source' && $key != 'last_view') {
+        $this->assertValue($wrapper, $key);
+      }
+    }
+    $this->assertException($wrapper, 'book');
+    $this->assertEmpty($wrapper, 'source');
+    $this->assertException($wrapper->source, 'title');
+    $this->assertEmpty($wrapper, 'last_view');
+  }
+
+  /**
+   * Tests properties provided by the taxonomy module.
+   */
+  function testTaxonomyProperties() {
+    $vocab = $this->createVocabulary();
+    $term_parent = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => $vocab,
+    ))->save()->value();
+    $term_parent2 = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => $vocab,
+    ))->save()->value();
+    $term = entity_property_values_create_entity('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'vocabulary' => $vocab,
+      'description' => $this->randomString(),
+      'weight' => mt_rand(0, 10),
+      'parent' => array($term_parent->tid),
+    ))->save()->value();
+
+    $wrapper = entity_metadata_wrapper('taxonomy_term', $term);
+    foreach ($wrapper as $key => $value) {
+      $this->assertValue($wrapper, $key);
+    }
+    // Test setting another parent using the full object.
+    $wrapper->parent[] = $term_parent2;
+    $this->assertEqual($wrapper->parent[1]->getIdentifier(), $term_parent2->tid, 'Term parent added.');
+
+    $parents = $wrapper->parent->value();
+    $tids = $term_parent->tid . ':' . $term_parent2->tid;
+    $this->assertEqual($parents[0]->tid . ':' . $parents[1]->tid, $tids, 'Parents returned.');
+    $this->assertEqual(implode(':', $wrapper->parent->value(array('identifier' => TRUE))), $tids, 'Parent ids returned.');
+
+    // Test vocabulary.
+    foreach ($wrapper->vocabulary as $key => $value) {
+      $this->assertValue($wrapper->vocabulary, $key);
+    }
+    // Test field integration.
+    $tags[LANGUAGE_NONE][0]['tid'] = $term->tid;
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', 'field_tags' => $tags));
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $this->assertEqual($wrapper->field_tags[0]->name->value(), $term->name, 'Get an associated tag of a node with the wrapper.');
+
+    $wrapper->field_tags[1] = $term_parent;
+    $tags = $wrapper->field_tags->value();
+    $this->assertEqual($tags[1]->tid, $term_parent->tid, 'Associated a new tag with a node.');
+    $this->assertEqual($tags[0]->tid, $term->tid, 'Previsous set association kept.');
+
+    // Test getting a list of identifiers.
+    $tags = $wrapper->field_tags->value(array('identifier' => TRUE));
+    $this->assertEqual($tags, array($term->tid, $term_parent->tid), 'List of referenced term identifiers returned.');
+
+    // Test setting tags by using ids.
+    $wrapper->field_tags->set(array(2));
+    $this->assertEqual($wrapper->field_tags[0]->tid->value(), 2, 'Specified tags by a list of term ids.');
+
+    // Test unsetting all tags.
+    $wrapper->field_tags = NULL;
+    $this->assertFalse($wrapper->field_tags->value(), 'Unset all tags from a node.');
+
+    // Test setting entity references to NULL.
+    // Create a taxonomy term field for that purpose.
+    $field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $field = array('field_name' => $field_name, 'type' => 'taxonomy_term_reference', 'cardinality' => 1);
+    $field = field_create_field($field);
+    $field_id = $field['id'];
+    $field_instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'node',
+      'bundle' => 'article',
+      'label' => $this->randomName() . '_label',
+      'description' => $this->randomName() . '_description',
+      'weight' => mt_rand(0, 127),
+      'widget' => array(
+        'type' => 'options_select',
+        'label' => 'Test term field',
+      )
+    );
+    field_create_instance($field_instance);
+    $term_field[LANGUAGE_NONE][0]['tid'] = $term->tid;
+    $node = $this->drupalCreateNode(array('title' => 'foo', 'type' => 'article', $field_name => $term_field));
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $wrapper->$field_name->set(NULL);
+    $termref = $wrapper->$field_name->value();
+    $this->assertNull($termref, 'Unset of a term reference successful.');
+  }
+
+  /**
+   * Test all properties of a user.
+   */
+  function testUserProperties() {
+    $account = $this->drupalCreateUser();
+    $account->login = REQUEST_TIME;
+    $account->access = REQUEST_TIME;
+    $wrapper = entity_metadata_wrapper('user', $account);
+    foreach ($wrapper as $key => $value) {
+      $this->assertValue($wrapper, $key);
+    }
+  }
+
+  /**
+   * Test properties provided by system module.
+   */
+  function testSystemProperties() {
+    $wrapper = entity_metadata_site_wrapper();
+    foreach ($wrapper as $key => $value) {
+      $this->assertValue($wrapper, $key);
+    }
+    // Test page request related properties.
+    foreach ($wrapper->current_page as $key => $value) {
+      $this->assertValue($wrapper->current_page, $key);
+    }
+
+    // Test files.
+    $file = $this->createFile();
+
+    $wrapper = entity_metadata_wrapper('file', $file);
+    foreach ($wrapper as $key => $value) {
+      $this->assertValue($wrapper, $key);
+    }
+  }
+
+  /**
+   * Runs some generic tests on each entity.
+   */
+  function testCRUDfunctions() {
+    $info = entity_get_info();
+    foreach ($info as $entity_type => $entity_info) {
+      // Test using access callback.
+      entity_access('view', $entity_type);
+      entity_access('update', $entity_type);
+      entity_access('create', $entity_type);
+      entity_access('delete', $entity_type);
+
+      // Test creating the entity.
+      if (!isset($entity_info['creation callback'])) {
+        continue;
+      }
+
+      // Populate $values with all values that are setable. They will be set
+      // with an metadata wrapper, so we also test setting that way.
+      $values = array();
+      foreach (entity_metadata_wrapper($entity_type) as $name => $wrapper) {
+        $info = $wrapper->info();
+        if (!empty($info['setter callback'])) {
+          $values[$name] = $this->createValue($wrapper);
+        }
+      }
+      $entity = entity_property_values_create_entity($entity_type, $values)->value();
+      $this->assertTrue($entity, "Created $entity_type and set all setable values.");
+
+      // Save the new entity.
+      $return = entity_save($entity_type, $entity);
+      if ($return === FALSE) {
+        continue; // No support for saving.
+      }
+      $id = entity_metadata_wrapper($entity_type, $entity)->getIdentifier();
+      $this->assertTrue($id, "$entity_type has been successfully saved.");
+
+      // And delete it.
+      $return = entity_delete($entity_type, $id);
+      if ($return === FALSE) {
+        continue; // No support for deleting.
+      }
+      $return = entity_load_single($entity_type, $id);
+      $this->assertFalse($return, "$entity_type has been successfully deleted.");
+    }
+  }
+
+  /**
+   * Test making use of a text fields.
+   */
+  function testTextFields() {
+    // Create a simple text field without text processing.
+    $field = array(
+      'field_name' => 'field_text',
+      'type' => 'text',
+      'cardinality' => 2,
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_text',
+      'entity_type' => 'node',
+      'label' => 'test',
+      'bundle' => 'article',
+      'widget' => array(
+        'type' => 'text_textfield',
+        'weight' => -1,
+      ),
+    );
+    field_create_instance($instance);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_text[0] = 'the text';
+
+    // Try saving the node and make sure the information is still there after
+    // loading the node again, thus the correct data structure has been written.
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual('the text', $wrapper->field_text[0]->value(), 'Text has been specified.');
+
+    // Now activate text processing.
+    $instance['settings']['text_processing'] = 1;
+    field_update_instance($instance);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_text[0]->set(array('value' => "<b>The second body.</b>"));
+    $this->assertEqual("<p>The second body.</p>\n", $wrapper->field_text[0]->value->value(), "Setting a processed text field value and reading it again.");
+
+    // Assert the summary property is correctly removed.
+    $this->assertFalse(isset($wrapper->field_text[0]->summary), 'Processed text has no summary.');
+
+    // Create a text field with summary but without text processing.
+    $field = array(
+      'field_name' => 'field_text2',
+      'type' => 'text_with_summary',
+      'cardinality' => 1,
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_text2',
+      'entity_type' => 'node',
+      'label' => 'test',
+      'bundle' => 'article',
+      'settings' => array('text_processing' => 0),
+      'widget' => array(
+        'type' => 'text_textarea_with_summary',
+        'weight' => -1,
+      ),
+    );
+    field_create_instance($instance);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_text2->summary = 'the summary';
+    $wrapper->field_text2->value = 'the text';
+
+    // Try saving the node and make sure the information is still there after
+    // loading the node again, thus the correct data structure has been written.
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual('the text', $wrapper->field_text2->value->value(), 'Text has been specified.');
+    $this->assertEqual('the summary', $wrapper->field_text2->summary->value(), 'Summary has been specified.');
+  }
+
+  /**
+   * Test making use of a file field.
+   */
+  function testFileFields() {
+    $file = $this->createFile();
+
+    // Create a file field.
+    $field = array(
+      'field_name' => 'field_file',
+      'type' => 'file',
+      'cardinality' => 2,
+      'settings' => array('display_field' => TRUE),
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_file',
+      'entity_type' => 'node',
+      'label' => 'File',
+      'bundle' => 'article',
+      'settings' => array('description_field' => TRUE),
+      'required' => FALSE,
+      'widget' => array(
+        'type' => 'file_generic',
+        'weight' => -1,
+      ),
+    );
+    field_create_instance($instance);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_file[0] = array('fid' => $file->fid, 'display' => FALSE);
+    $this->assertEqual($file->filename, $wrapper->field_file[0]->file->name->value(), 'File has been specified.');
+
+    $wrapper->field_file[0]->description = 'foo';
+    $wrapper->field_file[0]->display = TRUE;
+
+    $this->assertEqual($wrapper->field_file[0]->description->value(), 'foo', 'File description has been correctly set.');
+
+    // Try saving the node and make sure the information is still there after
+    // loading the node again, thus the correct data structure has been written.
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual($wrapper->field_file[0]->description->value(), 'foo', 'File description has been correctly set.');
+    $this->assertEqual($wrapper->field_file[0]->display->value(), TRUE, 'File display value has been correctly set.');
+
+    // Test adding a new file, the display-property has to be created
+    // automatically.
+    $wrapper->field_file[1]->file = $file;
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertEqual($file->fid, $wrapper->field_file[1]->file->getIdentifier(), 'New file has been added.');
+
+    // Test adding an invalid file-field item, i.e. without any file.
+    try {
+      $wrapper->field_file[] = array('description' => 'test');
+      $this->fail('Exception not thrown.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Not valid file-field item has thrown an exception.');
+    }
+
+    // Test remove all file-field items.
+    $wrapper->field_file = NULL;
+    $this->assertFalse($wrapper->field_file->value(), 'Removed multiple file-field items.');
+  }
+
+  /**
+   * Test making use of an image field.
+   */
+  function testImageFields() {
+    $file = $this->createFile('image');
+
+    // Just use the image field on the article node.
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $wrapper->field_image = array('fid' => $file->fid);
+    $this->assertEqual($file->filename, $wrapper->field_image->file->name->value(), 'File has been specified.');
+
+    $wrapper->field_image->alt = 'foo';
+    $this->assertEqual($wrapper->field_image->alt->value(), 'foo', 'Image alt attribute has been correctly set.');
+
+    // Try saving the node and make sure the information is still there after
+    // loading the node again, thus the correct data structure has been written.
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $wrapper = entity_metadata_wrapper('node', $node);
+
+    $this->assertEqual($wrapper->field_image->alt->value(), 'foo', 'File description has been correctly set.');
+
+    // Test adding a new image.
+    $wrapper->field_image->file = $file;
+    node_save($node);
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertEqual($file->fid, $wrapper->field_image->file->getIdentifier(), 'New file has been added.');
+
+    // Test adding an invalid image-field item, i.e. without any file.
+    try {
+      $wrapper->field_image = array();
+      $this->fail('Exception not thrown.');
+    }
+    catch (EntityMetadataWrapperException $e) {
+      $this->pass('Not valid image-field item has thrown an exception.');
+    }
+  }
+
+  /**
+   * Creates a value for the given property.
+   */
+  protected function createValue($wrapper) {
+    if (!isset($this->node)) {
+      $this->node = $this->drupalCreateNode(array('type' => 'page'));
+      $this->user = $this->drupalCreateUser();
+      $this->taxonomy_vocabulary = $this->createVocabulary();
+    }
+
+    if ($options = $wrapper->optionsList()) {
+      $options = entity_property_options_flatten($options);
+      return $wrapper instanceof EntityListWrapper ? array(key($options)) : key($options);
+    }
+
+    // For mail addresses properly pass an mail address.
+    $info = $wrapper->info();
+    if ($info['name'] == 'mail') {
+      return 'webmaster@example.com';
+    }
+
+    switch ($wrapper->type()) {
+      case 'decimal':
+      case 'integer':
+      case 'duration':
+        return 1;
+      case 'date':
+        return REQUEST_TIME;
+      case 'boolean':
+        return TRUE;
+      case 'token':
+        return drupal_strtolower($this->randomName(8));
+      case 'text':
+        return $this->randomName(32);
+      case 'text_formatted':
+        return array('value' => $this->randomName(16));
+      case 'list<taxonomy_term>':
+        return array();
+
+      default:
+        return $this->{$wrapper->type()};
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity_token.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Entity tokens
+description = Provides token replacements for all properties that have no tokens and are known to the entity API.
+core = 7.x
+files[] = entity_token.tokens.inc
+files[] = entity_token.module
+dependencies[] = entity
+
+; Information added by drupal.org packaging script on 2013-08-14
+version = "7.x-1.2"
+core = "7.x"
+project = "entity"
+datestamp = "1376493705"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity_token.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * Module file for the entity tokens module. Drupal needs this file.
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/entity_token.tokens.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,341 @@
+<?php
+
+/**
+ * @file
+ * Provides tokens for entity properties which have no token yet.
+ */
+
+/**
+ * Defines the types of properties to be added as token.
+ *
+ * @return
+ *   An array mapping token types to the usual (entity) type names.
+ */
+function entity_token_types() {
+  $return = entity_token_types_chained();
+  return $return + drupal_map_assoc(array('text', 'integer', 'decimal', 'duration', 'boolean', 'uri'));
+}
+
+/**
+ * Defines a list of token types that need to be chained.
+ *
+ * @return
+ *   If a (token) type is given, whether the given type needs to be chained.
+ *   Else a full list of token types to be chained as returned by
+ *   entity_token_token_types().
+ */
+function entity_token_types_chained($type = NULL) {
+  // This functions gets called rather often when replacing tokens, thus
+  // we statically cache $types using the advanced drupal static pattern.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['types'] = &drupal_static(__FUNCTION__, array());
+  }
+  $types = &$drupal_static_fast['types'];
+
+  if (!$types) {
+    // Add entities.
+    foreach (entity_get_info() as $entity_type => $info) {
+      if ($token_type = isset($info['token type']) ? $info['token type'] : $entity_type) {
+        $types[$token_type] = $entity_type;
+      }
+    }
+    // Add 'date' and 'site' tokens.
+    $types['date'] = 'date';
+    $types['site'] = 'site';
+    // Add a 'struct' type.
+    $types['struct'] = 'struct';
+  }
+
+  if (isset($type)) {
+    return isset($types[$type]) || entity_property_list_extract_type($type);
+  }
+  return $types;
+}
+
+/**
+ * Gets the right token type for a given property info array.
+ */
+function _entity_token_map_to_token_type($property_info) {
+  $lookup = &drupal_static(__FUNCTION__);
+
+  if (!$lookup) {
+    // Initialize a lookup array mapping property types to token types.
+    $lookup = array_flip(entity_token_types());
+  }
+
+  $type = isset($property_info['type']) ? $property_info['type'] : 'text';
+  // Just use the type 'struct' for all structures.
+  if (!empty($property_info['property info'])) {
+    $type = 'struct';
+  }
+
+  if ($item_type = entity_property_list_extract_type($type)) {
+    return isset($lookup[$item_type]) ? "list<$lookup[$item_type]>" : FALSE;
+  }
+  return isset($lookup[$type]) ? $lookup[$type] : FALSE;
+}
+
+/**
+ * Implements hook_token_info_alter().
+ */
+function entity_token_token_info_alter(&$info) {
+  $entity_info = entity_get_info();
+  $token_types = entity_token_types_chained();
+
+  // Loop over all chain-able token types, as those may contain further tokens,
+  // e.g. entity types or 'site'.
+  foreach ($token_types as $token_type => $type) {
+    // Just add all properties regardless whether it's in a bundle, but only if
+    // there is no token of the property yet.
+    foreach (entity_get_all_property_info($type) as $name => $property) {
+      $name = str_replace('_', '-', $name);
+      $property += array('type' => 'text', 'description' => $property['label']);
+      $property_token_type = _entity_token_map_to_token_type($property);
+
+      if (!isset($info['tokens'][$token_type][$name]) && $property_token_type) {
+
+        $info['tokens'][$token_type][$name] = array(
+          'name' => $property['label'],
+          'description' => $property['description'],
+          'type' => $property_token_type,
+          // Mark the token so we know we have to provide the value afterwards.
+          'entity-token' => TRUE,
+        );
+      }
+      if ($property_token_type == 'struct' && !empty($property['property info'])) {
+        $info['tokens'][$token_type][$name]['dynamic'] = TRUE;
+        $help = array();
+        foreach ($property['property info'] as $key => $property_info) {
+          $help[] = $key . ' (' . $property_info['label'] . ')';
+        }
+        $info['tokens'][$token_type][$name]['description'] .= ' ' . t('The following properties may be appended to the token: @keys',
+          array('@keys' => implode(', ', $help))
+        );
+      }
+    }
+  }
+
+  // Make sure all chain-able token types we support are registered.
+  foreach ($token_types as $token_type => $type) {
+
+    if (!empty($info['tokens'][$token_type]) && !isset($info['types'][$token_type])) {
+      if (isset($entity_info[$type])) {
+        $info['types'][$token_type] = array(
+          'name' => $entity_info[$type]['label'],
+          'description' => t('Tokens related to the "@name" entities.', array('@name' => $entity_info[$type]['label'])),
+          'needs-data' => $token_type,
+        );
+      }
+      else {
+        $info['types'][$token_type] = array(
+          'name' => drupal_strtoupper($token_type),
+          'description' => t('@name tokens.', array('@name' => drupal_strtoupper($token_type))),
+          'needs-data' => $token_type,
+        );
+      }
+    }
+    if (!empty($info['tokens'][$token_type]) && !isset($info['types']["list<$token_type>"]) && $token_type != 'site') {
+      if (isset($entity_info[$type])) {
+        $info['types']["list<$token_type>"] = array(
+          'name' => t('List of @entities', array('@entities' => isset($entity_info[$type]['plural label']) ? $entity_info[$type]['plural label'] : $entity_info[$type]['label'] . 's')),
+          'description' => t('Tokens related to the "@name" entities.', array('@name' => $entity_info[$type]['label'])),
+          'needs-data' => "list<$token_type>",
+        );
+      }
+      else {
+        $info['types']["list<$token_type>"] = array(
+          'name' => t('List of @type values', array('@type' => $token_type)),
+          'description' => t('Tokens for lists of @type values.', array('@type' => $token_type)),
+          'needs-data' => "list<$token_type>",
+        );
+      }
+      // Also add some basic token replacements for lists...
+      for ($i = 0; $i < 4; $i++) {
+        $info['tokens']["list<$token_type>"][$i] = array(
+          'name' => t('@type with delta @delta', array('@delta' => $i, '@type' => $info['types'][$token_type]['name'])),
+          'description' => t('The list item with delta @delta. Delta values start from 0 and are incremented by one per list item.', array('@delta' => $i)),
+          'type' => $token_type,
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function entity_token_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $token_types = entity_token_types_chained();
+  $replacements = array();
+
+  if (isset($token_types[$type]) && (!empty($data[$type]) || $type == 'site')) {
+    $data += array($type => FALSE);
+
+    // Make use of token module's token cache if available.
+    $info = module_exists('token') ? token_get_info() : token_info();
+    foreach ($tokens as $name => $original) {
+      // Provide the token for all properties marked to stem from us.
+      if (!empty($info['tokens'][$type][$name]['entity-token']) || $type == 'struct') {
+        $wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
+        $property_name = str_replace('-', '_', $name);
+        try {
+          $replacement = _entity_token_get_token($wrapper->$property_name, $options);
+          if (isset($replacement)) {
+            $replacements[$original] = $replacement;
+          }
+        }
+        catch (EntityMetadataWrapperException $e) {
+          // If tokens for not existing values are requested, just do nothing.
+        }
+      }
+    }
+
+    // Properly chain everything of a type marked as needs chaining.
+    $info['tokens'] += array($type => array());
+    foreach ($info['tokens'][$type] as $name => $token_info) {
+      if (!empty($token_info['entity-token']) && isset($token_info['type']) && entity_token_types_chained($token_info['type'])) {
+
+        if ($chained_tokens = token_find_with_prefix($tokens, $name)) {
+          $wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, $token_types[$type], $data[$type], $options) : $wrapper;
+          $property_name = str_replace('-', '_', $name);
+
+          try {
+            // Pass on 'struct' properties wrapped, else un-wrap the data.
+            $value = ($token_info['type'] == 'struct') ? $wrapper->$property_name : $wrapper->$property_name->value();
+            $replacements += token_generate($token_info['type'], $chained_tokens, array($token_info['type'] => $value), $options);
+          }
+          catch (EntityMetadataWrapperException $e) {
+            // If tokens for not existing values are requested, just do nothing.
+          }
+        }
+      }
+    }
+  }
+  // Add support for evaluating tokens for "list<type"> types.
+  elseif ($item_token_type = entity_property_list_extract_type($type)) {
+    foreach ($tokens as $name => $original) {
+      // Care about getting entries of a list.
+      if (is_numeric($name)) {
+        $wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, "list<$token_types[$item_token_type]>", $data[$type], $options) : $wrapper;
+        try {
+          $replacement = _entity_token_get_token($wrapper->get($name), $options);
+          if (isset($replacement)) {
+            $replacements[$original] = $replacement;
+          }
+        }
+        catch (EntityMetadataWrapperException $e) {
+          // If tokens for not existing values are requested, just do nothing.
+        }
+      }
+      // Care about generating chained tokens for list-items.
+      else {
+        $parts = explode(':', $name, 2);
+        $delta = $parts[0];
+
+        if (is_numeric($delta) && $chained_tokens = token_find_with_prefix($tokens, $delta)) {
+          $wrapper = !isset($wrapper) ? _entity_token_wrap_data($type, "list<$token_types[$item_token_type]>", $data[$type], $options) : $wrapper;
+          try {
+            $replacements += token_generate($item_token_type, $chained_tokens, array($item_token_type => $wrapper->get($delta)->value()), $options);
+          }
+          catch (EntityMetadataWrapperException $e) {
+            // If tokens for not existing values are requested, just do nothing.
+          }
+        }
+      }
+    }
+  }
+
+  // Add support for chaining struct data. As struct data has no registered
+  // tokens, we have to chain based upon wrapper property info.
+  if ($type == 'struct') {
+    $wrapper = $data[$type];
+    foreach ($wrapper as $name => $property) {
+      $token_type = _entity_token_map_to_token_type($property->info());
+
+      if (entity_token_types_chained($token_type) && $chained_tokens = token_find_with_prefix($tokens, $name)) {
+        try {
+          // Pass on 'struct' properties wrapped, else un-wrap the data.
+          $value = ($token_type == 'struct') ? $property : $property->value();
+          $replacements += token_generate($token_type, $chained_tokens, array($token_type => $value), $options);
+        }
+        catch (EntityMetadataWrapperException $e) {
+          // If tokens for not existing values are requested, just do nothing.
+        }
+      }
+    }
+  }
+
+  return $replacements;
+}
+
+/**
+ * Wraps the given data by correctly obeying the options.
+ */
+function _entity_token_wrap_data($token_type, $type, $data, $options) {
+  if ($type == 'site') {
+    $wrapper = entity_metadata_site_wrapper();
+  }
+  elseif ($type == 'struct') {
+    // 'struct' data items are passed on wrapped.
+    $wrapper = $data;
+  }
+  else {
+    $wrapper = entity_metadata_wrapper($type, $data);
+  }
+  if (isset($options['language']) && $wrapper instanceof EntityStructureWrapper) {
+    $wrapper->language($options['language']->language);
+  }
+  return $wrapper;
+}
+
+/**
+ * Gets the token replacement by correctly obeying the options.
+ */
+function _entity_token_get_token($wrapper, $options) {
+
+  if ($wrapper->value() === NULL) {
+    // Do not provide a replacement if there is no value.
+    return NULL;
+  }
+
+  if (empty($options['sanitize'])) {
+    // When we don't need sanitized tokens decode already sanitizied texts.
+    $options['decode'] = TRUE;
+  }
+  $langcode = isset($options['language']) ? $options['language']->language : NULL;
+
+  // If there is a label for a property, e.g. defined by an options list or an
+  // entity label, make use of it.
+  if ($label = $wrapper->label()) {
+    return empty($options['sanitize']) ? $label : check_plain($label);
+  }
+
+  switch ($wrapper->type()) {
+    case 'integer':
+      return $wrapper->value();
+    case 'decimal':
+      return number_format($wrapper->value(), 2);
+    case 'date':
+      return format_date($wrapper->value(), 'medium', '', NULL, $langcode);
+    case 'duration':
+      return format_interval($wrapper->value(), 2, $langcode);
+    case 'boolean':
+      return $wrapper->value() ? t('true') : t('false');
+    case 'uri':
+    case 'text':
+      return $wrapper->value($options);
+  }
+
+  // Care for outputing list values.
+  if ($wrapper instanceof EntityListWrapper) {
+    $output = array();
+    foreach ($wrapper as $item) {
+      $output[] = _entity_token_get_token($item, $options);
+    }
+    return implode(', ', $output);
+  }
+  // Else we do not have a good string to output, e.g. for struct values. Just
+  // output the string representation of the wrapper.
+  return (string) $wrapper;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/includes/entity.controller.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,976 @@
+<?php
+
+/**
+ * @file
+ * Provides a controller building upon the core controller but providing more
+ * features like full CRUD functionality.
+ */
+
+/**
+ * Interface for EntityControllers compatible with the entity API.
+ */
+interface EntityAPIControllerInterface extends DrupalEntityControllerInterface {
+
+  /**
+   * Delete permanently saved entities.
+   *
+   * In case of failures, an exception is thrown.
+   *
+   * @param $ids
+   *   An array of entity IDs.
+   */
+  public function delete($ids);
+
+  /**
+   * Invokes a hook on behalf of the entity. For hooks that have a respective
+   * field API attacher like insert/update/.. the attacher is called too.
+   */
+  public function invoke($hook, $entity);
+
+  /**
+   * Permanently saves the given entity.
+   *
+   * In case of failures, an exception is thrown.
+   *
+   * @param $entity
+   *   The entity to save.
+   *
+   * @return
+   *   SAVED_NEW or SAVED_UPDATED is returned depending on the operation
+   *   performed.
+   */
+  public function save($entity);
+
+  /**
+   * Create a new entity.
+   *
+   * @param array $values
+   *   An array of values to set, keyed by property name.
+   * @return
+   *   A new instance of the entity type.
+   */
+  public function create(array $values = array());
+
+  /**
+   * Exports an entity as serialized string.
+   *
+   * @param $entity
+   *   The entity to export.
+   * @param $prefix
+   *   An optional prefix for each line.
+   *
+   * @return
+   *   The exported entity as serialized string. The format is determined by
+   *   the controller and has to be compatible with the format that is accepted
+   *   by the import() method.
+   */
+  public function export($entity, $prefix = '');
+
+  /**
+   * Imports an entity from a string.
+   *
+   * @param string $export
+   *   An exported entity as serialized string.
+   *
+   * @return
+   *   An entity object not yet saved.
+   */
+  public function import($export);
+
+  /**
+   * Builds a structured array representing the entity's content.
+   *
+   * The content built for the entity will vary depending on the $view_mode
+   * parameter.
+   *
+   * @param $entity
+   *   An entity object.
+   * @param $view_mode
+   *   View mode, e.g. 'full', 'teaser'...
+   * @param $langcode
+   *   (optional) A language code to use for rendering. Defaults to the global
+   *   content language of the current request.
+   * @return
+   *   The renderable array.
+   */
+  public function buildContent($entity, $view_mode = 'full', $langcode = NULL);
+
+  /**
+   * Generate an array for rendering the given entities.
+   *
+   * @param $entities
+   *   An array of entities to render.
+   * @param $view_mode
+   *   View mode, e.g. 'full', 'teaser'...
+   * @param $langcode
+   *   (optional) A language code to use for rendering. Defaults to the global
+   *   content language of the current request.
+   * @param $page
+   *   (optional) If set will control if the entity is rendered: if TRUE
+   *   the entity will be rendered without its title, so that it can be embeded
+   *   in another context. If FALSE the entity will be displayed with its title
+   *   in a mode suitable for lists.
+   *   If unset, the page mode will be enabled if the current path is the URI
+   *   of the entity, as returned by entity_uri().
+   *   This parameter is only supported for entities which controller is a
+   *   EntityAPIControllerInterface.
+   * @return
+   *   The renderable array, keyed by entity name or numeric id.
+   */
+  public function view($entities, $view_mode = 'full', $langcode = NULL, $page = NULL);
+}
+
+/**
+ * Interface for EntityControllers of entities that support revisions.
+ */
+interface EntityAPIControllerRevisionableInterface extends EntityAPIControllerInterface {
+
+  /**
+   * Delete an entity revision.
+   *
+   * Note that the default revision of an entity cannot be deleted.
+   *
+   * @param $revision_id
+   *   The ID of the revision to delete.
+   *
+   * @return boolean
+   *   TRUE if the entity revision could be deleted, FALSE otherwise.
+   */
+  public function deleteRevision($revision_id);
+
+}
+
+/**
+ * A controller implementing EntityAPIControllerInterface for the database.
+ */
+class EntityAPIController extends DrupalDefaultEntityController implements EntityAPIControllerRevisionableInterface {
+
+  protected $cacheComplete = FALSE;
+  protected $bundleKey;
+  protected $defaultRevisionKey;
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController#__construct()
+   */
+  public function __construct($entityType) {
+    parent::__construct($entityType);
+    // If this is the bundle of another entity, set the bundle key.
+    if (isset($this->entityInfo['bundle of'])) {
+      $info = entity_get_info($this->entityInfo['bundle of']);
+      $this->bundleKey = $info['bundle keys']['bundle'];
+    }
+    $this->defaultRevisionKey = !empty($this->entityInfo['entity keys']['default revision']) ? $this->entityInfo['entity keys']['default revision'] : 'default_revision';
+  }
+
+  /**
+   * Overrides DrupalDefaultEntityController::buildQuery().
+   */
+  protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
+    $query = parent::buildQuery($ids, $conditions, $revision_id);
+    if ($this->revisionKey) {
+      // Compare revision id of the base and revision table, if equal then this
+      // is the default revision.
+      $query->addExpression('base.' . $this->revisionKey . ' = revision.' . $this->revisionKey, $this->defaultRevisionKey);
+    }
+    return $query;
+  }
+
+  /**
+   * Builds and executes the query for loading.
+   *
+   * @return The results in a Traversable object.
+   */
+  public function query($ids, $conditions, $revision_id = FALSE) {
+    // Build the query.
+    $query = $this->buildQuery($ids, $conditions, $revision_id);
+    $result = $query->execute();
+    if (!empty($this->entityInfo['entity class'])) {
+      $result->setFetchMode(PDO::FETCH_CLASS, $this->entityInfo['entity class'], array(array(), $this->entityType));
+    }
+    return $result;
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController#load($ids, $conditions)
+   *
+   * In contrast to the parent implementation we factor out query execution, so
+   * fetching can be further customized easily.
+   */
+  public function load($ids = array(), $conditions = array()) {
+    $entities = array();
+
+    // Revisions are not statically cached, and require a different query to
+    // other conditions, so separate the revision id into its own variable.
+    if ($this->revisionKey && isset($conditions[$this->revisionKey])) {
+      $revision_id = $conditions[$this->revisionKey];
+      unset($conditions[$this->revisionKey]);
+    }
+    else {
+      $revision_id = FALSE;
+    }
+
+    // Create a new variable which is either a prepared version of the $ids
+    // array for later comparison with the entity cache, or FALSE if no $ids
+    // were passed. The $ids array is reduced as items are loaded from cache,
+    // and we need to know if it's empty for this reason to avoid querying the
+    // database when all requested entities are loaded from cache.
+    $passed_ids = !empty($ids) ? array_flip($ids) : FALSE;
+
+    // Try to load entities from the static cache.
+    if ($this->cache && !$revision_id) {
+      $entities = $this->cacheGet($ids, $conditions);
+      // If any entities were loaded, remove them from the ids still to load.
+      if ($passed_ids) {
+        $ids = array_keys(array_diff_key($passed_ids, $entities));
+      }
+    }
+
+    // Support the entitycache module if activated.
+    if (!empty($this->entityInfo['entity cache']) && !$revision_id && $ids && !$conditions) {
+      $cached_entities = EntityCacheControllerHelper::entityCacheGet($this, $ids, $conditions);
+      // If any entities were loaded, remove them from the ids still to load.
+      $ids = array_diff($ids, array_keys($cached_entities));
+      $entities += $cached_entities;
+
+      // Add loaded entities to the static cache if we are not loading a
+      // revision.
+      if ($this->cache && !empty($cached_entities) && !$revision_id) {
+        $this->cacheSet($cached_entities);
+      }
+    }
+
+    // Load any remaining entities from the database. This is the case if $ids
+    // is set to FALSE (so we load all entities), if there are any ids left to
+    // load or if loading a revision.
+    if (!($this->cacheComplete && $ids === FALSE && !$conditions) && ($ids === FALSE || $ids || $revision_id)) {
+      $queried_entities = array();
+      foreach ($this->query($ids, $conditions, $revision_id) as $record) {
+        // Skip entities already retrieved from cache.
+        if (isset($entities[$record->{$this->idKey}])) {
+          continue;
+        }
+
+        // For DB-based entities take care of serialized columns.
+        if (!empty($this->entityInfo['base table'])) {
+          $schema = drupal_get_schema($this->entityInfo['base table']);
+
+          foreach ($schema['fields'] as $field => $info) {
+            if (!empty($info['serialize']) && isset($record->$field)) {
+              $record->$field = unserialize($record->$field);
+              // Support automatic merging of 'data' fields into the entity.
+              if (!empty($info['merge']) && is_array($record->$field)) {
+                foreach ($record->$field as $key => $value) {
+                  $record->$key = $value;
+                }
+                unset($record->$field);
+              }
+            }
+          }
+        }
+
+        $queried_entities[$record->{$this->idKey}] = $record;
+      }
+    }
+
+    // Pass all entities loaded from the database through $this->attachLoad(),
+    // which attaches fields (if supported by the entity type) and calls the
+    // entity type specific load callback, for example hook_node_load().
+    if (!empty($queried_entities)) {
+      $this->attachLoad($queried_entities, $revision_id);
+      $entities += $queried_entities;
+    }
+
+    // Entitycache module support: Add entities to the entity cache if we are
+    // not loading a revision.
+    if (!empty($this->entityInfo['entity cache']) && !empty($queried_entities) && !$revision_id) {
+      EntityCacheControllerHelper::entityCacheSet($this, $queried_entities);
+    }
+
+    if ($this->cache) {
+      // Add entities to the cache if we are not loading a revision.
+      if (!empty($queried_entities) && !$revision_id) {
+        $this->cacheSet($queried_entities);
+
+        // Remember if we have cached all entities now.
+        if (!$conditions && $ids === FALSE) {
+          $this->cacheComplete = TRUE;
+        }
+      }
+    }
+    // Ensure that the returned array is ordered the same as the original
+    // $ids array if this was passed in and remove any invalid ids.
+    if ($passed_ids && $passed_ids = array_intersect_key($passed_ids, $entities)) {
+      foreach ($passed_ids as $id => $value) {
+        $passed_ids[$id] = $entities[$id];
+      }
+      $entities = $passed_ids;
+    }
+    return $entities;
+  }
+
+  /**
+   * Overrides DrupalDefaultEntityController::resetCache().
+   */
+  public function resetCache(array $ids = NULL) {
+    $this->cacheComplete = FALSE;
+    parent::resetCache($ids);
+    // Support the entitycache module.
+    if (!empty($this->entityInfo['entity cache'])) {
+      EntityCacheControllerHelper::resetEntityCache($this, $ids);
+    }
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   */
+  public function invoke($hook, $entity) {
+    // entity_revision_delete() invokes hook_entity_revision_delete() and
+    // hook_field_attach_delete_revision() just as node module does. So we need
+    // to adjust the name of our revision deletion field attach hook in order to
+    // stick to this pattern.
+    $field_attach_hook = ($hook == 'revision_delete' ? 'delete_revision' : $hook);
+    if (!empty($this->entityInfo['fieldable']) && function_exists($function = 'field_attach_' . $field_attach_hook)) {
+      $function($this->entityType, $entity);
+    }
+
+    if (!empty($this->entityInfo['bundle of']) && entity_type_is_fieldable($this->entityInfo['bundle of'])) {
+      $type = $this->entityInfo['bundle of'];
+      // Call field API bundle attachers for the entity we are a bundle of.
+      if ($hook == 'insert') {
+        field_attach_create_bundle($type, $entity->{$this->bundleKey});
+      }
+      elseif ($hook == 'delete') {
+        field_attach_delete_bundle($type, $entity->{$this->bundleKey});
+      }
+      elseif ($hook == 'update' && $entity->original->{$this->bundleKey} != $entity->{$this->bundleKey}) {
+        field_attach_rename_bundle($type, $entity->original->{$this->bundleKey}, $entity->{$this->bundleKey});
+      }
+    }
+    // Invoke the hook.
+    module_invoke_all($this->entityType . '_' . $hook, $entity);
+    // Invoke the respective entity level hook.
+    if ($hook == 'presave' || $hook == 'insert' || $hook == 'update' || $hook == 'delete') {
+      module_invoke_all('entity_' . $hook, $entity, $this->entityType);
+    }
+    // Invoke rules.
+    if (module_exists('rules')) {
+      rules_invoke_event($this->entityType . '_' . $hook, $entity);
+    }
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $transaction
+   *   Optionally a DatabaseTransaction object to use. Allows overrides to pass
+   *   in their transaction object.
+   */
+  public function delete($ids, DatabaseTransaction $transaction = NULL) {
+    $entities = $ids ? $this->load($ids) : FALSE;
+    if (!$entities) {
+      // Do nothing, in case invalid or no ids have been passed.
+      return;
+    }
+    // This transaction causes troubles on MySQL, see
+    // http://drupal.org/node/1007830. So we deactivate this by default until
+    // is shipped in a point release.
+    // $transaction = isset($transaction) ? $transaction : db_transaction();
+
+    try {
+      $ids = array_keys($entities);
+
+      db_delete($this->entityInfo['base table'])
+        ->condition($this->idKey, $ids, 'IN')
+        ->execute();
+
+      if (isset($this->revisionTable)) {
+        db_delete($this->revisionTable)
+          ->condition($this->idKey, $ids, 'IN')
+          ->execute();
+      }
+      // Reset the cache as soon as the changes have been applied.
+      $this->resetCache($ids);
+
+      foreach ($entities as $id => $entity) {
+        $this->invoke('delete', $entity);
+      }
+      // Ignore slave server temporarily.
+      db_ignore_slave();
+    }
+    catch (Exception $e) {
+      if (isset($transaction)) {
+        $transaction->rollback();
+      }
+      watchdog_exception($this->entityType, $e);
+      throw $e;
+    }
+  }
+
+  /**
+   * Implements EntityAPIControllerRevisionableInterface::deleteRevision().
+   */
+  public function deleteRevision($revision_id) {
+    if ($entity_revision = entity_revision_load($this->entityType, $revision_id)) {
+      // Prevent deleting the default revision.
+      if (entity_revision_is_default($this->entityType, $entity_revision)) {
+        return FALSE;
+      }
+
+      db_delete($this->revisionTable)
+        ->condition($this->revisionKey, $revision_id)
+        ->execute();
+
+      $this->invoke('revision_delete', $entity_revision);
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $transaction
+   *   Optionally a DatabaseTransaction object to use. Allows overrides to pass
+   *   in their transaction object.
+   */
+  public function save($entity, DatabaseTransaction $transaction = NULL) {
+    $transaction = isset($transaction) ? $transaction : db_transaction();
+    try {
+      // Load the stored entity, if any.
+      if (!empty($entity->{$this->idKey}) && !isset($entity->original)) {
+        // In order to properly work in case of name changes, load the original
+        // entity using the id key if it is available.
+        $entity->original = entity_load_unchanged($this->entityType, $entity->{$this->idKey});
+      }
+      $entity->is_new = !empty($entity->is_new) || empty($entity->{$this->idKey});
+      $this->invoke('presave', $entity);
+
+      if ($entity->is_new) {
+        $return = drupal_write_record($this->entityInfo['base table'], $entity);
+        if ($this->revisionKey) {
+          $this->saveRevision($entity);
+        }
+        $this->invoke('insert', $entity);
+      }
+      else {
+        // Update the base table if the entity doesn't have revisions or
+        // we are updating the default revision.
+        if (!$this->revisionKey || !empty($entity->{$this->defaultRevisionKey})) {
+          $return = drupal_write_record($this->entityInfo['base table'], $entity, $this->idKey);
+        }
+        if ($this->revisionKey) {
+          $return = $this->saveRevision($entity);
+        }
+        $this->resetCache(array($entity->{$this->idKey}));
+        $this->invoke('update', $entity);
+
+        // Field API always saves as default revision, so if the revision saved
+        // is not default we have to restore the field values of the default
+        // revision now by invoking field_attach_update() once again.
+        if ($this->revisionKey && !$entity->{$this->defaultRevisionKey} && !empty($this->entityInfo['fieldable'])) {
+          field_attach_update($this->entityType, $entity->original);
+        }
+      }
+
+      // Ignore slave server temporarily.
+      db_ignore_slave();
+      unset($entity->is_new);
+      unset($entity->is_new_revision);
+      unset($entity->original);
+
+      return $return;
+    }
+    catch (Exception $e) {
+      $transaction->rollback();
+      watchdog_exception($this->entityType, $e);
+      throw $e;
+    }
+  }
+
+  /**
+   * Saves an entity revision.
+   *
+   * @param Entity $entity
+   *   Entity revision to save.
+   */
+  protected function saveRevision($entity) {
+    // Convert the entity into an array as it might not have the same properties
+    // as the entity, it is just a raw structure.
+    $record = (array) $entity;
+    // File fields assumes we are using $entity->revision instead of
+    // $entity->is_new_revision, so we also support it and make sure it's set to
+    // the same value.
+    $entity->is_new_revision = !empty($entity->is_new_revision) || !empty($entity->revision) || $entity->is_new;
+    $entity->revision = &$entity->is_new_revision;
+    $entity->{$this->defaultRevisionKey} = !empty($entity->{$this->defaultRevisionKey}) || $entity->is_new;
+
+
+
+    // When saving a new revision, set any existing revision ID to NULL so as to
+    // ensure that a new revision will actually be created.
+    if ($entity->is_new_revision && isset($record[$this->revisionKey])) {
+      $record[$this->revisionKey] = NULL;
+    }
+
+    if ($entity->is_new_revision) {
+      drupal_write_record($this->revisionTable, $record);
+      $update_default_revision = $entity->{$this->defaultRevisionKey};
+    }
+    else {
+      drupal_write_record($this->revisionTable, $record, $this->revisionKey);
+      // @todo: Fix original entity to be of the same revision and check whether
+      // the default revision key has been set.
+      $update_default_revision = $entity->{$this->defaultRevisionKey} && $entity->{$this->revisionKey} != $entity->original->{$this->revisionKey};
+    }
+    // Make sure to update the new revision key for the entity.
+    $entity->{$this->revisionKey} = $record[$this->revisionKey];
+
+    // Mark this revision as the default one.
+    if ($update_default_revision) {
+      db_update($this->entityInfo['base table'])
+        ->fields(array($this->revisionKey => $record[$this->revisionKey]))
+        ->condition($this->idKey, $entity->{$this->idKey})
+        ->execute();
+    }
+    return $entity->is_new_revision ? SAVED_NEW : SAVED_UPDATED;
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   */
+  public function create(array $values = array()) {
+    // Add is_new property if it is not set.
+    $values += array('is_new' => TRUE);
+    if (isset($this->entityInfo['entity class']) && $class = $this->entityInfo['entity class']) {
+      return new $class($values, $this->entityType);
+    }
+    return (object) $values;
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @return
+   *   A serialized string in JSON format suitable for the import() method.
+   */
+  public function export($entity, $prefix = '') {
+    $vars = get_object_vars($entity);
+    unset($vars['is_new']);
+    return entity_var_json_export($vars, $prefix);
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $export
+   *   A serialized string in JSON format as produced by the export() method.
+   */
+  public function import($export) {
+    $vars = drupal_json_decode($export);
+    if (is_array($vars)) {
+      return $this->create($vars);
+    }
+    return FALSE;
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $content
+   *   Optionally. Allows pre-populating the built content to ease overridding
+   *   this method.
+   */
+  public function buildContent($entity, $view_mode = 'full', $langcode = NULL, $content = array()) {
+    // Remove previously built content, if exists.
+    $entity->content = $content;
+    $langcode = isset($langcode) ? $langcode : $GLOBALS['language_content']->language;
+
+    // By default add in properties for all defined extra fields.
+    if ($extra_field_controller = entity_get_extra_fields_controller($this->entityType)) {
+      $wrapper = entity_metadata_wrapper($this->entityType, $entity);
+      $extra = $extra_field_controller->fieldExtraFields();
+      $type_extra = &$extra[$this->entityType][$this->entityType]['display'];
+      $bundle_extra = &$extra[$this->entityType][$wrapper->getBundle()]['display'];
+
+      foreach ($wrapper as $name => $property) {
+        if (isset($type_extra[$name]) || isset($bundle_extra[$name])) {
+          $this->renderEntityProperty($wrapper, $name, $property, $view_mode, $langcode, $entity->content);
+        }
+      }
+    }
+
+    // Add in fields.
+    if (!empty($this->entityInfo['fieldable'])) {
+      // Perform the preparation tasks if they have not been performed yet.
+      // An internal flag prevents the operation from running twice.
+      $key = isset($entity->{$this->idKey}) ? $entity->{$this->idKey} : NULL;
+      field_attach_prepare_view($this->entityType, array($key => $entity), $view_mode);
+      $entity->content += field_attach_view($this->entityType, $entity, $view_mode, $langcode);
+    }
+    // Invoke hook_ENTITY_view() to allow modules to add their additions.
+    if (module_exists('rules')) {
+      rules_invoke_all($this->entityType . '_view', $entity, $view_mode, $langcode);
+    }
+    else {
+      module_invoke_all($this->entityType . '_view', $entity, $view_mode, $langcode);
+    }
+    module_invoke_all('entity_view', $entity, $this->entityType, $view_mode, $langcode);
+    $build = $entity->content;
+    unset($entity->content);
+    return $build;
+  }
+
+  /**
+   * Renders a single entity property.
+   */
+  protected function renderEntityProperty($wrapper, $name, $property, $view_mode, $langcode, &$content) {
+    $info = $property->info();
+
+    $content[$name] = array(
+      '#label_hidden' => FALSE,
+      '#label' => $info['label'],
+      '#entity_wrapped' => $wrapper,
+      '#theme' => 'entity_property',
+      '#property_name' => $name,
+      '#access' => $property->access('view'),
+      '#entity_type' => $this->entityType,
+    );
+    $content['#attached']['css']['entity.theme'] = drupal_get_path('module', 'entity') . '/theme/entity.theme.css';
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   */
+  public function view($entities, $view_mode = 'full', $langcode = NULL, $page = NULL) {
+    // For Field API and entity_prepare_view, the entities have to be keyed by
+    // (numeric) id.
+    $entities = entity_key_array_by_property($entities, $this->idKey);
+    if (!empty($this->entityInfo['fieldable'])) {
+      field_attach_prepare_view($this->entityType, $entities, $view_mode);
+    }
+    entity_prepare_view($this->entityType, $entities);
+    $langcode = isset($langcode) ? $langcode : $GLOBALS['language_content']->language;
+
+    $view = array();
+    foreach ($entities as $entity) {
+      $build = entity_build_content($this->entityType, $entity, $view_mode, $langcode);
+      $build += array(
+        // If the entity type provides an implementation, use this instead the
+        // generic one.
+        // @see template_preprocess_entity()
+        '#theme' => 'entity',
+        '#entity_type' => $this->entityType,
+        '#entity' => $entity,
+        '#view_mode' => $view_mode,
+        '#language' => $langcode,
+        '#page' => $page,
+      );
+      // Allow modules to modify the structured entity.
+      drupal_alter(array($this->entityType . '_view', 'entity_view'), $build, $this->entityType);
+      $key = isset($entity->{$this->idKey}) ? $entity->{$this->idKey} : NULL;
+      $view[$this->entityType][$key] = $build;
+    }
+    return $view;
+  }
+}
+
+/**
+ * A controller implementing exportables stored in the database.
+ */
+class EntityAPIControllerExportable extends EntityAPIController {
+
+  protected $entityCacheByName = array();
+  protected $nameKey, $statusKey, $moduleKey;
+
+  /**
+   * Overridden.
+   *
+   * Allows specifying a name key serving as uniform identifier for this entity
+   * type while still internally we are using numeric identifieres.
+   */
+  public function __construct($entityType) {
+    parent::__construct($entityType);
+    // Use the name key as primary identifier.
+    $this->nameKey = isset($this->entityInfo['entity keys']['name']) ? $this->entityInfo['entity keys']['name'] : $this->idKey;
+    if (!empty($this->entityInfo['exportable'])) {
+      $this->statusKey = isset($this->entityInfo['entity keys']['status']) ? $this->entityInfo['entity keys']['status'] : 'status';
+      $this->moduleKey = isset($this->entityInfo['entity keys']['module']) ? $this->entityInfo['entity keys']['module'] : 'module';
+    }
+  }
+
+  /**
+   * Support loading by name key.
+   */
+  protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
+    // Add the id condition ourself, as we might have a separate name key.
+    $query = parent::buildQuery(array(), $conditions, $revision_id);
+    if ($ids) {
+      // Support loading by numeric ids as well as by machine names.
+      $key = is_numeric(reset($ids)) ? $this->idKey : $this->nameKey;
+      $query->condition("base.$key", $ids, 'IN');
+    }
+    return $query;
+  }
+
+  /**
+   * Overridden to support passing numeric ids as well as names as $ids.
+   */
+  public function load($ids = array(), $conditions = array()) {
+    $entities = array();
+
+    // Only do something if loaded by names.
+    if (!$ids || $this->nameKey == $this->idKey || is_numeric(reset($ids))) {
+      return parent::load($ids, $conditions);
+    }
+
+    // Revisions are not statically cached, and require a different query to
+    // other conditions, so separate the revision id into its own variable.
+    if ($this->revisionKey && isset($conditions[$this->revisionKey])) {
+      $revision_id = $conditions[$this->revisionKey];
+      unset($conditions[$this->revisionKey]);
+    }
+    else {
+      $revision_id = FALSE;
+    }
+    $passed_ids = !empty($ids) ? array_flip($ids) : FALSE;
+
+    // Care about the static cache.
+    if ($this->cache && !$revision_id) {
+      $entities = $this->cacheGetByName($ids, $conditions);
+    }
+    // If any entities were loaded, remove them from the ids still to load.
+    if ($entities) {
+      $ids = array_keys(array_diff_key($passed_ids, $entities));
+    }
+
+    $entities_by_id = parent::load($ids, $conditions);
+    $entities += entity_key_array_by_property($entities_by_id, $this->nameKey);
+
+    // Ensure that the returned array is keyed by numeric id and ordered the
+    // same as the original $ids array and remove any invalid ids.
+    $return = array();
+    foreach ($passed_ids as $name => $value) {
+      if (isset($entities[$name])) {
+        $return[$entities[$name]->{$this->idKey}] = $entities[$name];
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController::cacheGet()
+   */
+  protected function cacheGet($ids, $conditions = array()) {
+    if (!empty($this->entityCache) && $ids !== array()) {
+      $entities = $ids ? array_intersect_key($this->entityCache, array_flip($ids)) : $this->entityCache;
+      return $this->applyConditions($entities, $conditions);
+    }
+    return array();
+  }
+
+  /**
+   * Like cacheGet() but keyed by name.
+   */
+  protected function cacheGetByName($names, $conditions = array()) {
+    if (!empty($this->entityCacheByName) && $names !== array() && $names) {
+      // First get the entities by ids, then apply the conditions.
+      // Generally, we make use of $this->entityCache, but if we are loading by
+      // name, we have to use $this->entityCacheByName.
+      $entities = array_intersect_key($this->entityCacheByName, array_flip($names));
+      return $this->applyConditions($entities, $conditions);
+    }
+    return array();
+  }
+
+  protected function applyConditions($entities, $conditions = array()) {
+    if ($conditions) {
+      foreach ($entities as $key => $entity) {
+        $entity_values = (array) $entity;
+        // We cannot use array_diff_assoc() here because condition values can
+        // also be arrays, e.g. '$conditions = array('status' => array(1, 2))'
+        foreach ($conditions as $condition_key => $condition_value) {
+          if (is_array($condition_value)) {
+            if (!isset($entity_values[$condition_key]) || !in_array($entity_values[$condition_key], $condition_value)) {
+              unset($entities[$key]);
+            }
+          }
+          elseif (!isset($entity_values[$condition_key]) || $entity_values[$condition_key] != $condition_value) {
+            unset($entities[$key]);
+          }
+        }
+      }
+    }
+    return $entities;
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController::cacheSet()
+   */
+  protected function cacheSet($entities) {
+    $this->entityCache += $entities;
+    // If we have a name key, also support static caching when loading by name.
+    if ($this->nameKey != $this->idKey) {
+      $this->entityCacheByName += entity_key_array_by_property($entities, $this->nameKey);
+    }
+  }
+
+  /**
+   * Overridden.
+   * @see DrupalDefaultEntityController::attachLoad()
+   *
+   * Changed to call type-specific hook with the entities keyed by name if they
+   * have one.
+   */
+  protected function attachLoad(&$queried_entities, $revision_id = FALSE) {
+    // Attach fields.
+    if ($this->entityInfo['fieldable']) {
+      if ($revision_id) {
+        field_attach_load_revision($this->entityType, $queried_entities);
+      }
+      else {
+        field_attach_load($this->entityType, $queried_entities);
+      }
+    }
+
+    // Call hook_entity_load().
+    foreach (module_implements('entity_load') as $module) {
+      $function = $module . '_entity_load';
+      $function($queried_entities, $this->entityType);
+    }
+    // Call hook_TYPE_load(). The first argument for hook_TYPE_load() are
+    // always the queried entities, followed by additional arguments set in
+    // $this->hookLoadArguments.
+    // For entities with a name key, pass the entities keyed by name to the
+    // specific load hook.
+    if ($this->nameKey != $this->idKey) {
+      $entities_by_name = entity_key_array_by_property($queried_entities, $this->nameKey);
+    }
+    else {
+      $entities_by_name = $queried_entities;
+    }
+    $args = array_merge(array($entities_by_name), $this->hookLoadArguments);
+    foreach (module_implements($this->entityInfo['load hook']) as $module) {
+      call_user_func_array($module . '_' . $this->entityInfo['load hook'], $args);
+    }
+  }
+
+  public function resetCache(array $ids = NULL) {
+    $this->cacheComplete = FALSE;
+    if (isset($ids)) {
+      foreach (array_intersect_key($this->entityCache, array_flip($ids)) as $id => $entity) {
+        unset($this->entityCacheByName[$this->entityCache[$id]->{$this->nameKey}]);
+        unset($this->entityCache[$id]);
+      }
+    }
+    else {
+      $this->entityCache = array();
+      $this->entityCacheByName = array();
+    }
+  }
+
+  /**
+   * Overridden to care about reverted entities.
+   */
+  public function delete($ids, DatabaseTransaction $transaction = NULL) {
+    $entities = $ids ? $this->load($ids) : FALSE;
+    if ($entities) {
+      parent::delete($ids, $transaction);
+
+      foreach ($entities as $id => $entity) {
+        if (entity_has_status($this->entityType, $entity, ENTITY_IN_CODE)) {
+          entity_defaults_rebuild(array($this->entityType));
+          break;
+        }
+      }
+    }
+  }
+
+  /**
+   * Overridden to care about reverted bundle entities and to skip Rules.
+   */
+  public function invoke($hook, $entity) {
+    if ($hook == 'delete') {
+      // To ease figuring out whether this is a revert, make sure that the
+      // entity status is updated in case the providing module has been
+      // disabled.
+      if (entity_has_status($this->entityType, $entity, ENTITY_IN_CODE) && !module_exists($entity->{$this->moduleKey})) {
+        $entity->{$this->statusKey} = ENTITY_CUSTOM;
+      }
+      $is_revert = entity_has_status($this->entityType, $entity, ENTITY_IN_CODE);
+    }
+
+    if (!empty($this->entityInfo['fieldable']) && function_exists($function = 'field_attach_' . $hook)) {
+      $function($this->entityType, $entity);
+    }
+
+    if (isset($this->entityInfo['bundle of']) && $type = $this->entityInfo['bundle of']) {
+      // Call field API bundle attachers for the entity we are a bundle of.
+      if ($hook == 'insert') {
+        field_attach_create_bundle($type, $entity->{$this->bundleKey});
+      }
+      elseif ($hook == 'delete' && !$is_revert) {
+        field_attach_delete_bundle($type, $entity->{$this->bundleKey});
+      }
+      elseif ($hook == 'update' && $id = $entity->{$this->nameKey}) {
+        if ($entity->original->{$this->bundleKey} != $entity->{$this->bundleKey}) {
+          field_attach_rename_bundle($type, $entity->original->{$this->bundleKey}, $entity->{$this->bundleKey});
+        }
+      }
+    }
+    // Invoke the hook.
+    module_invoke_all($this->entityType . '_' . $hook, $entity);
+    // Invoke the respective entity level hook.
+    if ($hook == 'presave' || $hook == 'insert' || $hook == 'update' || $hook == 'delete') {
+      module_invoke_all('entity_' . $hook, $entity, $this->entityType);
+    }
+  }
+
+  /**
+   * Overridden to care exportables that are overridden.
+   */
+  public function save($entity, DatabaseTransaction $transaction = NULL) {
+    // Preload $entity->original by name key if necessary.
+    if (!empty($entity->{$this->nameKey}) && empty($entity->{$this->idKey}) && !isset($entity->original)) {
+      $entity->original = entity_load_unchanged($this->entityType, $entity->{$this->nameKey});
+    }
+    // Update the status for entities getting overridden.
+    if (entity_has_status($this->entityType, $entity, ENTITY_IN_CODE) && empty($entity->is_rebuild)) {
+      $entity->{$this->statusKey} |= ENTITY_CUSTOM;
+    }
+    return parent::save($entity, $transaction);
+  }
+
+  /**
+   * Overridden.
+   */
+  public function export($entity, $prefix = '') {
+    $vars = get_object_vars($entity);
+    unset($vars[$this->statusKey], $vars[$this->moduleKey], $vars['is_new']);
+    if ($this->nameKey != $this->idKey) {
+      unset($vars[$this->idKey]);
+    }
+    return entity_var_json_export($vars, $prefix);
+  }
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   */
+  public function view($entities, $view_mode = 'full', $langcode = NULL, $page = NULL) {
+    $view = parent::view($entities, $view_mode, $langcode, $page);
+
+    if ($this->nameKey != $this->idKey) {
+      // Re-key the view array to be keyed by name.
+      $return = array();
+      foreach ($view[$this->entityType] as $id => $content) {
+        $key = isset($content['#entity']->{$this->nameKey}) ? $content['#entity']->{$this->nameKey} : NULL;
+        $return[$this->entityType][$key] = $content;
+      }
+      $view = $return;
+    }
+    return $view;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/includes/entity.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,320 @@
+<?php
+
+/**
+ * @file
+ * Provides a base class for entities.
+ */
+
+/**
+ * A common class for entities.
+ *
+ * It's suggested, but not required, to extend this class and to override
+ * __construct() in order to specify a fixed entity type.
+ *
+ * For providing an entity label and URI it is suggested to override the
+ * defaultLabel() and defaultUri() methods, and to specify the
+ * entity_class_label() and entity_class_uri() as respective callbacks in
+ * hook_entity_info(). That way modules are able to override your defaults
+ * by altering the hook_entity_info() callbacks, while $entity->label() and
+ * $entity->uri() reflect this changes as well.
+ *
+ * Defaults for entity properties can be easily defined by adding class
+ * properties, e.g.:
+ * @code
+ *   public $name = '';
+ *   public $count = 0;
+ * @endcode
+ */
+class Entity {
+
+  protected $entityType;
+  protected $entityInfo;
+  protected $idKey, $nameKey, $statusKey;
+  protected $defaultLabel = FALSE;
+
+  /**
+   * Creates a new entity.
+   *
+   * @see entity_create()
+   */
+  public function __construct(array $values = array(), $entityType = NULL) {
+    if (empty($entityType)) {
+      throw new Exception('Cannot create an instance of Entity without a specified entity type.');
+    }
+    $this->entityType = $entityType;
+    $this->setUp();
+    // Set initial values.
+    foreach ($values as $key => $value) {
+      $this->$key = $value;
+    }
+  }
+
+  /**
+   * Set up the object instance on construction or unserializiation.
+   */
+  protected function setUp() {
+    $this->entityInfo = entity_get_info($this->entityType);
+    $this->idKey = $this->entityInfo['entity keys']['id'];
+    $this->nameKey = isset($this->entityInfo['entity keys']['name']) ? $this->entityInfo['entity keys']['name'] : $this->idKey;
+    $this->statusKey = empty($info['entity keys']['status']) ? 'status' : $info['entity keys']['status'];
+  }
+
+  /**
+   * Returns the internal, numeric identifier.
+   *
+   * Returns the numeric identifier, even if the entity type has specified a
+   * name key. In the latter case, the numeric identifier is supposed to be used
+   * when dealing generically with entities or internally to refer to an entity,
+   * i.e. in a relational database. If unsure, use Entity:identifier().
+   */
+  public function internalIdentifier() {
+    return isset($this->{$this->idKey}) ? $this->{$this->idKey} : NULL;
+  }
+
+  /**
+   * Returns the entity identifier, i.e. the entities name or numeric id.
+   *
+   * @return
+   *   The identifier of the entity. If the entity type makes use of a name key,
+   *   the name is returned, else the numeric id.
+   *
+   * @see entity_id()
+   */
+  public function identifier() {
+    return isset($this->{$this->nameKey}) ? $this->{$this->nameKey} : NULL;
+  }
+
+  /**
+   * Returns the info of the type of the entity.
+   *
+   * @see entity_get_info()
+   */
+  public function entityInfo() {
+    return $this->entityInfo;
+  }
+
+  /**
+   * Returns the type of the entity.
+   */
+  public function entityType() {
+    return $this->entityType;
+  }
+
+  /**
+   * Returns the bundle of the entity.
+   *
+   * @return
+   *   The bundle of the entity. Defaults to the entity type if the entity type
+   *   does not make use of different bundles.
+   */
+  public function bundle() {
+    return !empty($this->entityInfo['entity keys']['bundle']) ? $this->{$this->entityInfo['entity keys']['bundle']} : $this->entityType;
+  }
+
+  /**
+   * Returns the label of the entity.
+   *
+   * Modules may alter the label by specifying another 'label callback' using
+   * hook_entity_info_alter().
+   *
+   * @see entity_label()
+   */
+  public function label() {
+    // If the default label flag is enabled, this is being invoked recursively.
+    // In this case we need to use our default label callback directly. This may
+    // happen if a module provides a label callback implementation different
+    // from ours, but then invokes Entity::label() or entity_class_label() from
+    // there.
+    if ($this->defaultLabel || (isset($this->entityInfo['label callback']) && $this->entityInfo['label callback'] == 'entity_class_label')) {
+      return $this->defaultLabel();
+    }
+    $this->defaultLabel = TRUE;
+    $label = entity_label($this->entityType, $this);
+    $this->defaultLabel = FALSE;
+    return $label;
+  }
+
+  /**
+   * Defines the entity label if the 'entity_class_label' callback is used.
+   *
+   * Specify 'entity_class_label' as 'label callback' in hook_entity_info() to
+   * let the entity label point to this method. Override this in order to
+   * implement a custom default label.
+   */
+  protected function defaultLabel() {
+    // Add in the translated specified label property.
+    return $this->getTranslation($this->entityInfo['entity keys']['label']);
+  }
+
+  /**
+   * Returns the uri of the entity just as entity_uri().
+   *
+   * Modules may alter the uri by specifying another 'uri callback' using
+   * hook_entity_info_alter().
+   *
+   * @see entity_uri()
+   */
+  public function uri() {
+    if (isset($this->entityInfo['uri callback']) && $this->entityInfo['uri callback'] == 'entity_class_uri') {
+      return $this->defaultUri();
+    }
+    return entity_uri($this->entityType, $this);
+  }
+
+  /**
+   * Override this in order to implement a custom default URI and specify
+   * 'entity_class_uri' as 'uri callback' hook_entity_info().
+   */
+  protected function defaultUri() {
+    return array('path' => 'default/' . $this->identifier());
+  }
+
+  /**
+   * Checks if the entity has a certain exportable status.
+   *
+   * @param $status
+   *   A status constant, i.e. one of ENTITY_CUSTOM, ENTITY_IN_CODE,
+   *   ENTITY_OVERRIDDEN or ENTITY_FIXED.
+   *
+   * @return
+   *   For exportable entities TRUE if the entity has the status, else FALSE.
+   *   In case the entity is not exportable, NULL is returned.
+   *
+   * @see entity_has_status()
+   */
+  public function hasStatus($status) {
+    if (!empty($this->entityInfo['exportable'])) {
+      return isset($this->{$this->statusKey}) && ($this->{$this->statusKey} & $status) == $status;
+    }
+  }
+
+  /**
+   * Permanently saves the entity.
+   *
+   * @see entity_save()
+   */
+  public function save() {
+    return entity_get_controller($this->entityType)->save($this);
+  }
+
+  /**
+   * Permanently deletes the entity.
+   *
+   * @see entity_delete()
+   */
+  public function delete() {
+    $id = $this->identifier();
+    if (isset($id)) {
+      entity_get_controller($this->entityType)->delete(array($id));
+    }
+  }
+
+  /**
+   * Exports the entity.
+   *
+   * @see entity_export()
+   */
+  public function export($prefix = '') {
+    return entity_get_controller($this->entityType)->export($this, $prefix);
+  }
+
+  /**
+   * Generate an array for rendering the entity.
+   *
+   * @see entity_view()
+   */
+  public function view($view_mode = 'full', $langcode = NULL, $page = NULL) {
+    return entity_get_controller($this->entityType)->view(array($this), $view_mode, $langcode, $page);
+  }
+
+  /**
+   * Builds a structured array representing the entity's content.
+   *
+   * @see entity_build_content()
+   */
+  public function buildContent($view_mode = 'full', $langcode = NULL) {
+    return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode);
+  }
+
+  /**
+   * Gets the raw, translated value of a property or field.
+   *
+   * Supports retrieving field translations as well as i18n string translations.
+   *
+   * Note that this returns raw data values, which might not reflect what
+   * has been declared for hook_entity_property_info() as no 'getter callbacks'
+   * are invoked or no referenced entities are loaded. For retrieving values
+   * reflecting the property info make use of entity metadata wrappers, see
+   * entity_metadata_wrapper().
+   *
+   * @param $property_name
+   *   The name of the property to return; e.g., 'title'.
+   * @param $langcode
+   *   (optional) The language code of the language to which the value should
+   *   be translated. If set to NULL, the default display language is being
+   *   used.
+   *
+   * @return
+   *   The raw, translated property value; or the raw, un-translated value if no
+   *   translation is available.
+   *
+   * @todo Implement an analogous setTranslation() method for updating.
+   */
+  public function getTranslation($property, $langcode = NULL) {
+    $all_info = entity_get_all_property_info($this->entityType);
+    // Assign by reference to avoid triggering notices if metadata is missing.
+    $property_info = &$all_info[$property];
+
+    if (!empty($property_info['translatable'])) {
+      if (!empty($property_info['field'])) {
+        return field_get_items($this->entityType, $this, $property, $langcode);
+      }
+      elseif (!empty($property_info['i18n string'])) {
+        $name = $this->entityInfo['module'] . ':' . $this->entityType . ':' . $this->identifier() . ':' . $property;
+        return entity_i18n_string($name, $this->$property, $langcode);
+      }
+    }
+    return $this->$property;
+  }
+
+  /**
+   * Checks whether the entity is the default revision.
+   *
+   * @return Boolean
+   *
+   * @see entity_revision_is_default()
+   */
+  public function isDefaultRevision() {
+    if (!empty($this->entityInfo['entity keys']['revision'])) {
+      $key = !empty($this->entityInfo['entity keys']['default revision']) ? $this->entityInfo['entity keys']['default revision'] : 'default_revision';
+      return !empty($this->$key);
+    }
+    return TRUE;
+  }
+
+  /**
+   * Magic method to only serialize what's necessary.
+   */
+  public function __sleep() {
+    $vars = get_object_vars($this);
+    unset($vars['entityInfo'], $vars['idKey'], $vars['nameKey'], $vars['statusKey']);
+    // Also key the returned array with the variable names so the method may
+    // be easily overridden and customized.
+    return drupal_map_assoc(array_keys($vars));
+  }
+
+  /**
+   * Magic method to invoke setUp() on unserialization.
+   */
+  public function __wakeup() {
+    $this->setUp();
+  }
+}
+
+/**
+ * These classes are deprecated by "Entity" and are only here for backward
+ * compatibility reasons.
+ */
+class EntityDB extends Entity {}
+class EntityExtendable extends Entity {}
+class EntityDBExtendable extends Entity {}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/includes/entity.property.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,650 @@
+<?php
+
+/**
+ * @file
+ * Provides API functions around hook_entity_property_info(). Also see
+ * entity.info.inc, which cares for providing entity property info for all core
+ * entity types.
+ */
+
+/**
+ * Get the entity property info array of an entity type.
+ *
+ * @param $entity_type
+ *   The entity type, e.g. node, for which the info shall be returned, or NULL
+ *   to return an array with info about all types.
+ *
+ * @see hook_entity_property_info()
+ * @see hook_entity_property_info_alter()
+ */
+function entity_get_property_info($entity_type = NULL) {
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['info'] = &drupal_static(__FUNCTION__);
+  }
+  $info = &$drupal_static_fast['info'];
+
+  // hook_entity_property_info() includes translated strings, so each language
+  // is cached separately.
+  $langcode = $GLOBALS['language']->language;
+
+  if (empty($info)) {
+    if ($cache = cache_get("entity_property_info:$langcode")) {
+      $info = $cache->data;
+    }
+    else {
+      $info = module_invoke_all('entity_property_info');
+      // Let other modules alter the entity info.
+      drupal_alter('entity_property_info', $info);
+      cache_set("entity_property_info:$langcode", $info);
+    }
+  }
+  return empty($entity_type) ? $info : (isset($info[$entity_type]) ? $info[$entity_type] : array());
+}
+
+/**
+ * Returns the default information for an entity property.
+ *
+ * @return
+ *   An array of optional property information keys mapped to their defaults.
+ *
+ * @see hook_entity_property_info()
+ */
+function entity_property_info_defaults() {
+  return array(
+    'type' => 'text',
+    'getter callback' => 'entity_property_verbatim_get',
+  );
+}
+
+/**
+ * Gets an array of info about all properties of a given entity type.
+ *
+ * In contrast to entity_get_property_info(), this function returns info about
+ * all properties the entity might have, thus it adds an all properties assigned
+ * to entity bundles.
+ *
+ * @param $entity_type
+ *   (optiona) The entity type to return properties for.
+ *
+ * @return
+ *   An array of info about properties. If the type is ommitted, all known
+ *   properties are returned.
+ */
+function entity_get_all_property_info($entity_type = NULL) {
+  if (!isset($entity_type)) {
+    // Retrieve all known properties.
+    $properties = array();
+    foreach (entity_get_info() as $entity_type => $info) {
+      $properties += entity_get_all_property_info($entity_type);
+    }
+    return $properties;
+  }
+  // Else retrieve the properties of the given entity type only.
+  $info = entity_get_property_info($entity_type);
+  $info += array('properties' => array(), 'bundles' => array());
+  // Add all bundle properties.
+  foreach ($info['bundles'] as $bundle => $bundle_info) {
+    $bundle_info += array('properties' => array());
+    $info['properties'] += $bundle_info['properties'];
+  }
+  return $info['properties'];
+}
+
+/**
+ * Queries for entities having the given property value.
+ *
+ * @param $entity_type
+ *   The type of the entity.
+ * @param $property
+ *   The name of the property to query for.
+ * @param $value
+ *   A single property value or an array of possible values to query for.
+ * @param $limit
+ *   Limit the numer of results. Defaults to 30.
+ *
+ * @return
+ *   An array of entity ids or NULL if there is no information how to query for
+ *   the given property.
+ */
+function entity_property_query($entity_type, $property, $value, $limit = 30) {
+  $properties = entity_get_all_property_info($entity_type);
+  $info = $properties[$property] + array('type' => 'text', 'queryable' => !empty($properties[$property]['schema field']));
+
+  // We still support the deprecated query callback, so just add in EFQ-based
+  // callbacks in case 'queryable' is set to TRUE and make use of the callback.
+  if ($info['queryable'] && empty($info['query callback'])) {
+    $info['query callback'] = !empty($info['field']) ? 'entity_metadata_field_query' : 'entity_metadata_table_query';
+  }
+
+  $type = $info['type'];
+  // Make sure an entity or a list of entities are passed on as identifiers
+  // with the help of the wrappers. For that ensure the data type matches the
+  // passed on value(s).
+  if (is_array($value) && !entity_property_list_extract_type($type)) {
+    $type = 'list<' . $type . '>';
+  }
+  elseif (!is_array($value) && entity_property_list_extract_type($type)) {
+    $type = entity_property_list_extract_type($type);
+  }
+
+  $wrapper = entity_metadata_wrapper($type, $value);
+  $value = $wrapper->value(array('identifier' => TRUE));
+
+  if (!empty($info['query callback'])) {
+    return $info['query callback']($entity_type, $property, $value, $limit);
+  }
+}
+
+/**
+ * Resets the cached information of hook_entity_property_info().
+ */
+function entity_property_info_cache_clear() {
+  drupal_static_reset('entity_get_property_info');
+  // Clear all languages.
+  cache_clear_all('entity_property_info:', 'cache', TRUE);
+}
+
+/**
+ * Implements hook_hook_info().
+ */
+function entity_hook_info() {
+  $hook_info['entity_property_info'] = array(
+    'group' => 'info',
+  );
+  $hook_info['entity_property_info_alter'] = array(
+    'group' => 'info',
+  );
+  return $hook_info;
+}
+
+/**
+ * Implements hook_field_info_alter().
+ * Defines default property types for core field types.
+ */
+function entity_field_info_alter(&$field_info) {
+  if (module_exists('number')) {
+    $field_info['number_integer']['property_type'] = 'integer';
+    $field_info['number_decimal']['property_type'] = 'decimal';
+    $field_info['number_float']['property_type'] = 'decimal';
+  }
+  if (module_exists('text')) {
+    $field_info['text']['property_type'] = 'text';
+    $field_info['text']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
+    $field_info['text_long']['property_type'] = 'text';
+    $field_info['text_long']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
+    $field_info['text_with_summary']['property_type'] = 'field_item_textsummary';
+    $field_info['text_with_summary']['property_callbacks'][] = 'entity_metadata_field_text_property_callback';
+  }
+  if (module_exists('list')) {
+    $field_info['list_integer']['property_type'] = 'integer';
+    $field_info['list_boolean']['property_type'] = 'boolean';
+    $field_info['list_float']['property_type'] = 'decimal';
+    $field_info['list_text']['property_type'] = 'text';
+  }
+  if (module_exists('taxonomy')) {
+    $field_info['taxonomy_term_reference']['property_type'] = 'taxonomy_term';
+    $field_info['taxonomy_term_reference']['property_callbacks'][] = 'entity_metadata_field_term_reference_callback';
+  }
+  if (module_exists('file')) {
+    // The callback specifies a custom data structure matching the file field
+    // items. We introduce a custom type name for this data structure.
+    $field_info['file']['property_type'] = 'field_item_file';
+    $field_info['file']['property_callbacks'][] = 'entity_metadata_field_file_callback';
+  }
+  if (module_exists('image')) {
+    // The callback specifies a custom data structure matching the image field
+    // items. We introduce a custom type name for this data structure.
+    $field_info['image']['property_type'] = 'field_item_image';
+    $field_info['image']['property_callbacks'][] = 'entity_metadata_field_file_callback';
+    $field_info['image']['property_callbacks'][] = 'entity_metadata_field_image_callback';
+  }
+}
+
+/**
+ * Implements hook_field_create_instance().
+ * Clear the cache when a field instance changed.
+ */
+function entity_field_create_instance() {
+  entity_property_info_cache_clear();
+}
+
+/**
+ * Implements hook_field_delete_instance().
+ * Clear the cache when a field instance changed.
+ */
+function entity_field_delete_instance() {
+  entity_property_info_cache_clear();
+}
+
+/**
+ * Implements hook_field_update_instance().
+ * Clear the cache when a field instance changed.
+ */
+function entity_field_update_instance() {
+  entity_property_info_cache_clear();
+}
+
+/**
+ * Verifies that the given data can be safely used as the given type regardless
+ * of the PHP variable type of $data. Example: the string "15" is a valid
+ * integer, but "15nodes" is not.
+ *
+ * @return
+ *   Whether the data is valid for the given type.
+ */
+function entity_property_verify_data_type($data, $type) {
+  // As this may be called very often statically cache the entity info using
+  // the fast pattern.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    // Make use of the same static as entity info.
+    entity_get_info();
+    $drupal_static_fast['entity_info'] = &drupal_static('entity_get_info');
+  }
+  $info = &$drupal_static_fast['entity_info'];
+
+  // First off check for entities, which may be represented by their ids too.
+  if (isset($info[$type])) {
+    if (is_object($data)) {
+      return TRUE;
+    }
+    elseif (isset($info[$type]['entity keys']['name'])) {
+      // Read the data type of the name key from the metadata if available.
+      $key = $info[$type]['entity keys']['name'];
+      $property_info = entity_get_property_info($type);
+      $property_type = isset($property_info['properties'][$key]['type']) ? $property_info['properties'][$key]['type'] : 'token';
+      return entity_property_verify_data_type($data, $property_type);
+    }
+    return entity_property_verify_data_type($data, empty($info[$type]['fieldable']) ? 'text' : 'integer');
+  }
+
+  switch ($type) {
+    case 'site':
+    case 'unknown':
+      return TRUE;
+    case 'date':
+    case 'duration':
+    case 'integer':
+      return is_numeric($data) && strpos($data, '.') === FALSE;
+    case 'decimal':
+      return is_numeric($data);
+    case 'text':
+      return is_scalar($data);
+    case 'token':
+      return is_scalar($data) && preg_match('!^[a-z][a-z0-9_]*$!', $data);
+    case 'boolean':
+      return is_scalar($data) && (is_bool($data) || $data == 0 || $data == 1);
+    case 'uri':
+      return valid_url($data, TRUE);
+    case 'list':
+      return (is_array($data) && array_values($data) == $data) || (is_object($data) && $data instanceof EntityMetadataArrayObject);
+    case 'entity':
+      return is_object($data) && $data instanceof EntityDrupalWrapper;
+    default:
+    case 'struct':
+      return is_object($data) || is_array($data);
+  }
+}
+
+/**
+ * Creates the entity object for an array of given property values.
+ *
+ * @param $entity_type
+ *   The entity type to create an entity for.
+ * @param $values
+ *   An array of values as described by the entity's property info. All entity
+ *   properties of the given entity type that are marked as required, must be
+ *   present.
+ *   If the passed values have no matching property, their value will be
+ *   assigned to the entity directly, without the use of the metadata-wrapper
+ *   property.
+ *
+ * @return EntityDrupalWrapper
+ *   An EntityDrupalWrapper wrapping the newly created entity or FALSE, if
+ *   there were no information how to create the entity.
+ */
+function entity_property_values_create_entity($entity_type, $values = array()) {
+  if (entity_type_supports($entity_type, 'create')) {
+    $info = entity_get_info($entity_type);
+    // Create the initial entity by passing the values for all 'entity keys'
+    // to entity_create().
+    $entity_keys = array_filter($info['entity keys']);
+    $creation_values = array_intersect_key($values, array_flip($entity_keys));
+
+    // In case the bundle key does not match the property that sets it, ensure
+    // the bundle key is initialized somehow, so entity_extract_ids()
+    // does not bail out during wrapper creation.
+    if (!empty($info['entity keys']['bundle'])) {
+      $creation_values += array($info['entity keys']['bundle'] => FALSE);
+    }
+    $entity = entity_create($entity_type, $creation_values);
+
+    // Now set the remaining values using the wrapper.
+    $wrapper = entity_metadata_wrapper($entity_type, $entity);
+    foreach ($values as $key => $value) {
+      if (!in_array($key, $info['entity keys'])) {
+        if (isset($wrapper->$key)) {
+          $wrapper->$key->set($value);
+        }
+        else {
+          $entity->$key = $value;
+        }
+      }
+    }
+    // @todo: Once we require Drupal 7.7 or later, verify the entity has
+    // now a valid bundle and throw the EntityMalformedException if not.
+    return $wrapper;
+  }
+  return FALSE;
+}
+
+
+/**
+ * Extracts the contained type for a list type string like list<date>.
+ *
+ * @return
+ *   The contained type or FALSE, if the given type string is no list.
+ */
+function entity_property_list_extract_type($type) {
+  if (strpos($type, 'list<') === 0 && $type[strlen($type)-1] == '>') {
+    return substr($type, 5, -1);
+  }
+  return FALSE;
+}
+
+/**
+ * Extracts the innermost type for a type string like list<list<date>>.
+ *
+ * @param $type
+ *   The type to examine.
+ *
+ * @return
+ *   For list types, the innermost type. The type itself otherwise.
+ */
+function entity_property_extract_innermost_type($type) {
+  while (strpos($type, 'list<') === 0 && $type[strlen($type)-1] == '>') {
+    $type = substr($type, 5, -1);
+  }
+  return $type;
+}
+
+/**
+ * Gets the property just as it is set in the data.
+ */
+function entity_property_verbatim_get($data, array $options, $name, $type, $info) {
+  $name = isset($info['schema field']) ? $info['schema field'] : $name;
+  if ((is_array($data) || (is_object($data) && $data instanceof ArrayAccess)) && isset($data[$name])) {
+    return $data[$name];
+  }
+  elseif (is_object($data) && isset($data->$name)) {
+    // Incorporate i18n_string translations. We may rely on the entity class
+    // here as its usage is required by the i18n integration.
+    if (isset($options['language']) && !empty($info['i18n string'])) {
+      return $data->getTranslation($name, $options['language']->language);
+    }
+    else {
+      return $data->$name;
+    }
+  }
+  return NULL;
+}
+
+/**
+ * Date values are converted from ISO strings to timestamp if needed.
+ */
+function entity_property_verbatim_date_get($data, array $options, $name, $type, $info) {
+  $name = isset($info['schema field']) ? $info['schema field'] : $name;
+  return is_numeric($data[$name]) ? $data[$name] : strtotime($data[$name], REQUEST_TIME);
+}
+
+/**
+ * Sets the property to the given value. May be used as 'setter callback'.
+ */
+function entity_property_verbatim_set(&$data, $name, $value, $langcode, $type, $info) {
+  $name = isset($info['schema field']) ? $info['schema field'] : $name;
+  if (is_array($data) || (is_object($data) && $data instanceof ArrayAccess)) {
+    $data[$name] = $value;
+  }
+  elseif (is_object($data)) {
+    $data->$name = $value;
+  }
+}
+
+/**
+ * Gets the property using the getter method (named just like the property).
+ */
+function entity_property_getter_method($object, array $options, $name) {
+  // Remove any underscores as classes are expected to use CamelCase.
+  $method = strtr($name, array('_' => ''));
+  return $object->$method();
+}
+
+/**
+ * Sets the property to the given value using the setter method. May be used as
+ * 'setter callback'.
+ */
+function entity_property_setter_method($object, $name, $value) {
+  // Remove any underscores as classes are expected to use CamelCase.
+  $method = 'set' . strtr($name, array('_' => ''));
+  // Invoke the setProperty() method where 'Property' is the property name.
+  $object->$method($value);
+}
+
+/**
+ * Getter callback for getting an array. Makes sure it's numerically indexed.
+ */
+function entity_property_get_list($data, array $options, $name) {
+  return isset($data->$name) ? array_values($data->$name) : array();
+}
+
+/**
+ * A validation callback ensuring the passed integer is positive.
+ */
+function entity_property_validate_integer_positive($value) {
+  return $value > 0;
+}
+
+/**
+ * A validation callback ensuring the passed integer is non-negative.
+ */
+function entity_property_validate_integer_non_negative($value) {
+  return $value >= 0;
+}
+
+/**
+ * A simple auto-creation callback for array based data structures.
+ */
+function entity_property_create_array($property_name, $context) {
+  return array();
+}
+
+/**
+ * Flattens the given options in single dimensional array.
+ * We don't depend on options module, so we cannot use options_array_flatten().
+ *
+ * @see options_array_flatten()
+ */
+function entity_property_options_flatten($options) {
+  $result = array();
+  foreach ($options as $key => $value) {
+    if (is_array($value)) {
+      $result += $value;
+    }
+    else {
+      $result[$key] = $value;
+    }
+  }
+  return $result;
+}
+
+/**
+ * Defines info for the properties of the text_formatted data structure.
+ */
+function entity_property_text_formatted_info() {
+  return array(
+    'value' => array(
+      'type' => 'text',
+      'label' => t('Text'),
+      'sanitized' => TRUE,
+      'getter callback' => 'entity_metadata_field_text_get',
+      'setter callback' => 'entity_property_verbatim_set',
+      'setter permission' => 'administer nodes',
+      'raw getter callback' => 'entity_property_verbatim_get',
+    ),
+    'summary' => array(
+      'type' => 'text',
+      'label' => t('Summary'),
+      'sanitized' => TRUE,
+      'getter callback' => 'entity_metadata_field_text_get',
+      'setter callback' => 'entity_property_verbatim_set',
+      'setter permission' => 'administer nodes',
+      'raw getter callback' => 'entity_property_verbatim_get',
+    ),
+    'format' => array(
+      'type' => 'token',
+      'label' => t('Text format'),
+      'options list' => 'entity_metadata_field_text_formats',
+      'getter callback' => 'entity_property_verbatim_get',
+    ),
+  );
+}
+
+/**
+ * Defines info for the properties of the field_item_textsummary data structure.
+ */
+function entity_property_field_item_textsummary_info() {
+  return array(
+    'value' => array(
+      'type' => 'text',
+      'label' => t('Text'),
+      'setter callback' => 'entity_property_verbatim_set',
+    ),
+    'summary' => array(
+      'type' => 'text',
+      'label' => t('Summary'),
+      'setter callback' => 'entity_property_verbatim_set',
+    ),
+  );
+}
+
+/**
+ * Defines info for the properties of the file-field item data structure.
+ */
+function entity_property_field_item_file_info() {
+  $properties['file'] = array(
+    'type' => 'file',
+    'label' => t('The file.'),
+    'getter callback' => 'entity_metadata_field_file_get',
+    'setter callback' => 'entity_metadata_field_file_set',
+    'required' => TRUE,
+  );
+  $properties['description'] = array(
+    'type' => 'text',
+    'label' => t('The file description'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  $properties['display'] = array(
+    'type' => 'boolean',
+    'label' => t('Whether the file is being displayed.'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  return $properties;
+}
+
+/**
+ * Defines info for the properties of the image-field item data structure.
+ */
+function entity_property_field_item_image_info() {
+  $properties['file'] = array(
+    'type' => 'file',
+    'label' => t('The image file.'),
+    'getter callback' => 'entity_metadata_field_file_get',
+    'setter callback' => 'entity_metadata_field_file_set',
+    'required' => TRUE,
+  );
+  $properties['alt'] = array(
+    'type' => 'text',
+    'label' => t('The "Alt" attribute text'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  $properties['title'] = array(
+    'type' => 'text',
+    'label' => t('The "Title" attribute text'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  return $properties;
+}
+
+
+/**
+ * Previously, hook_entity_property_info() has been provided by the removed
+ * entity metadata module. To provide backward compatibility for provided
+ * helpers that may be specified in hook_entity_property_info(), the following
+ * (deprecated) functions are provided.
+ */
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_verbatim_get($data, array $options, $name) {
+  return entity_property_verbatim_get($data, $options, $name);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_verbatim_set($data, $name, $value) {
+  return entity_property_verbatim_set($data, $name, $value);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_getter_method($object, array $options, $name) {
+  return entity_property_getter_method($object, $options, $name);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_setter_method($object, $name, $value) {
+  entity_property_setter_method($object, $name, $value);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_get_list($data, array $options, $name) {
+  return entity_property_get_list($data, $options, $name);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_validate_integer_positive($value) {
+  return entity_property_validate_integer_positive($value);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_validate_integer_non_negative($value) {
+  return entity_property_validate_integer_non_negative($value);
+}
+
+/**
+ * Deprecated.
+ * Do not make use of this function, instead use the new one.
+ */
+function entity_metadata_text_formatted_properties() {
+  return entity_property_text_formatted_info();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/includes/entity.ui.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,834 @@
+<?php
+
+/**
+ * @file
+ * Provides a controller for building an entity overview form.
+ */
+
+/**
+ * Default UI controller providing admin UI.
+ *
+ * This controller suites best for managing configuration entities.
+ * For a controller suiting content entities, see EntityContentUIController.
+ */
+class EntityDefaultUIController {
+
+  protected $entityType;
+  protected $entityInfo, $path;
+  protected $id_count;
+
+  /**
+   * Defines the number of entries to show per page in overview table.
+   */
+  public $overviewPagerLimit = 25;
+
+  public function __construct($entity_type, $entity_info) {
+    $this->entityType = $entity_type;
+    $this->entityInfo = $entity_info;
+    $this->path = $this->entityInfo['admin ui']['path'];
+    $this->statusKey = empty($this->entityInfo['entity keys']['status']) ? 'status' : $this->entityInfo['entity keys']['status'];
+  }
+
+  /**
+   * Provides definitions for implementing hook_menu().
+   */
+  public function hook_menu() {
+    $items = array();
+    // Set this on the object so classes that extend hook_menu() can use it.
+    $this->id_count = count(explode('/', $this->path));
+    $wildcard = isset($this->entityInfo['admin ui']['menu wildcard']) ? $this->entityInfo['admin ui']['menu wildcard'] : '%entity_object';
+    $plural_label = isset($this->entityInfo['plural label']) ? $this->entityInfo['plural label'] : $this->entityInfo['label'] . 's';
+
+    $items[$this->path] = array(
+      'title' => $plural_label,
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array($this->entityType . '_overview_form', $this->entityType),
+      'description' => 'Manage ' . $plural_label . '.',
+      'access callback' => 'entity_access',
+      'access arguments' => array('view', $this->entityType),
+      'file' => 'includes/entity.ui.inc',
+    );
+    $items[$this->path . '/list'] = array(
+      'title' => 'List',
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+      'weight' => -10,
+    );
+    $items[$this->path . '/add'] = array(
+      'title callback' => 'entity_ui_get_action_title',
+      'title arguments' => array('add', $this->entityType),
+      'page callback' => 'entity_ui_get_form',
+      'page arguments' => array($this->entityType, NULL, 'add'),
+      'access callback' => 'entity_access',
+      'access arguments' => array('create', $this->entityType),
+      'type' => MENU_LOCAL_ACTION,
+    );
+    $items[$this->path . '/manage/' . $wildcard] = array(
+      'title' => 'Edit',
+      'title callback' => 'entity_label',
+      'title arguments' => array($this->entityType, $this->id_count + 1),
+      'page callback' => 'entity_ui_get_form',
+      'page arguments' => array($this->entityType, $this->id_count + 1),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('update', $this->entityType, $this->id_count + 1),
+    );
+    $items[$this->path . '/manage/' . $wildcard . '/edit'] = array(
+      'title' => 'Edit',
+      'load arguments' => array($this->entityType),
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+    );
+
+    // Clone form, a special case for the edit form.
+    $items[$this->path . '/manage/' . $wildcard . '/clone'] = array(
+      'title' => 'Clone',
+      'page callback' => 'entity_ui_get_form',
+      'page arguments' => array($this->entityType, $this->id_count + 1, 'clone'),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('create', $this->entityType),
+    );
+    // Menu item for operations like revert and delete.
+    $items[$this->path . '/manage/' . $wildcard . '/%'] = array(
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array($this->entityType . '_operation_form', $this->entityType, $this->id_count + 1, $this->id_count + 2),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('delete', $this->entityType, $this->id_count + 1),
+      'file' => 'includes/entity.ui.inc',
+    );
+
+    if (!empty($this->entityInfo['exportable'])) {
+      // Menu item for importing an entity.
+      $items[$this->path . '/import'] = array(
+        'title callback' => 'entity_ui_get_action_title',
+        'title arguments' => array('import', $this->entityType),
+        'page callback' => 'drupal_get_form',
+        'page arguments' => array($this->entityType . '_operation_form', $this->entityType, NULL, 'import'),
+        'access callback' => 'entity_access',
+        'access arguments' => array('create', $this->entityType),
+        'file' => 'includes/entity.ui.inc',
+        'type' => MENU_LOCAL_ACTION,
+      );
+    }
+
+    if (!empty($this->entityInfo['admin ui']['file'])) {
+      // Add in the include file for the entity form.
+      foreach (array("/manage/$wildcard", "/manage/$wildcard/clone", '/add') as $path_end) {
+        $items[$this->path . $path_end]['file'] = $this->entityInfo['admin ui']['file'];
+        $items[$this->path . $path_end]['file path'] = isset($this->entityInfo['admin ui']['file path']) ? $this->entityInfo['admin ui']['file path'] : drupal_get_path('module', $this->entityInfo['module']);
+      }
+    }
+    return $items;
+  }
+
+  /**
+   * Provides definitions for implementing hook_forms().
+   *
+   * Use per bundle form ids if possible, such that easy per bundle alterations
+   * are supported too.
+   *
+   * Note that for performance reasons, this method is only invoked for forms,
+   * which receive the entity_type as first argument. Thus any forms added, must
+   * follow that pattern.
+   *
+   * @see entity_forms()
+   */
+  public function hook_forms() {
+    // The overview and the operation form are implemented by the controller,
+    // the callback and validation + submit handlers just invoke the controller.
+    $forms[$this->entityType . '_overview_form'] = array(
+      'callback' => 'entity_ui_overview_form',
+      'wrapper_callback' => 'entity_ui_form_defaults',
+    );
+    $forms[$this->entityType . '_operation_form'] = array(
+      'callback' => 'entity_ui_operation_form',
+      'wrapper_callback' => 'entity_ui_form_defaults',
+    );
+
+    // The entity form (ENTITY_TYPE_form) handles editing, adding and cloning.
+    // For that form, the wrapper callback entity_ui_main_form_defaults() gets
+    // directly invoked via entity_ui_get_form().
+    // If there are bundles though, we use form ids that include the bundle name
+    // (ENTITY_TYPE_edit_BUNDLE_NAME_form) to enable per bundle alterations
+    // as well as alterations based upon the base form id (ENTITY_TYPE_form).
+    if (!(count($this->entityInfo['bundles']) == 1 && isset($this->entityInfo['bundles'][$this->entityType]))) {
+      foreach ($this->entityInfo['bundles'] as $bundle => $bundle_info) {
+        $forms[$this->entityType . '_edit_' . $bundle . '_form']['callback'] = $this->entityType . '_form';
+        // Again the wrapper callback is invoked by entity_ui_get_form() anyway.
+      }
+    }
+    return $forms;
+  }
+
+  /**
+   * Builds the entity overview form.
+   */
+  public function overviewForm($form, &$form_state) {
+    // By default just show a simple overview for all entities.
+    $form['table'] = $this->overviewTable();
+    $form['pager'] = array('#theme' => 'pager');
+    return $form;
+  }
+
+  /**
+   * Overview form validation callback.
+   *
+   * @param $form
+   *   The form array of the overview form.
+   * @param $form_state
+   *   The overview form state which will be used for validating.
+   */
+  public function overviewFormValidate($form, &$form_state) {}
+
+  /**
+   * Overview form submit callback.
+   *
+   * @param $form
+   *   The form array of the overview form.
+   * @param $form_state
+   *   The overview form state which will be used for submitting.
+   */
+  public function overviewFormSubmit($form, &$form_state) {}
+
+
+  /**
+   * Generates the render array for a overview table for arbitrary entities
+   * matching the given conditions.
+   *
+   * @param $conditions
+   *   An array of conditions as needed by entity_load().
+
+   * @return Array
+   *   A renderable array.
+   */
+  public function overviewTable($conditions = array()) {
+
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $this->entityType);
+
+    // Add all conditions to query.
+    foreach ($conditions as $key => $value) {
+      $query->propertyCondition($key, $value);
+    }
+
+    if ($this->overviewPagerLimit) {
+      $query->pager($this->overviewPagerLimit);
+    }
+
+    $results = $query->execute();
+
+    $ids = isset($results[$this->entityType]) ? array_keys($results[$this->entityType]) : array();
+    $entities = $ids ? entity_load($this->entityType, $ids) : array();
+    ksort($entities);
+
+    $rows = array();
+    foreach ($entities as $entity) {
+      $rows[] = $this->overviewTableRow($conditions, entity_id($this->entityType, $entity), $entity);
+    }
+
+    $render = array(
+      '#theme' => 'table',
+      '#header' => $this->overviewTableHeaders($conditions, $rows),
+      '#rows' => $rows,
+      '#empty' => t('None.'),
+    );
+    return $render;
+  }
+
+  /**
+   * Generates the table headers for the overview table.
+   */
+  protected function overviewTableHeaders($conditions, $rows, $additional_header = array()) {
+    $header = $additional_header;
+    array_unshift($header, t('Label'));
+    if (!empty($this->entityInfo['exportable'])) {
+      $header[] = t('Status');
+    }
+    // Add operations with the right colspan.
+    $header[] = array('data' => t('Operations'), 'colspan' => $this->operationCount());
+    return $header;
+  }
+
+  /**
+   * Returns the operation count for calculating colspans.
+   */
+  protected function operationCount() {
+    $count = 3;
+    $count += !empty($this->entityInfo['bundle of']) && entity_type_is_fieldable($this->entityInfo['bundle of']) && module_exists('field_ui') ? 2 : 0;
+    $count += !empty($this->entityInfo['exportable']) ? 1 : 0;
+    $count += !empty($this->entityInfo['i18n controller class']) ? 1 : 0;
+    return $count;
+  }
+
+  /**
+   * Generates the row for the passed entity and may be overridden in order to
+   * customize the rows.
+   *
+   * @param $additional_cols
+   *   Additional columns to be added after the entity label column.
+   */
+  protected function overviewTableRow($conditions, $id, $entity, $additional_cols = array()) {
+    $entity_uri = entity_uri($this->entityType, $entity);
+
+    $row[] = array('data' => array(
+      '#theme' => 'entity_ui_overview_item',
+      '#label' => entity_label($this->entityType, $entity),
+      '#name' => !empty($this->entityInfo['exportable']) ? entity_id($this->entityType, $entity) : FALSE,
+      '#url' => $entity_uri ? $entity_uri : FALSE,
+      '#entity_type' => $this->entityType),
+    );
+
+    // Add in any passed additional cols.
+    foreach ($additional_cols as $col) {
+      $row[] = $col;
+    }
+
+    // Add a row for the exportable status.
+    if (!empty($this->entityInfo['exportable'])) {
+      $row[] = array('data' => array(
+        '#theme' => 'entity_status',
+        '#status' => $entity->{$this->statusKey},
+      ));
+    }
+    // In case this is a bundle, we add links to the field ui tabs.
+    $field_ui = !empty($this->entityInfo['bundle of']) && entity_type_is_fieldable($this->entityInfo['bundle of']) && module_exists('field_ui');
+    // For exportable entities we add an export link.
+    $exportable = !empty($this->entityInfo['exportable']);
+    // If i18n integration is enabled, add a link to the translate tab.
+    $i18n = !empty($this->entityInfo['i18n controller class']);
+
+    // Add operations depending on the status.
+    if (entity_has_status($this->entityType, $entity, ENTITY_FIXED)) {
+      $row[] = array('data' => l(t('clone'), $this->path . '/manage/' . $id . '/clone'), 'colspan' => $this->operationCount());
+    }
+    else {
+      $row[] = l(t('edit'), $this->path . '/manage/' . $id);
+
+      if ($field_ui) {
+        $row[] = l(t('manage fields'), $this->path . '/manage/' . $id . '/fields');
+        $row[] = l(t('manage display'), $this->path . '/manage/' . $id . '/display');
+      }
+      if ($i18n) {
+        $row[] = l(t('translate'), $this->path . '/manage/' . $id . '/translate');
+      }
+      if ($exportable) {
+        $row[] = l(t('clone'), $this->path . '/manage/' . $id . '/clone');
+      }
+
+      if (empty($this->entityInfo['exportable']) || !entity_has_status($this->entityType, $entity, ENTITY_IN_CODE)) {
+        $row[] = l(t('delete'), $this->path . '/manage/' . $id . '/delete', array('query' => drupal_get_destination()));
+      }
+      elseif (entity_has_status($this->entityType, $entity, ENTITY_OVERRIDDEN)) {
+        $row[] = l(t('revert'), $this->path . '/manage/' . $id . '/revert', array('query' => drupal_get_destination()));
+      }
+      else {
+        $row[] = '';
+      }
+    }
+    if ($exportable) {
+      $row[] = l(t('export'), $this->path . '/manage/' . $id . '/export');
+    }
+    return $row;
+  }
+
+
+  /**
+   * Builds the operation form.
+   *
+   * For the export operation a serialized string of the entity is directly
+   * shown in the form (no submit function needed).
+   */
+  public function operationForm($form, &$form_state, $entity, $op) {
+    switch ($op) {
+      case 'revert':
+        $label = entity_label($this->entityType, $entity);
+        $confirm_question = t('Are you sure you want to revert the %entity %label?', array('%entity' => $this->entityInfo['label'], '%label' => $label));
+        return confirm_form($form, $confirm_question, $this->path);
+
+      case 'delete':
+        $label = entity_label($this->entityType, $entity);
+        $confirm_question = t('Are you sure you want to delete the %entity %label?', array('%entity' => $this->entityInfo['label'], '%label' => $label));
+        return confirm_form($form, $confirm_question, $this->path);
+
+      case 'export':
+        if (!empty($this->entityInfo['exportable'])) {
+          $export = entity_export($this->entityType, $entity);
+          $form['export'] = array(
+            '#type' => 'textarea',
+            '#title' => t('Export'),
+            '#description' => t('For importing copy the content of the text area and paste it into the import page.'),
+            '#rows' => 25,
+            '#default_value' => $export,
+          );
+          return $form;
+        }
+
+      case 'import':
+        $form['import'] = array(
+          '#type' => 'textarea',
+          '#title' => t('Import'),
+          '#description' => t('Paste an exported %entity_type here.', array('%entity_type' => $this->entityInfo['label'])),
+          '#rows' => 20,
+        );
+        $form['overwrite'] = array(
+          '#title' => t('Overwrite'),
+          '#type' => 'checkbox',
+          '#description' => t('If checked, any existing %entity with the same identifier will be replaced by the import.', array('%entity' => $this->entityInfo['label'])),
+          '#default_value' => FALSE,
+        );
+        $form['submit'] = array(
+          '#type' => 'submit',
+          '#value' => t('Import'),
+        );
+        return $form;
+    }
+    drupal_not_found();
+    exit;
+  }
+
+  /**
+   * Operation form validation callback.
+   */
+  public function operationFormValidate($form, &$form_state) {
+    if ($form_state['op'] == 'import') {
+      if ($entity = entity_import($this->entityType, $form_state['values']['import'])) {
+        // Store the successfully imported entity in $form_state.
+        $form_state[$this->entityType] = $entity;
+        if (!$form_state['values']['overwrite']) {
+          // Check for existing entities with the same identifier.
+          $id = entity_id($this->entityType, $entity);
+          $entities = entity_load($this->entityType, array($id));
+          if (!empty($entities)) {
+            $label = entity_label($this->entityType, $entity);
+            $vars = array('%entity' => $this->entityInfo['label'], '%label' => $label);
+            form_set_error('import', t('Import of %entity %label failed, a %entity with the same machine name already exists. Check the overwrite option to replace it.', $vars));
+          }
+        }
+      }
+      else {
+        form_set_error('import', t('Import failed.'));
+      }
+    }
+  }
+
+  /**
+   * Operation form submit callback.
+   */
+  public function operationFormSubmit($form, &$form_state) {
+    $msg = $this->applyOperation($form_state['op'], $form_state[$this->entityType]);
+    drupal_set_message($msg);
+    $form_state['redirect'] = $this->path;
+  }
+
+  /**
+   * Applies an operation to the given entity.
+   *
+   * Note: the export operation is directly carried out by the operationForm()
+   * method.
+   *
+   * @param string $op
+   *   The operation (revert, delete or import).
+   * @param $entity
+   *   The entity to manipulate.
+   *
+   * @return
+   *   The status message of what has been applied.
+   */
+  public function applyOperation($op, $entity) {
+    $label = entity_label($this->entityType, $entity);
+    $vars = array('%entity' => $this->entityInfo['label'], '%label' => $label);
+    $id = entity_id($this->entityType, $entity);
+    $edit_link = l(t('edit'), $this->path . '/manage/' . $id . '/edit');
+
+    switch ($op) {
+      case 'revert':
+        entity_delete($this->entityType, $id);
+        watchdog($this->entityType, 'Reverted %entity %label to the defaults.', $vars, WATCHDOG_NOTICE, $edit_link);
+        return t('Reverted %entity %label to the defaults.', $vars);
+
+      case 'delete':
+        entity_delete($this->entityType, $id);
+        watchdog($this->entityType, 'Deleted %entity %label.', $vars);
+        return t('Deleted %entity %label.', $vars);
+
+      case 'import':
+        // First check if there is any existing entity with the same ID.
+        $id = entity_id($this->entityType, $entity);
+        $entities = entity_load($this->entityType, array($id));
+        if ($existing_entity = reset($entities)) {
+          // Copy DB id and remove the new indicator to overwrite the DB record.
+          $idkey = $this->entityInfo['entity keys']['id'];
+          $entity->{$idkey} = $existing_entity->{$idkey};
+          unset($entity->is_new);
+        }
+        entity_save($this->entityType, $entity);
+        watchdog($this->entityType, 'Imported %entity %label.', $vars);
+        return t('Imported %entity %label.', $vars);
+
+      default:
+        return FALSE;
+    }
+  }
+
+  /**
+   * Entity submit builder invoked via entity_ui_form_submit_build_entity().
+   *
+   * Extracts the form values and updates the entity.
+   *
+   * The provided implementation makes use of the helper function
+   * entity_form_submit_build_entity() provided by core, which already invokes
+   * the field API attacher for fieldable entities.
+   *
+   * @return
+   *   The updated entity.
+   *
+   * @see entity_ui_form_submit_build_entity()
+   */
+  public function entityFormSubmitBuildEntity($form, &$form_state) {
+    // Add the bundle property to the entity if the entity type supports bundles
+    // and the form provides a value for the bundle key. Especially new entities
+    // need to have their bundle property pre-populated before we invoke
+    // entity_form_submit_build_entity().
+    if (!empty($this->entityInfo['entity keys']['bundle']) && isset($form_state['values'][$this->entityInfo['entity keys']['bundle']])) {
+      $form_state[$this->entityType]->{$this->entityInfo['entity keys']['bundle']} = $form_state['values'][$this->entityInfo['entity keys']['bundle']];
+    }
+    entity_form_submit_build_entity($this->entityType, $form_state[$this->entityType], $form, $form_state);
+    return $form_state[$this->entityType];
+  }
+}
+
+/**
+ * UI controller providing UI for content entities.
+ *
+ * For a controller providing UI for bundleable content entities, see
+ * EntityBundleableUIController.
+ * For a controller providing admin UI for configuration entities, see
+ * EntityDefaultUIController.
+ */
+class EntityContentUIController extends EntityDefaultUIController {
+
+  /**
+   * Provides definitions for implementing hook_menu().
+   */
+  public function hook_menu() {
+    $items = parent::hook_menu();
+    $wildcard = isset($this->entityInfo['admin ui']['menu wildcard']) ? $this->entityInfo['admin ui']['menu wildcard'] : '%entity_object';
+
+    // Unset the manage entity path, as the provided UI is for admin entities.
+    unset($items[$this->path]);
+
+    $defaults = array(
+      'file' => $this->entityInfo['admin ui']['file'],
+      'file path' =>  isset($this->entityInfo['admin ui']['file path']) ? $this->entityInfo['admin ui']['file path'] : drupal_get_path('module', $this->entityInfo['module']),
+    );
+
+    // Add view, edit and delete menu items for content entities.
+    $items[$this->path . '/' . $wildcard] = array(
+      'title callback' => 'entity_ui_get_page_title',
+      'title arguments' => array('view', $this->entityType, $this->id_count),
+      'page callback' => 'entity_ui_entity_page_view',
+      'page arguments' => array($this->id_count),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('view', $this->entityType, $this->id_count),
+    ) + $defaults;
+    $items[$this->path . '/' . $wildcard . '/view'] = array(
+      'title' => 'View',
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+      'load arguments' => array($this->entityType),
+      'weight' => -10,
+    ) + $defaults;
+    $items[$this->path . '/' . $wildcard . '/edit'] = array(
+      'page callback' => 'entity_ui_get_form',
+      'page arguments' => array($this->entityType, $this->id_count),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('edit', $this->entityType, $this->id_count),
+      'title' => 'Edit',
+      'type' => MENU_LOCAL_TASK,
+      'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+    ) + $defaults;
+    $items[$this->path . '/' . $wildcard . '/delete'] = array(
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array($this->entityType . '_operation_form', $this->entityType, $this->id_count, 'delete'),
+      'load arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('delete', $this->entityType, $this->id_count),
+      'title' => 'Delete',
+      'type' => MENU_LOCAL_TASK,
+      'context' => MENU_CONTEXT_INLINE,
+      'file' => $this->entityInfo['admin ui']['file'],
+      'file path' => isset($this->entityInfo['admin ui']['file path']) ? $this->entityInfo['admin ui']['file path'] : drupal_get_path('module', $this->entityInfo['module']),
+    ) + $defaults;
+
+    return $items;
+  }
+
+  /**
+   * Operation form submit callback.
+   */
+  public function operationFormSubmit($form, &$form_state) {
+    parent::operationFormSubmit($form, $form_state);
+    // The manage entity path is unset for the content entity UI.
+    $form_state['redirect'] = '<front>';
+  }
+}
+
+/**
+ * UI controller providing UI for bundleable content entities.
+ *
+ * Adds a bundle selection page to the entity/add path, analogously to the
+ * node/add path.
+ */
+class EntityBundleableUIController extends EntityContentUIController {
+
+  /**
+   * Provides definitions for implementing hook_menu().
+   */
+  public function hook_menu() {
+    $items = parent::hook_menu();
+
+    // Extend the 'add' path.
+    $items[$this->path . '/add'] = array(
+      'title callback' => 'entity_ui_get_action_title',
+      'title arguments' => array('add', $this->entityType),
+      'page callback' => 'entity_ui_bundle_add_page',
+      'page arguments' => array($this->entityType),
+      'access callback' => 'entity_access',
+      'access arguments' => array('create', $this->entityType),
+      'type' => MENU_LOCAL_ACTION,
+    );
+    $items[$this->path . '/add/%'] = array(
+      'title callback' => 'entity_ui_get_action_title',
+      'title arguments' => array('add', $this->entityType, $this->id_count + 1),
+      'page callback' => 'entity_ui_get_bundle_add_form',
+      'page arguments' => array($this->entityType, $this->id_count + 1),
+      'access callback' => 'entity_access',
+      'access arguments' => array('create', $this->entityType),
+    );
+
+    if (!empty($this->entityInfo['admin ui']['file'])) {
+      // Add in the include file for the entity form.
+      foreach (array('/add', '/add/%') as $path_end) {
+        $items[$this->path . $path_end]['file'] = $this->entityInfo['admin ui']['file'];
+        $items[$this->path . $path_end]['file path'] = isset($this->entityInfo['admin ui']['file path']) ? $this->entityInfo['admin ui']['file path'] : drupal_get_path('module', $this->entityInfo['module']);
+      }
+    }
+
+    return $items;
+  }
+}
+
+/**
+ * Form builder function for the overview form.
+ *
+ * @see EntityDefaultUIController::overviewForm()
+ */
+function entity_ui_overview_form($form, &$form_state, $entity_type) {
+  return entity_ui_controller($entity_type)->overviewForm($form, $form_state);
+}
+
+/**
+ * Form builder for the entity operation form.
+ *
+ * @see EntityDefaultUIController::operationForm()
+ */
+function entity_ui_operation_form($form, &$form_state, $entity_type, $entity, $op) {
+  $form_state['op'] = $op;
+  return entity_ui_controller($entity_type)->operationForm($form, $form_state, $entity, $op);
+}
+
+/**
+ * Form wrapper the main entity form.
+ *
+ * @see entity_ui_form_defaults()
+ */
+function entity_ui_main_form_defaults($form, &$form_state, $entity = NULL, $op = NULL) {
+  // Now equals entity_ui_form_defaults() but is still here to keep backward
+  // compatability.
+  return entity_ui_form_defaults($form, $form_state, $form_state['entity_type'], $entity, $op);
+}
+
+/**
+ * Clones the entity object and makes sure it will get saved as new entity.
+ *
+ * @return
+ *   The cloned entity object.
+ */
+function entity_ui_clone_entity($entity_type, $entity) {
+  // Clone the entity and make sure it will get saved as a new entity.
+  $entity = clone $entity;
+
+  $entity_info = entity_get_info($entity_type);
+  $entity->{$entity_info['entity keys']['id']} = FALSE;
+  if (!empty($entity_info['entity keys']['name'])) {
+    $entity->{$entity_info['entity keys']['name']} = FALSE;
+  }
+  $entity->is_new = TRUE;
+
+  // Make sure the status of a cloned exportable is custom.
+  if (!empty($entity_info['exportable'])) {
+    $status_key = isset($entity_info['entity keys']['status']) ? $entity_info['entity keys']['status'] : 'status';
+    $entity->$status_key = ENTITY_CUSTOM;
+  }
+  return $entity;
+}
+
+/**
+ * Form wrapper callback for all entity ui forms.
+ *
+ * This callback makes sure the form state is properly initialized and sets
+ * some useful default titles.
+ *
+ * @see EntityDefaultUIController::hook_forms()
+ */
+function entity_ui_form_defaults($form, &$form_state, $entity_type, $entity = NULL, $op = NULL) {
+  $defaults = array(
+    'entity_type' => $entity_type,
+  );
+  if (isset($entity)) {
+    $defaults[$entity_type] = $entity;
+  }
+  if (isset($op)) {
+    $defaults['op'] = $op;
+  }
+  $form_state += $defaults;
+  if (isset($op)) {
+    drupal_set_title(entity_ui_get_page_title($op, $entity_type, $entity), PASS_THROUGH);
+  }
+  // Add in handlers pointing to the controller for the forms implemented by it.
+  if (isset($form_state['build_info']['base_form_id']) && $form_state['build_info']['base_form_id'] != $entity_type . '_form') {
+    $form['#validate'][] = 'entity_ui_controller_form_validate';
+    $form['#submit'][] = 'entity_ui_controller_form_submit';
+  }
+  return $form;
+}
+
+/**
+ * Validation callback for forms implemented by the UI controller.
+ */
+function entity_ui_controller_form_validate($form, &$form_state) {
+  // Remove 'entity_ui_' prefix and the '_form' suffix.
+  $base = substr($form_state['build_info']['base_form_id'], 10, -5);
+  $method = $base . 'FormValidate';
+  entity_ui_controller($form_state['entity_type'])->$method($form, $form_state);
+}
+
+/**
+ * Submit callback for forms implemented by the UI controller.
+ */
+function entity_ui_controller_form_submit($form, &$form_state) {
+  // Remove 'entity_ui_' prefix and the '_form' suffix.
+  $base = substr($form_state['build_info']['base_form_id'], 10, -5);
+  $method = $base . 'FormSubmit';
+  entity_ui_controller($form_state['entity_type'])->$method($form, $form_state);
+}
+
+/**
+ * Gets the page title for the passed operation.
+ */
+function entity_ui_get_page_title($op, $entity_type, $entity = NULL) {
+  $label = entity_label($entity_type, $entity);
+  switch ($op) {
+    case 'view':
+      return $label;
+    case 'edit':
+      return t('Edit @label', array('@label' => $label));
+    case 'clone':
+      return t('Clone @label', array('@label' => $label));
+    case 'revert':
+      return t('Revert @label', array('@label' => $label));
+    case 'delete':
+      return t('Delete @label', array('@label' => $label));
+    case 'export':
+      return t('Export @label', array('@label' => $label));
+  }
+  if (isset($entity)) {
+    list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  }
+  return entity_ui_get_action_title($op, $entity_type, $bundle);
+}
+
+/**
+ * Gets the page/menu title for local action operations.
+ *
+ * @param $op
+ *  The current operation. One of 'add' or 'import'.
+ * @param $entity_type
+ *  The entity type.
+ * @param $bundle_name
+ *  (Optional) The name of the bundle. May be NULL if the bundle name is not
+ *  relevant to the current page. If the entity type has only one bundle, or no
+ *  bundles, this will be the same as the entity type.
+ */
+function entity_ui_get_action_title($op, $entity_type, $bundle_name = NULL) {
+  $info = entity_get_info($entity_type);
+  switch ($op) {
+    case 'add':
+      if (isset($bundle_name) && $bundle_name != $entity_type) {
+        return t('Add @bundle_name @entity_type', array(
+          '@bundle_name' => drupal_strtolower($info['bundles'][$bundle_name]['label']),
+          '@entity_type' => drupal_strtolower($info['label']),
+        ));
+      }
+      else {
+        return t('Add @entity_type', array('@entity_type' => drupal_strtolower($info['label'])));
+      }
+    case 'import':
+      return t('Import @entity_type', array('@entity_type' => drupal_strtolower($info['label'])));
+  }
+}
+
+/**
+ * Submit builder for the main entity form, which extracts the form values and updates the entity.
+ *
+ * This is a helper function for entities making use of the entity UI
+ * controller.
+ *
+ * @return
+ *   The updated entity.
+ *
+ * @see EntityDefaultUIController::hook_forms()
+ * @see EntityDefaultUIController::entityFormSubmitBuildEntity()
+ */
+function entity_ui_form_submit_build_entity($form, &$form_state) {
+  return entity_ui_controller($form_state['entity_type'])->entityFormSubmitBuildEntity($form, $form_state);
+}
+
+/**
+ * Validation callback for machine names of exportables.
+ *
+ * We don't allow numeric machine names, as entity_load() treats them as the
+ * numeric identifier and they are easily confused with ids in general.
+ */
+function entity_ui_validate_machine_name($element, &$form_state) {
+  if (is_numeric($element['#value'])) {
+    form_error($element, t('Machine-readable names must not consist of numbers only.'));
+  }
+}
+
+/**
+ * Returns HTML for an entity on the entity overview listing.
+ *
+ * @ingroup themeable
+ */
+function theme_entity_ui_overview_item($variables) {
+  $output = $variables['url'] ? l($variables['label'], $variables['url']['path'], $variables['url']['options']) : check_plain($variables['label']);
+  if ($variables['name']) {
+    $output .= ' <small> (' . t('Machine name') . ': ' . check_plain($variables['name']) . ')</small>';
+  }
+  return $output;
+}
+
+/**
+ * Page callback for viewing an entity.
+ *
+ * @param Entity $entity
+ *   The entity to be rendered.
+ *
+ * @return array
+ *   A renderable array of the entity in full view mode.
+ */
+function entity_ui_entity_page_view($entity) {
+  return $entity->view('full', NULL, TRUE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/includes/entity.wrapper.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1194 @@
+<?php
+
+/**
+ * @file
+ * Provides wrappers allowing easy usage of the entity metadata.
+ */
+
+/**
+ * A common base class for all wrappers.
+ */
+abstract class EntityMetadataWrapper {
+
+  protected $type;
+  protected $data;
+  protected $info;
+  protected $cache = array();
+
+  /**
+   * Construct a new wrapper object.
+   *
+   * @param $type
+   *   The type of the passed data.
+   * @param $data
+   *   Optional. The data to wrap.
+   * @param $info
+   *   Optional. Used internally to pass info about properties down the tree.
+   */
+  public function __construct($type, $data = NULL, $info = array()) {
+    $this->type = $type;
+    $this->info = $info + array(
+      'langcode' => NULL,
+    );
+    $this->info['type'] = $type;
+    if (isset($data)) {
+      $this->set($data);
+    }
+  }
+
+  /**
+   * Gets info about the wrapped data.
+   *
+   * @return Array
+   *   Keys set are all keys as specified for a property in hook_entity_info()
+   *   as well as possible the following keys:
+   *    - name: If this wraps a property, the name of the property.
+   *    - parent: The parent wrapper, if any.
+   *    - langcode: The language code, if this data is language specific.
+   */
+  public function info() {
+    return $this->info;
+  }
+
+  /**
+   * Gets the (entity)type of the wrapped data.
+   */
+  public function type() {
+    return $this->type;
+  }
+
+  /**
+   * Returns the wrapped data. If no options are given the data is returned as
+   * described in the info.
+   *
+   * @param $options
+   *   (optional) A keyed array of options:
+   *   - sanitize: A boolean flag indicating that textual properties should be
+   *     sanitized for display to a web browser. Defaults to FALSE.
+   *   - decode: If set to TRUE and some textual data is already sanitized, it
+   *     strips HTML tags and decodes HTML entities. Defaults to FALSE.
+   *
+   *  @return
+   *    The value of the wrapped data. If the data property is not set, NULL
+   *    is returned.
+   *
+   *  @throws EntityMetadataWrapperException
+   *    In case there are no data values available to the wrapper, an exception
+   *    is thrown. E.g. if the value for an entity property is to be retrieved
+   *    and there is no entity available, the exception is thrown. However, if
+   *    an entity is available but the property is not set, NULL is returned.
+   */
+  public function value(array $options = array()) {
+    if (!$this->dataAvailable() && isset($this->info['parent'])) {
+      throw new EntityMetadataWrapperException('Missing data values.');
+    }
+    if (!isset($this->data) && isset($this->info['name'])) {
+      $this->data = $this->info['parent']->getPropertyValue($this->info['name'], $this->info);
+    }
+    return $this->data;
+  }
+
+  /**
+   * Returns the raw, unprocessed data. Most times this is the same as returned
+   * by value(), however for already processed and sanitized textual data, this
+   * will return the unprocessed data in contrast to value().
+   */
+  public function raw() {
+    if (!$this->dataAvailable()) {
+      throw new EntityMetadataWrapperException('Missing data values.');
+    }
+    if (isset($this->info['name']) && isset($this->info['parent'])) {
+      return $this->info['parent']->getPropertyRaw($this->info['name'], $this->info);
+    }
+    // Else return the usual value, which should be raw in this case.
+    return $this->value();
+  }
+
+  /**
+   * Returns whether data is available to work with.
+   *
+   * @return
+   *   If we operate without any data FALSE, else TRUE.
+   */
+  protected function dataAvailable() {
+    return isset($this->data) || (isset($this->info['parent']) && $this->info['parent']->dataAvailable());
+  }
+
+  /**
+   * Set a new data value.
+   */
+  public function set($value) {
+    if (!$this->validate($value)) {
+      throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.');
+    }
+    $this->clear();
+    $this->data = $value;
+    $this->updateParent($value);
+    return $this;
+  }
+
+  /**
+   * Updates the parent data structure of a data property with the latest data value.
+   */
+  protected function updateParent($value) {
+    if (isset($this->info['parent'])) {
+      $this->info['parent']->setProperty($this->info['name'], $value);
+    }
+  }
+
+  /**
+   * Returns whether $value is a valid value to set.
+   */
+  public function validate($value) {
+    if (isset($value) && !entity_property_verify_data_type($value, $this->type)) {
+      return FALSE;
+    }
+    // Only proceed with further checks if this is not a list item. If this is
+    // a list item, the checks are performed on the list property level.
+    if (isset($this->info['parent']) && $this->info['parent'] instanceof EntityListWrapper) {
+      return TRUE;
+    }
+    if (!isset($value) && !empty($this->info['required'])) {
+      // Do not allow NULL values if the property is required.
+      return FALSE;
+    }
+    return !isset($this->info['validation callback']) || call_user_func($this->info['validation callback'], $value, $this->info);
+  }
+
+  public function __toString() {
+    return isset($this->info) ? 'Property ' . $this->info['name'] : $this->type;
+  }
+
+  /**
+   * Clears the data value and the wrapper cache.
+   */
+  protected function clear() {
+    $this->data = NULL;
+    foreach ($this->cache as $wrapper) {
+      $wrapper->clear();
+    }
+  }
+
+  /**
+   * Returns the options list specifying possible values for the property, if
+   * defined.
+   *
+   * @param $op
+   *   (optional) One of 'edit' or 'view'. In case the list of possible values
+   *   a user could set for a property differs from the list of values a
+   *   property could have, $op determines which options should be returned.
+   *   Defaults to 'edit'.
+   *   E.g. all possible roles a user could have include the anonymous and the
+   *   authenticated user roles, while those roles cannot be added to a user
+   *   account. So their options would be included for 'view', but for 'edit'
+   *   not.
+   *
+   * @return
+   *   An array as used by hook_options_list() or FALSE.
+   */
+  public function optionsList($op = 'edit') {
+    if (isset($this->info['options list']) && is_callable($this->info['options list'])) {
+      $name = isset($this->info['name']) ? $this->info['name'] : NULL;
+      return call_user_func($this->info['options list'], $name, $this->info, $op);
+    }
+    return FALSE;
+  }
+
+  /**
+   * Returns the label for the currently set property value if there is one
+   * available, i.e. if an options list has been specified.
+   */
+  public function label() {
+    if ($options = $this->optionsList('view')) {
+      $options = entity_property_options_flatten($options);
+      $value = $this->value();
+      if (is_scalar($value) && isset($options[$value])) {
+        return $options[$value];
+      }
+    }
+  }
+
+  /**
+   * Determines whether the given user has access to view or edit this property.
+   * Apart from relying on access metadata of properties, this takes into
+   * account information about entity level access, if available:
+   *  - Referenced entities can only be viewed, when the user also has
+   *    permission to view the entity.
+   *  - A property may be only edited, if the user has permission to update the
+   *    entity containing the property.
+   *
+   * @param $op
+   *   The operation being performed. One of 'view' or 'edit.
+   * @param $account
+   *   The user to check for. Leave it to NULL to check for the global user.
+   * @return boolean
+   *   Whether access to entity property is allowed for the given operation.
+   *   However if we wrap no data, it returns whether access is allowed to the
+   *   property of all entities of this type.
+   *   If there is no access information for this property, TRUE is returned.
+   */
+  public function access($op, $account = NULL) {
+    if (empty($this->info['parent']) && $this instanceof EntityDrupalWrapper) {
+      // If there is no parent just incorporate entity based access.
+      return $this->entityAccess($op == 'edit' ? 'update' : 'view', $account);
+    }
+    return !empty($this->info['parent']) ? $this->info['parent']->propertyAccess($this->info['name'], $op, $account) : TRUE;
+  }
+
+  /**
+   * Prepare for serializiation.
+   */
+  public function __sleep() {
+    $vars = get_object_vars($this);
+    unset($vars['cache']);
+    return drupal_map_assoc(array_keys($vars));
+  }
+}
+
+/**
+ * Wraps a single value.
+ */
+class EntityValueWrapper extends EntityMetadataWrapper {
+
+  /**
+   * Overrides EntityMetadataWrapper#value().
+   * Sanitizes or decode textual data if necessary.
+   */
+  public function value(array $options = array()) {
+    $data = parent::value();
+    if ($this->type == 'text' && isset($data)) {
+      $info = $this->info + array('sanitized' => FALSE, 'sanitize' => 'check_plain');
+      $options += array('sanitize' => FALSE, 'decode' => FALSE);
+      if ($options['sanitize'] && !$info['sanitized']) {
+        return call_user_func($info['sanitize'], $data);
+      }
+      elseif ($options['decode'] && $info['sanitized']) {
+        return decode_entities(strip_tags($data));
+      }
+    }
+    return $data;
+  }
+}
+
+/**
+ * Provides a general wrapper for any data structure. For this to work the
+ * metadata has to be passed during construction.
+ */
+class EntityStructureWrapper extends EntityMetadataWrapper implements IteratorAggregate {
+
+  protected $propertyInfo = array(), $propertyInfoAltered = FALSE;
+  protected $langcode = LANGUAGE_NONE;
+
+  protected $propertyInfoDefaults = array(
+    'type' => 'text',
+    'getter callback' => 'entity_property_verbatim_get',
+    'clear' => array(),
+  );
+
+  /**
+   * Construct a new EntityStructureWrapper object.
+   *
+   * @param $type
+   *   The type of the passed data.
+   * @param $data
+   *   Optional. The data to wrap.
+   * @param $info
+   *   Used to for specifying metadata about the data and internally to pass
+   *   info about properties down the tree. For specifying metadata known keys
+   *   are:
+   *   - property info: An array of info about the properties of the wrapped
+   *     data structure. It has to contain an array of property info in the same
+   *     structure as used by hook_entity_property_info().
+   */
+  public function __construct($type, $data = NULL, $info = array()) {
+    parent::__construct($type, $data, $info);
+    $this->info += array('property defaults' => array());
+    $info += array('property info' => array());
+    $this->propertyInfo['properties'] = $info['property info'];
+  }
+
+  /**
+   * May be used to lazy-load additional info about the data, depending on the
+   * concrete passed data.
+   */
+  protected function spotInfo() {
+    // Apply the callback if set, such that the caller may alter the info.
+    if (!empty($this->info['property info alter']) && !$this->propertyInfoAltered) {
+      $this->propertyInfo = call_user_func($this->info['property info alter'], $this, $this->propertyInfo);
+      $this->propertyInfoAltered = TRUE;
+    }
+  }
+
+  /**
+   * Gets the info about the given property.
+   *
+   * @param $name
+   *   The name of the property. If not given, info about all properties will
+   *   be returned.
+   * @throws EntityMetadataWrapperException
+   *   If there is no such property.
+   * @return
+   *   An array of info about the property.
+   */
+  public function getPropertyInfo($name = NULL) {
+    $this->spotInfo();
+    if (!isset($name)) {
+      return $this->propertyInfo['properties'];
+    }
+    if (!isset($this->propertyInfo['properties'][$name])) {
+      throw new EntityMetadataWrapperException('Unknown data property ' . check_plain($name) . '.');
+    }
+    return $this->propertyInfo['properties'][$name] + $this->info['property defaults'] + $this->propertyInfoDefaults;
+  }
+
+  /**
+   * Returns a reference on the property info.
+   *
+   * If possible, use the property info alter callback for spotting metadata.
+   * The reference may be used to alter the property info for any remaining
+   * cases, e.g. if additional metadata has been asserted.
+   */
+  public function &refPropertyInfo() {
+    return $this->propertyInfo;
+  }
+
+  /**
+   * Sets a new language to use for retrieving properties.
+   *
+   * @param $langcode
+   *   The language code of the language to set.
+   * @return EntityWrapper
+   */
+  public function language($langcode = LANGUAGE_NONE) {
+    if ($langcode != $this->langcode) {
+      $this->langcode = $langcode;
+      $this->cache = array();
+    }
+    return $this;
+  }
+
+  /**
+   * Gets the language used for retrieving properties.
+   *
+   * @return String
+   *   The language object of the language or NULL for the default language.
+   *
+   * @see EntityStructureWrapper::language()
+   */
+  public function getPropertyLanguage() {
+    if ($this->langcode != LANGUAGE_NONE && $list = language_list()) {
+      if (isset($list[$this->langcode])) {
+        return $list[$this->langcode];
+      }
+    }
+    return NULL;
+  }
+
+  /**
+   * Get the wrapper for a property.
+   *
+   * @return
+   *   An instance of EntityMetadataWrapper.
+   */
+  public function get($name) {
+    // Look it up in the cache if possible.
+    if (!array_key_exists($name, $this->cache)) {
+      if ($info = $this->getPropertyInfo($name)) {
+        $info += array('parent' => $this, 'name' => $name, 'langcode' => $this->langcode, 'property defaults' => array());
+        $info['property defaults'] += $this->info['property defaults'];
+        $this->cache[$name] = entity_metadata_wrapper($info['type'], NULL, $info);
+      }
+      else {
+        throw new EntityMetadataWrapperException('There is no property ' . check_plain($name) . " for this entity.");
+      }
+    }
+    return $this->cache[$name];
+  }
+
+  /**
+   * Magic method: Get a wrapper for a property.
+   */
+  public function __get($name) {
+    if (strpos($name, 'krumo') === 0) {
+      // #914934 Ugly workaround to allow krumo to write its recursion property.
+      // This is necessary to make dpm() work without throwing exceptions.
+      return NULL;
+    }
+    $get = $this->get($name);
+    return $get;
+  }
+
+  /**
+   * Magic method: Set a property.
+   */
+  public function __set($name, $value) {
+    if (strpos($name, 'krumo') === 0) {
+      // #914934 Ugly workaround to allow krumo to write its recursion property.
+      // This is necessary to make dpm() work without throwing exceptions.
+      $this->$name = $value;
+    }
+    else {
+      $this->get($name)->set($value);
+    }
+  }
+
+  /**
+   * Gets the value of a property.
+   */
+  protected function getPropertyValue($name, &$info) {
+    $options = array('language' => $this->getPropertyLanguage(), 'absolute' => TRUE);
+    $data = $this->value();
+    if (!isset($data)) {
+      throw new EntityMetadataWrapperException('Unable to get the data property ' . check_plain($name) . ' as the parent data structure is not set.');
+    }
+    return $info['getter callback']($data, $options, $name, $this->type, $info);
+  }
+
+  /**
+   * Gets the raw value of a property.
+   */
+  protected function getPropertyRaw($name, &$info) {
+    if (!empty($info['raw getter callback'])) {
+      $options = array('language' => $this->getPropertyLanguage(), 'absolute' => TRUE);
+      $data = $this->value();
+      if (!isset($data)) {
+        throw new EntityMetadataWrapperException('Unable to get the data property ' . check_plain($name) . ' as the parent data structure is not set.');
+      }
+      return $info['raw getter callback']($data, $options, $name, $this->type, $info);
+    }
+    return $this->getPropertyValue($name, $info);
+  }
+
+  /**
+   * Sets a property.
+   */
+  protected function setProperty($name, $value) {
+    $info = $this->getPropertyInfo($name);
+    if (!empty($info['setter callback'])) {
+      $data = $this->value();
+
+      // In case the data structure is not set, support simple auto-creation
+      // for arrays. Else an exception is thrown.
+      if (!isset($data)) {
+        if (!empty($this->info['auto creation']) && !($this instanceof EntityDrupalWrapper)) {
+          $data = $this->info['auto creation']($name, $this->info);
+        }
+        else {
+          throw new EntityMetadataWrapperException('Unable to set the data property ' . check_plain($name) . ' as the parent data structure is not set.');
+        }
+      }
+
+      // Invoke the setter callback for updating our data.
+      $info['setter callback']($data, $name, $value, $this->langcode, $this->type, $info);
+
+      // If the setter has not thrown any exceptions, proceed and apply the
+      // update to the current and any parent wrappers as necessary.
+      $data = $this->info['type'] == 'entity' ? $this : $data;
+      $this->set($data);
+
+      // Clear the cache of properties dependent on this value.
+      foreach ($info['clear'] as $name) {
+        if (isset($this->cache[$name])) {
+          $this->cache[$name]->clear();
+        }
+      }
+    }
+    else {
+      throw new EntityMetadataWrapperException('Entity property ' . check_plain($name) . " doesn't support writing.");
+    }
+  }
+
+  protected function propertyAccess($name, $op, $account = NULL) {
+    $info = $this->getPropertyInfo($name);
+    // If the property should be accessed and it's an entity, make sure the user
+    // is allowed to view that entity.
+    if ($op == 'view' && $this->$name instanceof EntityDrupalWrapper && !$this->$name->entityAccess($op, $account)) {
+      return FALSE;
+    }
+    // If a property should be edited and this is an entity, make sure the user
+    // has update access for this entity.
+    if ($op == 'edit') {
+      $entity = $this;
+      while (!($entity instanceof EntityDrupalWrapper) && isset($entity->info['parent'])) {
+        $entity = $entity->info['parent'];
+      }
+      if ($entity instanceof EntityDrupalWrapper && !$entity->entityAccess('update', $account)) {
+        return FALSE;
+      }
+    }
+    if (!empty($info['access callback'])) {
+      $data = $this->dataAvailable() ? $this->value() : NULL;
+      return call_user_func($info['access callback'], $op, $name, $data, $account, $this->type);
+    }
+    elseif ($op == 'edit' && isset($info['setter permission'])) {
+      return user_access($info['setter permission'], $account);
+    }
+    return TRUE;
+  }
+
+  /**
+   * Magic method: Can be used to check if a property is known.
+   */
+  public function __isset($name) {
+    $this->spotInfo();
+    return isset($this->propertyInfo['properties'][$name]);
+  }
+
+  public function getIterator() {
+    $this->spotInfo();
+    return new EntityMetadataWrapperIterator($this, array_keys($this->propertyInfo['properties']));
+  }
+
+  /**
+   * Returns the identifier of the data structure. If there is none, NULL is
+   * returned.
+   */
+  public function getIdentifier() {
+    return isset($this->id) && $this->dataAvailable() ? $this->id->value() : NULL;
+  }
+
+  /**
+   * Prepare for serializiation.
+   */
+  public function __sleep() {
+    $vars = parent::__sleep();
+    unset($vars['propertyInfoDefaults']);
+    return $vars;
+  }
+
+  public function clear() {
+    $this->propertyInfoAltered = FALSE;
+    parent::clear();
+  }
+}
+
+/**
+ * Provides a wrapper for entities registrered in hook_entity_info().
+ *
+ * The wrapper eases applying getter and setter callbacks of entity properties
+ * specified in hook_entity_property_info().
+ */
+class EntityDrupalWrapper extends EntityStructureWrapper {
+
+  /**
+   * Contains the entity id.
+   */
+  protected $id = FALSE;
+  protected $bundle;
+  protected $entityInfo;
+
+  /**
+   * Construct a new EntityDrupalWrapper object.
+   *
+   * @param $type
+   *   The type of the passed data.
+   * @param $data
+   *   Optional. The entity to wrap or its identifier.
+   * @param $info
+   *   Optional. Used internally to pass info about properties down the tree.
+   */
+  public function __construct($type, $data = NULL, $info = array()) {
+    parent::__construct($type, $data, $info);
+    $this->setUp();
+  }
+
+  protected function setUp() {
+    $this->propertyInfo = entity_get_property_info($this->type) + array('properties' => array());
+    $info = $this->info + array('property info' => array(), 'bundle' => NULL);
+    $this->propertyInfo['properties'] += $info['property info'];
+    $this->bundle = $info['bundle'];
+    $this->entityInfo = entity_get_info($this->type);
+    if (isset($this->bundle)) {
+      $this->spotBundleInfo(FALSE);
+    }
+  }
+
+  /**
+   * Sets the entity internally accepting both the entity id and object.
+   */
+  protected function setEntity($data) {
+    // For entities we allow getter callbacks to return FALSE, which we
+    // interpret like NULL values as unset properties.
+    if (isset($data) && $data !== FALSE && !is_object($data)) {
+      $this->id = $data;
+      $this->data = FALSE;
+    }
+    elseif (is_object($data) && $data instanceof EntityDrupalWrapper) {
+      // We got a wrapped entity passed, so take over its values.
+      $this->id = $data->id;
+      $this->data = $data->data;
+      // For generic entity references, also update the entity type accordingly.
+      if ($this->info['type'] == 'entity') {
+        $this->type = $data->type;
+      }
+    }
+    elseif (is_object($data)) {
+      // We got the entity object passed.
+      $this->data = $data;
+      $id = entity_id($this->type, $data);
+      $this->id = isset($id) ? $id : FALSE;
+    }
+    else {
+      $this->id = FALSE;
+      $this->data = NULL;
+    }
+  }
+
+  /**
+   * Used to lazy-load bundle info. So the wrapper can be loaded e.g. just
+   * for setting without the data being loaded.
+   */
+  protected function spotInfo() {
+    if (!$this->propertyInfoAltered) {
+      if ($this->info['type'] == 'entity' && $this->dataAvailable() && $this->value()) {
+        // Add in entity-type specific details.
+        $this->setUp();
+      }
+      $this->spotBundleInfo(TRUE);
+      parent::spotInfo();
+      $this->propertyInfoAltered = TRUE;
+    }
+  }
+
+  /**
+   * Tries to determine the bundle and adds in the according property info.
+   *
+   * @param $load
+   *   Whether the entity should be loaded to spot the info if necessary.
+   */
+  protected function spotBundleInfo($load = TRUE) {
+    // Like entity_extract_ids() assume the entity type if no key is given.
+    if (empty($this->entityInfo['entity keys']['bundle']) && $this->type != 'entity') {
+      $this->bundle = $this->type;
+    }
+    // Detect the bundle if not set yet and add in properties from the bundle.
+    elseif (!$this->bundle && $load && $this->dataAvailable()) {
+      try {
+        if ($entity = $this->value()) {
+          list($id, $vid, $bundle) = entity_extract_ids($this->type, $entity);
+          $this->bundle = $bundle;
+        }
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // Loading data failed, so we cannot derive the used bundle.
+      }
+    }
+
+    if ($this->bundle && isset($this->propertyInfo['bundles'][$this->bundle])) {
+      $bundle_info = (array) $this->propertyInfo['bundles'][$this->bundle] + array('properties' => array());
+      // Allow bundles to re-define existing properties, such that the bundle
+      // can add in more bundle-specific details like the bundle of a referenced
+      // entity.
+      $this->propertyInfo['properties'] = $bundle_info['properties'] + $this->propertyInfo['properties'];
+    }
+  }
+
+  /**
+   * Returns the identifier of the wrapped entity.
+   *
+   * @see entity_id()
+   */
+  public function getIdentifier() {
+    return $this->dataAvailable() ? $this->value(array('identifier' => TRUE)) : NULL;
+  }
+
+  /**
+   * Returns the bundle of an entity, or FALSE if it has no bundles.
+   */
+  public function getBundle() {
+    if ($this->dataAvailable()) {
+      $this->spotInfo();
+      return $this->bundle;
+    }
+  }
+
+  /**
+   * Overridden.
+   *
+   * @param $options
+   *   An array of options. Known keys:
+   *   - identifier: If set to TRUE, the entity identifier is returned.
+   */
+  public function value(array $options = array()) {
+    // Try loading the data via the getter callback if there is none yet.
+    if (!isset($this->data)) {
+      $this->setEntity(parent::value());
+    }
+    if (!empty($options['identifier'])) {
+      return $this->id;
+    }
+    elseif (!$this->data && !empty($this->id)) {
+      // Lazy load the entity if necessary.
+      $return = entity_load($this->type, array($this->id));
+      // In case the entity cannot be loaded, we return NULL just as for empty
+      // properties.
+      $this->data = $return ? reset($return) : NULL;
+    }
+    return $this->data;
+  }
+
+  /**
+   * Returns the entity prepared for rendering.
+   *
+   * @see entity_view()
+   */
+  public function view($view_mode = 'full', $langcode = NULL, $page = NULL) {
+    return entity_view($this->type(), array($this->value()), $view_mode, $langcode, $page);
+  }
+
+  /**
+   * Overridden to support setting the entity by either the object or the id.
+   */
+  public function set($value) {
+    if (!$this->validate($value)) {
+      throw new EntityMetadataWrapperException('Invalid data value given. Be sure it matches the required data type and format.');
+    }
+    if ($this->info['type'] == 'entity' && $value === $this) {
+      // Nothing to do.
+      return $this;
+    }
+    $previous_id = $this->id;
+    $previous_type = $this->type;
+    // Set value, so we get the identifier and pass it to the normal setter.
+    $this->clear();
+    $this->setEntity($value);
+    // Generally, we have to update the parent only if the entity reference
+    // has changed. In case of a generic entity reference, we pass the entity
+    // wrapped. Else we just pass the id of the entity to the setter callback.
+    if ($this->info['type'] == 'entity' && ($previous_id != $this->id || $previous_type != $this->type)) {
+      // We need to clone the wrapper we pass through as value, so it does not
+      // get cleared when the current wrapper instance gets cleared.
+      $this->updateParent(clone $this);
+    }
+    // In case the entity has been unset, we cannot properly detect changes as
+    // the previous id defaults to FALSE for unloaded entities too. So in that
+    // case we just always update the parent.
+    elseif ($this->id === FALSE && !$this->data) {
+      $this->updateParent(NULL);
+    }
+    elseif ($previous_id != $this->id) {
+      $this->updateParent($this->id);
+    }
+    return $this;
+  }
+
+  /**
+   * Overridden.
+   */
+  public function clear() {
+    $this->id = NULL;
+    $this->bundle = isset($this->info['bundle']) ? $this->info['bundle'] : NULL;
+    if ($this->type != $this->info['type']) {
+      // Reset entity info / property info based upon the info provided during
+      // the creation of the wrapper.
+      $this->type = $this->info['type'];
+      $this->setUp();
+    }
+    parent::clear();
+  }
+
+  /**
+   * Overridden.
+   */
+  public function type() {
+    // In case of a generic entity wrapper, load the data first to determine
+    // the type of the concrete entity.
+    if ($this->dataAvailable() && $this->info['type'] == 'entity') {
+      try {
+        $this->value(array('identifier' => TRUE));
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // If loading data fails, we cannot determine the concrete entity type.
+      }
+    }
+    return $this->type;
+  }
+
+  /**
+   * Checks whether the operation $op is allowed on the entity.
+   *
+   * @see entity_access()
+   */
+  public function entityAccess($op, $account = NULL) {
+    $entity = $this->dataAvailable() ? $this->value() : NULL;
+    return entity_access($op, $this->type, $entity, $account);
+  }
+
+  /**
+   * Permanently save the wrapped entity.
+   *
+   * @throws EntityMetadataWrapperException
+   *   If the entity type does not support saving.
+   *
+   * @return EntityDrupalWrapper
+   */
+  public function save() {
+    if ($this->data) {
+      if (!entity_type_supports($this->type, 'save')) {
+        throw new EntityMetadataWrapperException("There is no information about how to save entities of type " . check_plain($this->type) . '.');
+      }
+      entity_save($this->type, $this->data);
+      // On insert, update the identifier afterwards.
+      if (!$this->id) {
+        list($this->id, , ) = entity_extract_ids($this->type, $this->data);
+      }
+    }
+    // If the entity hasn't been loaded yet, don't bother saving it.
+    return $this;
+  }
+
+  /**
+   * Permanently delete the wrapped entity.
+   *
+   * @return EntityDrupalWrapper
+   */
+  public function delete() {
+    if ($this->dataAvailable() && $this->value()) {
+      $return = entity_delete($this->type, $this->id);
+      if ($return === FALSE) {
+        throw new EntityMetadataWrapperException("There is no information about how to delete entities of type " . check_plain($this->type) . '.');
+      }
+    }
+    return $this;
+  }
+
+  /**
+   * Gets the info about the wrapped entity.
+   */
+  public function entityInfo() {
+    return $this->entityInfo;
+  }
+
+  /**
+   * Returns the name of the key used by the entity for given entity key.
+   *
+   * @param $name
+   *   One of 'id', 'name', 'bundle' or 'revision'.
+   * @return
+   *   The name of the key used by the entity.
+   */
+  public function entityKey($name) {
+    return isset($this->entityInfo['entity keys'][$name]) ? $this->entityInfo['entity keys'][$name] : FALSE;
+  }
+
+  /**
+   * Returns the entity label.
+   *
+   * @see entity_label()
+   */
+  public function label() {
+    if ($entity = $this->value()) {
+      return entity_label($this->type, $entity);
+    }
+  }
+
+  /**
+   * Prepare for serializiation.
+   */
+  public function __sleep() {
+    $vars = parent::__sleep();
+    // Don't serialize the loaded entity and its property info.
+    unset($vars['data'], $vars['propertyInfo'], $vars['propertyInfoAltered'], $vars['entityInfo']);
+    // In case the entity is not saved yet, serialize the unsaved data.
+    if ($this->dataAvailable() && $this->id === FALSE) {
+      $vars['data'] = 'data';
+    }
+    return $vars;
+  }
+
+  public function __wakeup() {
+    $this->setUp();
+    if ($this->id !== FALSE) {
+      // Make sure data is set, so the entity will be loaded when needed.
+      $this->data = FALSE;
+    }
+  }
+}
+
+/**
+ * Wraps a list of values.
+ *
+ * If the wrapped data is a list of data, its numerical indexes may be used to
+ * retrieve wrappers for the list items. For that this wrapper implements
+ * ArrayAccess so it may be used like a usual numerically indexed array.
+ */
+class EntityListWrapper extends EntityMetadataWrapper implements IteratorAggregate, ArrayAccess, Countable {
+
+  /**
+   * The type of contained items.
+   */
+  protected $itemType;
+
+  /**
+   * Whether this is a list of entities with a known entity type, i.e. for
+   * generic list of entities (list<entity>) this is FALSE.
+   */
+  protected $isEntityList;
+
+
+  public function __construct($type, $data = NULL, $info = array()) {
+    parent::__construct($type, NULL, $info);
+
+    $this->itemType = entity_property_list_extract_type($this->type);
+    if (!$this->itemType) {
+      $this->itemType = 'unknown';
+    }
+    $this->isEntityList = (bool) entity_get_info($this->itemType);
+
+    if (isset($data)) {
+      $this->set($data);
+    }
+  }
+
+  /**
+   * Get the wrapper for a single item.
+   *
+   * @return
+   *   An instance of EntityMetadataWrapper.
+   */
+  public function get($delta) {
+    // Look it up in the cache if possible.
+    if (!array_key_exists($delta, $this->cache)) {
+      if (!isset($delta)) {
+        // The [] operator has been used so point at a new entry.
+        $values = parent::value();
+        $delta = $values ? max(array_keys($values)) + 1 : 0;
+      }
+      if (is_numeric($delta)) {
+        $info = array('parent' => $this, 'name' => $delta) + $this->info;
+        $this->cache[$delta] = entity_metadata_wrapper($this->itemType, NULL, $info);
+      }
+      else {
+        throw new EntityMetadataWrapperException('There can be only numerical keyed items in a list.');
+      }
+    }
+    return $this->cache[$delta];
+  }
+
+  protected function getPropertyValue($delta) {
+    // Make use parent::value() to easily by-pass any entity-loading.
+    $data = parent::value();
+    if (isset($data[$delta])) {
+      return $data[$delta];
+    }
+  }
+
+  protected function getPropertyRaw($delta) {
+    return $this->getPropertyValue($delta);
+  }
+
+  protected function setProperty($delta, $value) {
+    $data = parent::value();
+    if (is_numeric($delta)) {
+      $data[$delta] = $value;
+      $this->set($data);
+    }
+  }
+
+  protected function propertyAccess($delta, $op, $account = NULL) {
+    return $this->access($op, $account);
+  }
+
+  /**
+   * Returns the list as numerically indexed array.
+   *
+   * Note that a list of entities might contain stale entity references. In
+   * that case the wrapper and the identifier of a stale reference would be
+   * still accessible, however the entity object value would be NULL. That way,
+   * there may be NULL values in lists of entity objects due to stale entity
+   * references.
+   *
+   * @param $options
+   *   An array of options. Known keys:
+   *   - identifier: If set to TRUE for a list of entities, it won't be returned
+   *     as list of fully loaded entity objects, but as a list of entity ids.
+   *     Note that this list may contain ids of stale entity references.
+   */
+  public function value(array $options = array()) {
+    // For lists of entities fetch full entity objects before returning.
+    // Generic entity-wrappers need to be handled separately though.
+    if ($this->isEntityList && empty($options['identifier']) && $this->dataAvailable()) {
+      $list = parent::value();
+      $entities = $list ? entity_load($this->get(0)->type, $list) : array();
+      // Make sure to keep the array keys as present in the list.
+      foreach ($list as $key => $id) {
+        // In case the entity cannot be loaded, we return NULL just as for empty
+        // properties.
+        $list[$key] = isset($entities[$id]) ? $entities[$id] : NULL;
+      }
+      return $list;
+    }
+    return parent::value();
+  }
+
+  public function set($values) {
+    // Support setting lists of fully loaded entities.
+    if ($this->isEntityList && $values && is_object(reset($values))) {
+      foreach ($values as $key => $value) {
+        list($id, $vid, $bundle) = entity_extract_ids($this->itemType, $value);
+        $values[$key] = $id;
+      }
+    }
+    return parent::set($values);
+  }
+
+  /**
+   * If we wrap a list, we return an iterator over the data list.
+   */
+  public function getIterator() {
+    // In case there is no data available, just iterate over the first item.
+    return new EntityMetadataWrapperIterator($this, $this->dataAvailable() ? array_keys(parent::value()) : array(0));
+  }
+
+  /**
+   * Implements the ArrayAccess interface.
+   */
+  public function offsetGet($delta) {
+    return $this->get($delta);
+  }
+
+  public function offsetExists($delta) {
+    return $this->dataAvailable() && ($data = $this->value()) && array_key_exists($delta, $data);
+  }
+
+  public function offsetSet($delta, $value) {
+    $this->get($delta)->set($value);
+  }
+
+  public function offsetUnset($delta) {
+    if ($this->offsetExists($delta)) {
+      unset($this->data[$delta]);
+      $this->set($this->data);
+    }
+  }
+
+  public function count() {
+    return $this->dataAvailable() ? count($this->value()) : 0;
+  }
+
+  /**
+   * Overridden.
+   */
+  public function validate($value) {
+    // Required lists may not be empty or unset.
+    if (!empty($this->info['required']) && empty($value)) {
+      return FALSE;
+    }
+    return parent::validate($value);
+  }
+
+  /**
+   * Returns the label for the list of set values if available.
+   */
+  public function label() {
+    if ($options = $this->optionsList('view')) {
+      $options = entity_property_options_flatten($options);
+      $labels = array_intersect_key($options, array_flip((array) parent::value()));
+    }
+    else {
+      // Get each label on its own, e.g. to support getting labels of a list
+      // of entities.
+      $labels = array();
+      foreach ($this as $key => $property) {
+        $label = $property->label();
+        if (!$label) {
+          return NULL;
+        }
+        $labels[] = $label;
+      }
+    }
+    return isset($labels) ? implode(', ', $labels) : NULL;
+  }
+}
+
+/**
+ * Provide a separate Exception so it can be caught separately.
+ */
+class EntityMetadataWrapperException extends Exception { }
+
+
+/**
+ * Allows to easily iterate over existing child wrappers.
+ */
+class EntityMetadataWrapperIterator implements RecursiveIterator {
+
+  protected $position = 0;
+  protected $wrapper, $keys;
+
+  public function __construct(EntityMetadataWrapper $wrapper, array $keys) {
+    $this->wrapper = $wrapper;
+    $this->keys = $keys;
+  }
+
+  function rewind() {
+    $this->position = 0;
+  }
+
+  function current() {
+    return $this->wrapper->get($this->keys[$this->position]);
+  }
+
+  function key() {
+    return $this->keys[$this->position];
+  }
+
+  function next() {
+    $this->position++;
+  }
+
+  function valid() {
+    return isset($this->keys[$this->position]);
+  }
+
+  public function hasChildren() {
+    return $this->current() instanceof IteratorAggregate;
+  }
+
+  public function getChildren() {
+    return $this->current()->getIterator();
+  }
+}
+
+/**
+ * An array object implementation keeping the reference on the given array so
+ * changes to the object are reflected in the passed array.
+ */
+class EntityMetadataArrayObject implements ArrayAccess, Countable, IteratorAggregate {
+
+  protected $data;
+
+  public function __construct(&$array) {
+    $this->data =& $array;
+  }
+
+  public function &getArray() {
+    return $this->data;
+  }
+
+  /**
+   * Implements the ArrayAccess interface.
+   */
+  public function offsetGet($delta) {
+    return $this->data[$delta];
+  }
+
+  public function offsetExists($delta) {
+    return array_key_exists($delta, $this->data);
+  }
+
+  public function offsetSet($delta, $value) {
+    $this->data[$delta] = $value;
+  }
+
+  public function offsetUnset($delta) {
+    unset($this->data[$delta]);
+  }
+
+  public function count() {
+    return count($this->data);
+  }
+
+  public function getIterator() {
+    return new ArrayIterator($this->data);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/book.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Provides info about book nodes.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() on top of book module.
+ *
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_book_entity_property_info_alter(&$info) {
+  // Add meta-data about the added node properties.
+  $properties = &$info['node']['properties'];
+
+  $properties['book'] = array(
+    'label' => t("Book"),
+    'type' => 'node',
+    'description' => t("If part of a book, the book to which this book page belongs."),
+    'getter callback' => 'entity_metadata_book_get_properties',
+  );
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/callbacks.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,974 @@
+<?php
+
+/**
+ * @file
+ * Provides various callbacks for the whole core module integration.
+ */
+
+/**
+ * Callback for getting properties of an entity.
+ */
+function entity_metadata_entity_get_properties($entity, array $options, $name, $entity_type) {
+  if ($name == 'url') {
+    $return = entity_uri($entity_type, $entity);
+    return url($return['path'], $return['options'] + $options);
+  }
+}
+
+/**
+ * Callback for getting book node properties.
+ * @see entity_metadata_book_entity_info_alter()
+ */
+function entity_metadata_book_get_properties($node, array $options, $name, $entity_type) {
+  if (!isset($node->book['bid'])) {
+    throw new EntityMetadataWrapperException('This node is no book page.');
+  }
+  return $node->book['bid'];
+}
+
+/**
+ * Callback for getting comment properties.
+ * @see entity_metadata_comment_entity_info_alter()
+ */
+function entity_metadata_comment_get_properties($comment, array $options, $name) {
+  switch ($name) {
+    case 'name':
+      return $comment->name;
+
+    case 'mail':
+      if ($comment->uid != 0) {
+        $account = user_load($comment->uid);
+        return $account->mail;
+      }
+      return $comment->mail;
+
+    case 'edit_url':
+      return url('comment/edit/' . $comment->cid, $options);
+
+    case 'parent':
+      if (!empty($comment->pid)) {
+        return $comment->pid;
+      }
+      // There is no parent comment.
+      return NULL;
+  }
+}
+
+/**
+ * Callback for setting comment properties.
+ * @see entity_metadata_comment_entity_info_alter()
+ */
+function entity_metadata_comment_setter($comment, $name, $value) {
+  switch ($name) {
+    case 'node':
+      $comment->nid = $value;
+      // Also set the bundle name.
+      $node = node_load($value);
+      $comment->node_type = 'comment_node_' . $node->type;
+      break;
+  }
+}
+
+/**
+ * Callback for getting comment related node properties.
+ * @see entity_metadata_comment_entity_info_alter()
+ */
+function entity_metadata_comment_get_node_properties($node, array $options, $name, $entity_type) {
+  switch ($name) {
+    case 'comment_count':
+      return isset($node->comment_count) ? $node->comment_count : 0;
+
+    case 'comment_count_new':
+      return comment_num_new($node->nid);
+  }
+}
+
+/**
+ * Getter callback for getting global languages.
+ */
+function entity_metadata_locale_get_languages($data, array $options, $name) {
+  return isset($GLOBALS[$name]) ? $GLOBALS[$name]->language : NULL;
+}
+
+/**
+ * Getter callback for getting the preferred user language.
+ */
+function entity_metadata_locale_get_user_language($account, array $options, $name) {
+  return user_preferred_language($account)->language;
+}
+
+/**
+ * Return the options lists for the node and comment status property.
+ */
+function entity_metadata_status_options_list() {
+  return array(
+    NODE_PUBLISHED => t('Published'),
+    NODE_NOT_PUBLISHED => t('Unpublished'),
+  );
+}
+
+/**
+ * Callback for getting node properties.
+ *
+ * @see entity_metadata_node_entity_info_alter()
+ */
+function entity_metadata_node_get_properties($node, array $options, $name, $entity_type) {
+  switch ($name) {
+    case 'is_new':
+      return empty($node->nid) || !empty($node->is_new);
+
+    case 'source':
+      if (!empty($node->tnid) && $source = node_load($node->tnid)) {
+        return $source;
+      }
+      return NULL;
+
+    case 'edit_url':
+      return url('node/' . $node->nid . '/edit', $options);
+  }
+}
+
+/**
+ * Callback for determing access for node revision related properties.
+ */
+function entity_metadata_node_revision_access($op, $name, $entity = NULL, $account = NULL) {
+  return $op == 'view' ? user_access('view revisions', $account) : user_access('administer nodes', $account);
+}
+
+/**
+ * Callback for getting poll properties.
+ * @see entity_metadata_poll_entity_info_alter()
+ */
+function entity_metadata_poll_node_get_properties($node, array $options, $name) {
+  $total_votes = $highest_votes = 0;
+  foreach ($node->choice as $choice) {
+    if ($choice['chvotes'] > $highest_votes) {
+      $winner = $choice;
+      $highest_votes = $choice['chvotes'];
+    }
+    $total_votes = $total_votes + $choice['chvotes'];
+  }
+
+  if ($name == 'poll_duration') {
+    return $node->runtime;
+  }
+  elseif ($name == 'poll_votes') {
+    return $total_votes;
+  }
+  elseif (!isset($winner)) {
+    // There is no poll winner yet.
+    return NULL;
+  }
+  switch ($name) {
+    case 'poll_winner_votes':
+        return $winner['chvotes'];
+
+    case 'poll_winner':
+        return $winner['chtext'];
+
+    case 'poll_winner_percent':
+        return ($winner['chvotes'] / $total_votes) * 100;
+  }
+}
+
+/**
+ * Callback for getting statistics properties.
+ * @see entity_metadata_statistics_entity_info_alter()
+ */
+function entity_metadata_statistics_node_get_properties($node, array $options, $name) {
+  $statistics = (array) statistics_get($node->nid);
+  $statistics += array('totalcount' => 0, 'daycount' => 0, 'timestamp' => NULL);
+
+  switch ($name) {
+    case 'views':
+      return $statistics['totalcount'];
+
+    case 'day_views':
+      return $statistics['daycount'];
+
+    case 'last_view':
+      return $statistics['timestamp'];
+  }
+}
+
+/**
+ * Callback for getting site-wide properties.
+ * @see entity_metadata_system_entity_info_alter()
+ */
+function entity_metadata_system_get_properties($data = FALSE, array $options, $name) {
+  switch ($name) {
+    case 'name':
+      return variable_get('site_name', 'Drupal');
+
+    case 'url':
+      return url('<front>', $options);
+
+    case 'login_url':
+      return url('user', $options);
+
+    case 'current_user':
+      return $GLOBALS['user']->uid ? $GLOBALS['user']->uid : drupal_anonymous_user();
+
+    case 'current_date':
+      return REQUEST_TIME;
+
+    case 'current_page':
+      // Subsequent getters of the struct retrieve the actual values.
+      return array();
+
+    default:
+      return variable_get('site_' . $name, '');
+  }
+}
+
+/**
+ * Callback for getting properties for the current page request.
+ * @see entity_metadata_system_entity_info_alter()
+ */
+function entity_metadata_system_get_page_properties($data = array(), array $options, $name) {
+  switch ($name) {
+    case 'url':
+      return $GLOBALS['base_root'] . request_uri();
+  }
+}
+
+/**
+ * Callback for getting file properties.
+ * @see entity_metadata_system_entity_info_alter()
+ */
+function entity_metadata_system_get_file_properties($file, array $options, $name) {
+  switch ($name) {
+    case 'name':
+      return $file->filename;
+
+    case 'mime':
+      return $file->filemime;
+
+    case 'size':
+      return $file->filesize;
+
+    case 'url':
+      return url(file_create_url($file->uri), $options);
+
+    case 'owner':
+      return $file->uid;
+  }
+}
+
+/**
+ * Callback for getting term properties.
+ *
+ * @see entity_metadata_taxonomy_entity_info_alter()
+ */
+function entity_metadata_taxonomy_term_get_properties($term, array $options, $name) {
+  switch ($name) {
+    case 'node_count':
+      return count(taxonomy_select_nodes($term->tid));
+
+    case 'description':
+      return check_markup($term->description, isset($term->format) ? $term->format : NULL, '', TRUE);
+
+    case 'parent':
+      if (isset($term->parent[0]) && !is_array(isset($term->parent[0]))) {
+        return $term->parent;
+      }
+      return array_keys(taxonomy_get_parents($term->tid));
+
+    case 'parents_all':
+      // We have to return an array of ids.
+      $tids = array();
+      foreach (taxonomy_get_parents_all($term->tid) as $parent) {
+        $tids[] = $parent->tid;
+      }
+      return $tids;
+  }
+}
+
+/**
+ * Callback for setting term properties.
+ *
+ * @see entity_metadata_taxonomy_entity_info_alter()
+ */
+function entity_metadata_taxonomy_term_setter($term, $name, $value) {
+  switch ($name) {
+    case 'vocabulary':
+      // Make sure to update the taxonomy bundle key, so load the vocabulary.
+      // Support both, loading by name or ID.
+      $vocabulary = is_numeric($value) ? taxonomy_vocabulary_load($value) : taxonomy_vocabulary_machine_name_load($value);
+      $term->vocabulary_machine_name = $vocabulary->machine_name;
+      return $term->vid = $vocabulary->vid;
+    case 'parent':
+      return $term->parent = $value;
+  }
+}
+
+/**
+ * Callback for getting vocabulary properties.
+ * @see entity_metadata_taxonomy_entity_info_alter()
+ */
+function entity_metadata_taxonomy_vocabulary_get_properties($vocabulary, array $options, $name) {
+  switch ($name) {
+    case 'term_count':
+      $sql = "SELECT COUNT (1) FROM {taxonomy_term_data} td WHERE td.vid = :vid";
+      return db_query($sql, array(':vid' => $vocabulary->vid))->fetchField();
+  }
+}
+
+/**
+ * Callback for getting user properties.
+ * @see entity_metadata_user_entity_info_alter()
+ */
+function entity_metadata_user_get_properties($account, array $options, $name, $entity_type) {
+  switch ($name) {
+    case 'last_access':
+      // In case there was no access the value is 0, but we have to return NULL.
+      return empty($account->access) ? NULL : $account->access;
+
+    case 'last_login':
+      return empty($account->login) ? NULL : $account->login;
+
+    case 'name':
+      return empty($account->uid) ? variable_get('anonymous', t('Anonymous')) : $account->name;
+
+    case 'url':
+      if (empty($account->uid)) {
+        return NULL;
+      }
+      $return = entity_uri('user', $account);
+      return $return ? url($return['path'], $return['options'] + $options) : '';
+
+    case 'edit_url':
+      return empty($account->uid) ? NULL : url("user/$account->uid/edit", $options);
+
+    case 'roles':
+      return isset($account->roles) ? array_keys($account->roles) : array();
+
+    case 'theme':
+      return empty($account->theme) ? variable_get('theme_default', 'bartik') : $account->theme;
+  }
+}
+
+/**
+ * Callback for setting user properties.
+ * @see entity_metadata_user_entity_info_alter()
+ */
+function entity_metadata_user_set_properties($account, $name, $value) {
+  switch ($name) {
+    case 'roles':
+      $account->roles = array_intersect_key(user_roles(), array_flip($value));
+      break;
+  }
+}
+
+/**
+ * Options list callback returning all user roles.
+ */
+function entity_metadata_user_roles($property_name = 'roles', $info = array(), $op = 'edit') {
+  $roles = user_roles();
+  if ($op == 'edit') {
+    unset($roles[DRUPAL_AUTHENTICATED_RID], $roles[DRUPAL_ANONYMOUS_RID]);
+  }
+  return $roles;
+}
+
+/**
+ * Return the options lists for user status property.
+ */
+function entity_metadata_user_status_options_list() {
+  return array(
+    0 => t('Blocked'),
+    1 => t('Active'),
+  );
+}
+
+/**
+ * Callback defining an options list for language properties.
+ */
+function entity_metadata_language_list() {
+  $list = array();
+  $list[LANGUAGE_NONE] = t('Language neutral');
+  foreach (language_list() as $language) {
+    $list[$language->language] = $language->name;
+  }
+  return $list;
+}
+
+/**
+ * Callback for getting field property values.
+ */
+function entity_metadata_field_property_get($entity, array $options, $name, $entity_type, $info) {
+  $field = field_info_field($name);
+  $columns = array_keys($field['columns']);
+  $langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode, TRUE);
+  $values = array();
+  if (isset($entity->{$name}[$langcode])) {
+    foreach ($entity->{$name}[$langcode] as $delta => $data) {
+      $values[$delta] = $data[$columns[0]];
+      if ($info['type'] == 'boolean' || $info['type'] == 'list<boolean>') {
+        // Ensure that we have a clean boolean data type.
+        $values[$delta] = (boolean) $values[$delta];
+      }
+    }
+  }
+  // For an empty single-valued field, we have to return NULL.
+  return $field['cardinality'] == 1 ? ($values ? reset($values) : NULL) : $values;
+}
+
+/**
+ * Callback for setting field property values.
+ */
+function entity_metadata_field_property_set($entity, $name, $value, $langcode, $entity_type, $info) {
+  $field = field_info_field($name);
+  $columns = array_keys($field['columns']);
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode);
+  $values = $field['cardinality'] == 1 ? array($value) : (array) $value;
+
+  $items = array();
+  foreach ($values as $delta => $value) {
+    if (isset($value)) {
+      $items[$delta][$columns[0]] = $value;
+      if ($info['type'] == 'boolean' || $info['type'] == 'list<boolean>') {
+        // Convert boolean values back to an integer for writing.
+        $items[$delta][$columns[0]] = (integer) $items[$delta][$columns[0]] = $value;
+      }
+    }
+  }
+  $entity->{$name}[$langcode] = $items;
+  // Empty the static field language cache, so the field system picks up any
+  // possible new languages.
+  drupal_static_reset('field_language');
+}
+
+/**
+ * Callback returning the options list of a field.
+ */
+function entity_metadata_field_options_list($name, $info) {
+  $field_property_info = $info;
+  if (is_numeric($name) && isset($info['parent'])) {
+    // The options list is to be returned for a single item of a multiple field.
+    $field_property_info = $info['parent']->info();
+    $name = $field_property_info['name'];
+  }
+  if (($field = field_info_field($name)) && isset($field_property_info['parent'])) {
+    // Retrieve the wrapped entity holding the field.
+    $wrapper = $field_property_info['parent'];
+    try {
+      $entity = $wrapper->value();
+    }
+    catch (EntityMetadataWrapperException $e) {
+      // No data available.
+      $entity = NULL;
+    }
+    $instance = $wrapper->getBundle() ? field_info_instance($wrapper->type(), $name, $wrapper->getBundle()) : NULL;
+    return (array) module_invoke($field['module'], 'options_list', $field, $instance, $wrapper->type(), $entity);
+  }
+}
+
+/**
+ * Callback to verbatim get the data structure of a field. Useful for fields
+ * that add metadata for their own data structure.
+ */
+function entity_metadata_field_verbatim_get($entity, array $options, $name, $entity_type, &$context) {
+  // Set contextual info useful for getters of any child properties.
+  $context['instance'] = field_info_instance($context['parent']->type(), $name, $context['parent']->getBundle());
+  $context['field'] = field_info_field($name);
+  $langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $context['field'], $langcode, TRUE);
+
+  if ($context['field']['cardinality'] == 1) {
+    return isset($entity->{$name}[$langcode][0]) ? $entity->{$name}[$langcode][0] : NULL;
+  }
+  return isset($entity->{$name}[$langcode]) ? $entity->{$name}[$langcode] : array();
+}
+
+/**
+ * Writes the passed field items in the object. Useful as field level setter
+ * to set the whole data structure at once.
+ */
+function entity_metadata_field_verbatim_set($entity, $name, $items, $langcode, $entity_type) {
+  $field = field_info_field($name);
+  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode);
+  $value = $field['cardinality'] == 1 ? array($items) : (array) $items;
+  // Filter out any items set to NULL.
+  $entity->{$name}[$langcode] = array_filter($value);
+
+  // Empty the static field language cache, so the field system picks up any
+  // possible new languages.
+  drupal_static_reset('field_language');
+}
+
+/**
+ * Helper for determining the field language to be used.
+ *
+ * Note that we cannot use field_language() as we are not about to display
+ * values, but generally read/write values.
+ *
+ * @param $fallback
+ *   (optional) Whether to fall back to the entity default language, if no
+ *   value is available for the given language code yet.
+ *
+ * @return
+ *   The language code to use.
+ */
+function entity_metadata_field_get_language($entity_type, $entity, $field, $langcode = LANGUAGE_NONE, $fallback = FALSE) {
+  // Try to figure out the default language used by the entity.
+  // With Drupal >= 7.15 we can use entity_language().
+  if (function_exists('entity_language')) {
+    $default_langcode = entity_language($entity_type, $entity);
+  }
+  else {
+    $default_langcode = !empty($entity->language) ? $entity->language : LANGUAGE_NONE;
+  }
+
+  // Determine the right language to use.
+  if ($default_langcode != LANGUAGE_NONE && field_is_translatable($entity_type, $field)) {
+    $langcode = ($langcode != LANGUAGE_NONE) ? field_valid_language($langcode, $default_langcode) : $default_langcode;
+    if (!isset($entity->{$field['field_name']}[$langcode]) && $fallback) {
+      $langcode = $default_langcode;
+    }
+    return $langcode;
+  }
+  else {
+    return LANGUAGE_NONE;
+  }
+}
+
+/**
+ * Callback for getting the sanitized text of 'text_formatted' properties.
+ * This callback is used for both the 'value' and the 'summary'.
+ */
+function entity_metadata_field_text_get($item, array $options, $name, $type, $context) {
+  // $name is either 'value' or 'summary'.
+  if (!isset($item['safe_' . $name])) {
+    // Apply input formats.
+    $langcode = isset($options['language']) ? $options['language']->language : '';
+    $format = isset($item['format']) ? $item['format'] : filter_default_format();
+    $item['safe_' . $name] = check_markup($item[$name], $format, $langcode);
+    // To speed up subsequent calls, update $item with the 'safe_value'.
+    $context['parent']->set($item);
+  }
+  return $item['safe_' . $name];
+}
+
+/**
+ * Defines the list of all available text formats.
+ */
+function entity_metadata_field_text_formats() {
+  foreach (filter_formats() as $key => $format) {
+    $formats[$key] = $format->name;
+  }
+  return $formats;
+}
+
+/**
+ * Callback for getting the file entity of file fields.
+ */
+function entity_metadata_field_file_get($item) {
+  return $item['fid'];
+}
+
+/**
+ * Callback for setting the file entity of file fields.
+ */
+function entity_metadata_field_file_set(&$item, $property_name, $value) {
+  $item['fid'] = $value;
+}
+
+/**
+ * Callback for auto-creating file field $items.
+ */
+function entity_metadata_field_file_create_item($property_name, $context) {
+  // 'fid' is required, so 'file' has to be set as initial property.
+  return array('display' => isset($context['field']['settings']['display_default']) ? $context['field']['settings']['display_default'] : 0);
+}
+
+/**
+ * Callback for validating file field $items.
+ */
+function entity_metadata_field_file_validate_item($items, $context) {
+  // Allow NULL values.
+  if (!isset($items)) {
+    return TRUE;
+  }
+
+  // Stream-line $items for multiple vs non-multiple fields.
+  $items = !entity_property_list_extract_type($context['type']) ? array($items) : (array) $items;
+
+  foreach ($items as $item) {
+    // File-field items require a valid file.
+    if (!isset($item['fid']) || !file_load($item['fid'])) {
+      return FALSE;
+    }
+    if (isset($context['property info']['display']) && !isset($item['display'])) {
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * Access callback for the node entity.
+ *
+ * This function does not implement hook_node_access(), thus it may not be
+ * called entity_metadata_node_access().
+ */
+function entity_metadata_no_hook_node_access($op, $node = NULL, $account = NULL) {
+  if (isset($node)) {
+    // If a non-default revision is given, incorporate revision access.
+    $default_revision = node_load($node->nid);
+    if ($node->vid != $default_revision->vid) {
+      return _node_revision_access($node, $op);
+    }
+    else {
+      return node_access($op, $node, $account);
+    }
+  }
+  // Is access to all nodes allowed?
+  if (!user_access('access content', $account)) {
+    return FALSE;
+  }
+  if (user_access('bypass node access', $account) || (!isset($account) && $op == 'view' && node_access_view_all_nodes())) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the user entity.
+ */
+function entity_metadata_user_access($op, $entity = NULL, $account = NULL, $entity_type) {
+  $account = isset($account) ? $account : $GLOBALS['user'];
+  // Grant access to the users own user account and to the anonymous one.
+  if (isset($entity) && $op != 'delete' && (($entity->uid == $account->uid && $entity->uid) || (!$entity->uid && $op == 'view'))) {
+    return TRUE;
+  }
+  if (user_access('administer users', $account) || user_access('access user profiles', $account) && $op == 'view' && $entity->status) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for restricted user properties.
+ */
+function entity_metadata_user_properties_access($op, $property, $entity = NULL, $account = NULL) {
+  if (user_access('administer users', $account)) {
+    return TRUE;
+  }
+  $account = isset($account) ? $account : $GLOBALS['user'];
+  // Flag to indicate if this user entity is the own user account.
+  $is_own_account = isset($entity) && $account->uid == $entity->uid;
+  switch ($property) {
+    case 'name':
+      // Allow view access to anyone with access to the entity.
+      if ($op == 'view') {
+        return TRUE;
+      }
+      // Allow edit access for own user name if the permission is satisfied.
+      return $is_own_account && user_access('change own username', $account);
+    case 'mail':
+      // Allow access to own mail address.
+      return $is_own_account;
+    case 'roles':
+      // Allow view access for own roles.
+      return ($op == 'view' && $is_own_account);
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the comment entity.
+ */
+function entity_metadata_comment_access($op, $entity = NULL, $account = NULL) {
+  // When determining access to a comment, 'comment_access' does not take any
+  // access restrictions to the comment's associated node into account. If a
+  // comment has an associated node, the user must be able to view it in order
+  // to access the comment.
+  if (isset($entity->nid)) {
+    if (!entity_access('view', 'node', node_load($entity->nid), $account)) {
+      return FALSE;
+    }
+  }
+  if (isset($entity) && $op == 'update') {
+    // Because 'comment_access' only checks the current user, we need to do our
+    // own access checking if an account was specified.
+    if (!isset($account)) {
+      return comment_access('edit', $entity);
+    }
+    else {
+      return ($account->uid && $account->uid == $entity->uid && $entity->status == COMMENT_PUBLISHED && user_access('edit own comments', $account)) || user_access('administer comments', $account);
+    }
+  }
+  if (user_access('administer comments', $account) || user_access('access comments', $account) && $op == 'view') {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for the taxonomy entities.
+ */
+function entity_metadata_taxonomy_access($op, $entity = NULL, $account = NULL, $entity_type) {
+  if ($entity_type == 'taxonomy_vocabulary') {
+    return user_access('administer taxonomy', $account);
+  }
+  if (isset($entity) && $op == 'update' && !isset($account) && taxonomy_term_edit_access($entity)) {
+    return TRUE;
+  }
+  if (user_access('administer taxonomy', $account) || user_access('access content', $account) && $op == 'view') {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Access callback for file entities.
+ */
+function entity_metadata_file_access($op, $file = NULL, $account = NULL, $entity_type) {
+  // We can only check access for the current user, so return FALSE on other accounts.
+  global $user;
+  if ($op == 'view' && isset($file) && (!isset($account) || $user->uid == $account->uid)) {
+    // Invoke hook_file_download() to obtain access information.
+    foreach (module_implements('file_download') as $module) {
+      $result = module_invoke($module, 'file_download', $file->uri);
+      if ($result == -1) {
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+
+
+/**
+ * Callback to determine access for properties which are fields.
+ */
+function entity_metadata_field_access_callback($op, $name, $entity = NULL, $account = NULL, $entity_type) {
+  $field = field_info_field($name);
+  return field_access($op, $field, $entity_type, $entity, $account);
+}
+
+/**
+ * Callback to create entity objects.
+ */
+function entity_metadata_create_object($values = array(), $entity_type) {
+  $info = entity_get_info($entity_type);
+  // Make sure at least the bundle and label properties are set.
+  if (isset($info['entity keys']['bundle']) && $key = $info['entity keys']['bundle']) {
+    $values += array($key => NULL);
+  }
+  if (isset($info['entity keys']['label']) && $key = $info['entity keys']['label']) {
+    $values += array($key => NULL);
+  }
+  $entity = (object) $values;
+  $entity->is_new = TRUE;
+  return $entity;
+}
+
+/**
+ * Callback to create a new comment.
+ */
+function entity_metadata_create_comment($values = array()) {
+  $comment = (object) ($values + array(
+    'status' => COMMENT_PUBLISHED,
+    'pid' => 0,
+    'subject' => '',
+    'uid' => 0,
+    'language' => LANGUAGE_NONE,
+    'node_type' => NULL,
+    'is_new' => TRUE,
+  ));
+  $comment->cid = FALSE;
+  return $comment;
+}
+
+/**
+ * Callback to create a new node.
+ */
+function entity_metadata_create_node($values = array()) {
+  $node = (object) array(
+    'type' => $values['type'],
+    'language' => LANGUAGE_NONE,
+    'is_new' => TRUE,
+  );
+  // Set some defaults.
+  $node_options = variable_get('node_options_' . $node->type, array('status', 'promote'));
+  foreach (array('status', 'promote', 'sticky') as $key) {
+    $node->$key = (int) in_array($key, $node_options);
+  }
+  if (module_exists('comment') && !isset($node->comment)) {
+    $node->comment = variable_get("comment_$node->type", COMMENT_NODE_OPEN);
+  }
+  // Apply the given values.
+  foreach ($values as $key => $value) {
+    $node->$key = $value;
+  }
+  return $node;
+}
+
+/**
+ * Callback to save a user account.
+ */
+function entity_metadata_user_save($account) {
+  $edit = (array) $account;
+  // Don't save the hashed password as password.
+  unset($edit['pass']);
+  user_save($account, $edit);
+}
+
+/**
+ * Callback to delete a file.
+ * Watch out to not accidentilly implement hook_file_delete().
+ */
+function entity_metadata_delete_file($fid) {
+  file_delete(file_load($fid), TRUE);
+}
+
+/**
+ * Callback to view nodes.
+ */
+function entity_metadata_view_node($entities, $view_mode = 'full', $langcode = NULL) {
+  $result = node_view_multiple($entities, $view_mode, 0, $langcode);
+  // Make sure to key the result with 'node' instead of 'nodes'.
+  return array('node' => reset($result));
+}
+
+/**
+ * Callback to view comments.
+ */
+function entity_metadata_view_comment($entities, $view_mode = 'full', $langcode = NULL) {
+  $build = array();
+  $nodes = array();
+  // The comments, indexed by nid and then by cid.
+  $nid_comments = array();
+  foreach ($entities as $cid => $comment) {
+    $nid = $comment->nid;
+    $nodes[$nid] = $nid;
+    $nid_comments[$nid][$cid] = $comment;
+  }
+  $nodes = node_load_multiple(array_keys($nodes));
+  foreach ($nid_comments as $nid => $comments) {
+    $node = isset($nodes[$nid]) ? $nodes[$nid] : NULL;
+    $build += comment_view_multiple($comments, $node, $view_mode, 0, $langcode);
+  }
+  return array('comment' => $build);
+}
+
+/**
+ * Callback to view an entity, for which just ENTITYTYPE_view() is available.
+ */
+function entity_metadata_view_single($entities, $view_mode = 'full', $langcode = NULL, $entity_type) {
+  $function = $entity_type . '_view';
+  $build = array();
+  foreach ($entities as $key => $entity) {
+    $build[$entity_type][$key] = $function($entity, $view_mode, $langcode);
+  }
+  return $build;
+}
+
+/**
+ * Callback to get the form of a node.
+ */
+function entity_metadata_form_node($node) {
+  // Pre-populate the form-state with the right form include.
+  $form_state['build_info']['args'] = array($node);
+  form_load_include($form_state, 'inc', 'node', 'node.pages');
+  return drupal_build_form($node->type . '_node_form', $form_state);
+}
+
+/**
+ * Callback to get the form of a comment.
+ */
+function entity_metadata_form_comment($comment) {
+  if (!isset($comment->node_type)) {
+    $node = node_load($comment->nid);
+    $comment->node_type = 'comment_node_' . $node->type;
+  }
+  return drupal_get_form($comment->node_type . '_form', $comment);
+}
+
+/**
+ * Callback to get the form of a user account.
+ */
+function entity_metadata_form_user($account) {
+  // Pre-populate the form-state with the right form include.
+  $form_state['build_info']['args'] = array($account);
+  form_load_include($form_state, 'inc', 'user', 'user.pages');
+  return drupal_build_form('user_profile_form', $form_state);
+}
+
+/**
+ * Callback to get the form of a term.
+ */
+function entity_metadata_form_taxonomy_term($term) {
+  // Pre-populate the form-state with the right form include.
+  $form_state['build_info']['args'] = array($term);
+  form_load_include($form_state, 'inc', 'taxonomy', 'taxonomy.admin');
+  return drupal_build_form('taxonomy_form_term', $form_state);
+}
+
+/**
+ * Callback to get the form of a vocabulary.
+ */
+function entity_metadata_form_taxonomy_vocabulary($term) {
+  // Pre-populate the form-state with the right form include.
+  $form_state['build_info']['args'] = array($term);
+  form_load_include($form_state, 'inc', 'taxonomy', 'taxonomy.admin');
+  return drupal_build_form('taxonomy_form_term', $form_state);
+}
+
+/**
+ * Callback to get the form for entities using the entity API admin ui.
+ */
+function entity_metadata_form_entity_ui($entity, $entity_type) {
+  $info = entity_get_info($entity_type);
+  $form_state = form_state_defaults();
+  // Add in the include file as the form API does else with the include file
+  // specified for the active menu item.
+  if (!empty($info['admin ui']['file'])) {
+    $path = isset($info['admin ui']['file path']) ? $info['admin ui']['file path'] : drupal_get_path('module', $info['module']);
+    $form_state['build_info']['files']['entity_ui'] = $path . '/' . $info['admin ui']['file'];
+    // Also load the include file.
+    if (file_exists($form_state['build_info']['files']['entity_ui'])) {
+      require_once DRUPAL_ROOT . '/' . $form_state['build_info']['files']['entity_ui'];
+    }
+  }
+  return entity_ui_get_form($entity_type, $entity, $op = 'edit', $form_state);
+}
+
+/**
+ * Callback for querying entity properties having their values stored in the
+ * entities main db table.
+ */
+function entity_metadata_table_query($entity_type, $property, $value, $limit) {
+  $properties = entity_get_all_property_info($entity_type);
+  $info = $properties[$property] + array('schema field' => $property);
+
+  $query = new EntityFieldQuery();
+  $query->entityCondition('entity_type', $entity_type, '=')
+        ->propertyCondition($info['schema field'], $value, is_array($value) ? 'IN' : '=')
+        ->range(0, $limit);
+
+  $result = $query->execute();
+  return !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
+}
+
+/**
+ * Callback for querying entities by field values. This function just queries
+ * for the value of the first specified column. Also it is only suitable for
+ * fields that don't process the data, so it's stored the same way as returned.
+ */
+function entity_metadata_field_query($entity_type, $property, $value, $limit) {
+  $query = new EntityFieldQuery();
+  $field = field_info_field($property);
+  $columns = array_keys($field['columns']);
+
+  $query->entityCondition('entity_type', $entity_type, '=')
+        ->fieldCondition($field, $columns[0], $value, is_array($value) ? 'IN' : '=')
+        ->range(0, $limit);
+
+  $result = $query->execute();
+  return !empty($result[$entity_type]) ? array_keys($result[$entity_type]) : array();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/comment.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * @file
+ * Provides info about the comment entity.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of comment module.
+ *
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_comment_entity_property_info() {
+  $info = array();
+  // Add meta-data about the basic comment properties.
+  $properties = &$info['comment']['properties'];
+
+  $properties['cid'] = array(
+    'label' => t("Comment ID"),
+    'type' => 'integer',
+    'description' => t("The unique ID of the comment."),
+    'schema field' => 'cid',
+  );
+  $properties['hostname'] = array(
+    'label' => t("IP Address"),
+    'description' => t("The IP address of the computer the comment was posted from."),
+    'schema field' => 'hostname',
+  );
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The name left by the comment author."),
+    'getter callback' => 'entity_metadata_comment_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'sanitize' => 'filter_xss',
+    'schema field' => 'name',
+  );
+  $properties['mail'] = array(
+    'label' => t("Email address"),
+    'description' => t("The email address left by the comment author."),
+    'getter callback' => 'entity_metadata_comment_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'validation callback' => 'valid_email_address',
+    'schema field' => 'mail',
+  );
+  $properties['homepage'] = array(
+    'label' => t("Home page"),
+    'description' => t("The home page URL left by the comment author."),
+    'sanitize' => 'filter_xss_bad_protocol',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'schema field' => 'homepage',
+  );
+  $properties['subject'] = array(
+    'label' => t("Subject"),
+    'description' => t("The subject of the comment."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'sanitize' => 'filter_xss',
+    'required' => TRUE,
+    'schema field' => 'subject',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the comment."),
+    'getter callback' => 'entity_metadata_entity_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['edit_url'] = array(
+    'label' => t("Edit URL"),
+    'description' => t("The URL of the comment's edit page."),
+    'getter callback' => 'entity_metadata_comment_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['created'] = array(
+    'label' => t("Date created"),
+    'description' => t("The date the comment was posted."),
+    'type' => 'date',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'schema field' => 'created',
+  );
+  $properties['parent'] = array(
+    'label' => t("Parent"),
+    'description' => t("The comment's parent, if comment threading is active."),
+    'type' => 'comment',
+    'getter callback' => 'entity_metadata_comment_get_properties',
+    'schema field' => 'pid',
+  );
+  $properties['node'] = array(
+    'label' => t("Node"),
+    'description' => t("The node the comment was posted to."),
+    'type' => 'node',
+    'setter callback' => 'entity_metadata_comment_setter',
+    'setter permission' => 'administer comments',
+    'required' => TRUE,
+    'schema field' => 'nid',
+  );
+  $properties['author'] = array(
+    'label' => t("Author"),
+    'description' => t("The author of the comment."),
+    'type' => 'user',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'required' => TRUE,
+    'schema field' => 'uid',
+  );
+  $properties['status'] = array(
+    'label' => t("Status"),
+    'description' => t("Whether the comment is published or unpublished."),
+    'setter callback' => 'entity_property_verbatim_set',
+    // Although the status is expected to be boolean, its schema suggests
+    // it is an integer, so we follow the schema definition.
+    'type' => 'integer',
+    'options list' => 'entity_metadata_status_options_list',
+    'setter permission' => 'administer comments',
+    'schema field' => 'status',
+  );
+  return $info;
+}
+
+/**
+ * Implements hook_entity_property_info_alter() on top of comment module.
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_comment_entity_property_info_alter(&$info) {
+  // Add info about comment module related properties to the node entity.
+  $properties = &$info['node']['properties'];
+  $properties['comment'] = array(
+    'label' => t("Comments allowed"),
+    'description' => t("Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write)."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer comments',
+    'type' => 'integer',
+  );
+  $properties['comment_count'] = array(
+    'label' => t("Comment count"),
+    'description' => t("The number of comments posted on a node."),
+    'getter callback' => 'entity_metadata_comment_get_node_properties',
+    'type' => 'integer',
+  );
+  $properties['comment_count_new'] = array(
+    'label' => t("New comment count"),
+    'description' => t("The number of comments posted on a node since the reader last viewed it."),
+    'getter callback' => 'entity_metadata_comment_get_node_properties',
+    'type' => 'integer',
+  );
+
+  // The comment body field is usually available for all bundles, so add it
+  // directly to the comment entity.
+  $info['comment']['properties']['comment_body'] = array(
+    'type' => 'text_formatted',
+    'label' => t('The main body text'),
+    'getter callback' => 'entity_metadata_field_verbatim_get',
+    'setter callback' => 'entity_metadata_field_verbatim_set',
+    'property info' => entity_property_text_formatted_info(),
+    'field' => TRUE,
+    'required' => TRUE,
+  );
+  unset($info['comment']['properties']['comment_body']['property info']['summary']);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/field.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,170 @@
+<?php
+
+/**
+ * @file
+ * Provides info for fields.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of field module.
+ *
+ * @see entity_field_info_alter()
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_field_entity_property_info() {
+  $info = array();
+  // Loop over all field instances and add them as property.
+  foreach (field_info_fields() as $field_name => $field) {
+    $field += array('bundles' => array());
+    if ($field_type = field_info_field_types($field['type'])) {
+      // Add in our default callback as the first one.
+      $field_type += array('property_callbacks' => array());
+      array_unshift($field_type['property_callbacks'], 'entity_metadata_field_default_property_callback');
+
+      foreach ($field['bundles'] as $entity_type => $bundles) {
+        foreach ($bundles as $bundle) {
+          $instance = field_info_instance($entity_type, $field_name, $bundle);
+
+          if ($instance && empty($instance['deleted'])) {
+            foreach ($field_type['property_callbacks'] as $callback) {
+              $callback($info, $entity_type, $field, $instance, $field_type);
+            }
+          }
+        }
+      }
+    }
+  }
+  return $info;
+}
+
+/**
+ * Callback to add in property info defaults per field instance.
+ * @see entity_metadata_field_entity_property_info().
+ */
+function entity_metadata_field_default_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  if (!empty($field_type['property_type'])) {
+    if ($field['cardinality'] != 1) {
+      $field_type['property_type'] = 'list<' . $field_type['property_type'] . '>';
+    }
+    // Add in instance specific property info, if given and apply defaults.
+    $name = $field['field_name'];
+    $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$name];
+    $instance += array('property info' => array());
+    $property = $instance['property info'] + array(
+      'label' => $instance['label'],
+      'type' => $field_type['property_type'],
+      'description' => t('Field "@name".', array('@name' => $name)),
+      'getter callback' => 'entity_metadata_field_property_get',
+      'setter callback' => 'entity_metadata_field_property_set',
+      'access callback' => 'entity_metadata_field_access_callback',
+      'query callback' => 'entity_metadata_field_query',
+      'translatable' => !empty($field['translatable']),
+      // Specify that this property stems from a field.
+      'field' => TRUE,
+      'required' => !empty($instance['required']),
+    );
+    // For field types of the list module add in the options list callback.
+    if (strpos($field['type'], 'list') === 0) {
+      $property['options list'] = 'entity_metadata_field_options_list';
+    }
+  }
+}
+
+/**
+ * Additional callback to adapt the property info for text fields. If a text
+ * field is processed we make use of a separate data structure so that format
+ * filters are available too. For the text value the sanitized, thus processed
+ * value is returned by default.
+ *
+ * @see entity_metadata_field_entity_property_info()
+ * @see entity_field_info_alter()
+ * @see entity_property_text_formatted_info()
+ */
+function entity_metadata_field_text_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  if (!empty($instance['settings']['text_processing']) || $field['type'] == 'text_with_summary') {
+    // Define a data structure for dealing with text that is formatted or has
+    // a summary.
+    $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+
+    $property['getter callback'] = 'entity_metadata_field_verbatim_get';
+    $property['setter callback'] = 'entity_metadata_field_verbatim_set';
+    unset($property['query callback']);
+
+    if (empty($instance['settings']['text_processing'])) {
+      $property['property info'] =  entity_property_field_item_textsummary_info();
+    }
+    else {
+      // For formatted text we use the type name 'text_formatted'.
+      $property['type'] = ($field['cardinality'] != 1) ? 'list<text_formatted>' : 'text_formatted';
+      $property['property info'] = entity_property_text_formatted_info();
+    }
+    // Enable auto-creation of the item, so that it is possible to just set
+    // the textual or summary value.
+    $property['auto creation'] = 'entity_property_create_array';
+
+    if ($field['type'] != 'text_with_summary') {
+      unset($property['property info']['summary']);
+    }
+  }
+}
+
+/**
+ * Additional callback to adapt the property info for term reference fields.
+ * @see entity_metadata_field_entity_property_info().
+ */
+function entity_metadata_field_term_reference_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  if (count($field['settings']['allowed_values']) == 1) {
+    $settings = reset($field['settings']['allowed_values']);
+    $property['bundle'] = $settings['vocabulary'];
+  }
+  // Only add the options list callback for controlled vocabularies, thus
+  // vocabularies not using the autocomplete widget.
+  if ($instance['widget']['type'] != 'taxonomy_autocomplete') {
+    $property['options list'] = 'entity_metadata_field_options_list';
+  }
+}
+
+/**
+ * Additional callback to adapt the property info for file fields.
+ * @see entity_metadata_field_entity_property_info().
+ */
+function entity_metadata_field_file_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  // Define a data structure so it's possible to deal with files and their
+  // descriptions.
+  $property['getter callback'] = 'entity_metadata_field_verbatim_get';
+  $property['setter callback'] = 'entity_metadata_field_verbatim_set';
+
+  // Auto-create the field $items as soon as a property is set.
+  $property['auto creation'] = 'entity_metadata_field_file_create_item';
+  $property['validation callback'] = 'entity_metadata_field_file_validate_item';
+
+  $property['property info'] = entity_property_field_item_file_info();
+
+  if (empty($instance['settings']['description_field'])) {
+    unset($property['property info']['description']);
+  }
+  if (empty($field['settings']['display_field'])) {
+    unset($property['property info']['display']);
+  }
+  unset($property['query callback']);
+}
+
+/**
+ * Additional callback to adapt the property info for image fields.
+ * This callback gets invoked after entity_metadata_field_file_callback().
+ * @see entity_metadata_field_entity_property_info().
+ */
+function entity_metadata_field_image_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  // Update the property info with the info for image fields.
+  $property['property info'] = entity_property_field_item_image_info();
+
+  if (empty($instance['settings']['alt_field'])) {
+    unset($property['property info']['alt']);
+  }
+  if (empty($field['settings']['title_field'])) {
+    unset($property['property info']['title']);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/locale.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Provides locale-related properties.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() on top of locale module.
+ *
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_locale_entity_property_info_alter(&$info) {
+
+  $info['user']['properties']['language'] = array(
+    'label' => t("Language"),
+    'description' => t("This account's default language for e-mails, and preferred language for site presentation."),
+    'type' => 'token',
+    'getter callback' => 'entity_metadata_locale_get_user_language',
+    'setter callback' => 'entity_property_verbatim_set',
+    'options list' => 'entity_metadata_language_list',
+    'schema field' => 'language',
+    'setter permission' => 'administer users',
+  );
+
+  $info['site']['properties']['current_page']['property info']['language'] = array(
+    'label' => t("Interface language"),
+    'description' => t("The language code of the current user interface language."),
+    'type' => 'token',
+    'getter callback' => 'entity_metadata_locale_get_languages',
+    'options list' => 'entity_metadata_language_list',
+  );
+  $info['site']['properties']['current_page']['property info']['language_content'] = array(
+    'label' => t("Content language"),
+    'description' => t("The language code of the current content language."),
+    'type' => 'token',
+    'getter callback' => 'entity_metadata_locale_get_languages',
+    'options list' => 'entity_metadata_language_list',
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/node.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * @file
+ * Provides info about the node entity.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of node module.
+ *
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_node_entity_property_info() {
+  $info = array();
+  // Add meta-data about the basic node properties.
+  $properties = &$info['node']['properties'];
+
+  $properties['nid'] = array(
+    'label' => t("Node ID"),
+    'type' => 'integer',
+    'description' => t("The unique ID of the node."),
+    'schema field' => 'nid',
+  );
+  $properties['vid'] = array(
+    'label' => t("Revision ID"),
+    'type' => 'integer',
+    'description' => t("The unique ID of the node's revision."),
+    'schema field' => 'vid',
+  );
+  $properties['is_new'] = array(
+    'label' => t("Is new"),
+    'type' => 'boolean',
+    'description' => t("Whether the node is new and not saved to the database yet."),
+    'getter callback' => 'entity_metadata_node_get_properties',
+  );
+  $properties['type'] = array(
+    'label' => t("Content type"),
+    'type' => 'token',
+    'description' => t("The type of the node."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'options list' => 'node_type_get_names',
+    'required' => TRUE,
+    'schema field' => 'type',
+  );
+  $properties['title'] = array(
+    'label' => t("Title"),
+    'description' => t("The title of the node."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'schema field' => 'title',
+    'required' => TRUE,
+  );
+  $properties['language'] = array(
+    'label' => t("Language"),
+    'type' => 'token',
+    'description' => t("The language the node is written in."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'options list' => 'entity_metadata_language_list',
+    'schema field' => 'language',
+    'setter permission' => 'administer nodes',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the node."),
+    'getter callback' => 'entity_metadata_entity_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['edit_url'] = array(
+    'label' => t("Edit URL"),
+    'description' => t("The URL of the node's edit page."),
+    'getter callback' => 'entity_metadata_node_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['status'] = array(
+    'label' => t("Status"),
+    'description' => t("Whether the node is published or unpublished."),
+    // Although the status is expected to be boolean, its schema suggests
+    // it is an integer, so we follow the schema definition.
+    'type' => 'integer',
+    'options list' => 'entity_metadata_status_options_list',
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'schema field' => 'status',
+  );
+  $properties['promote'] = array(
+    'label' => t("Promoted to frontpage"),
+    'description' => t("Whether the node is promoted to the frontpage."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'schema field' => 'promote',
+    'type' => 'boolean',
+  );
+  $properties['sticky'] = array(
+    'label' => t("Sticky in lists"),
+    'description' => t("Whether the node is displayed at the top of lists in which it appears."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'schema field' => 'sticky',
+    'type' => 'boolean',
+  );
+  $properties['created'] = array(
+    'label' => t("Date created"),
+    'type' => 'date',
+    'description' => t("The date the node was posted."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'schema field' => 'created',
+  );
+  $properties['changed'] = array(
+    'label' => t("Date changed"),
+    'type' => 'date',
+    'schema field' => 'changed',
+    'description' => t("The date the node was most recently updated."),
+  );
+  $properties['author'] = array(
+    'label' => t("Author"),
+    'type' => 'user',
+    'description' => t("The author of the node."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'setter permission' => 'administer nodes',
+    'required' => TRUE,
+    'schema field' => 'uid',
+  );
+  $properties['source'] = array(
+    'label' => t("Translation source node"),
+    'type' => 'node',
+    'description' => t("The original-language version of this node, if one exists."),
+    'getter callback' => 'entity_metadata_node_get_properties',
+  );
+  $properties['log'] = array(
+    'label' => t("Revision log message"),
+    'type' => 'text',
+    'description' => t("In case a new revision is to be saved, the log entry explaining the changes for this version."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'access callback' => 'entity_metadata_node_revision_access',
+  );
+  $properties['revision'] = array(
+    'label' => t("Creates revision"),
+    'type' => 'boolean',
+    'description' => t("Whether saving this node creates a new revision."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'access callback' => 'entity_metadata_node_revision_access',
+  );
+  return $info;
+}
+
+/**
+ * Implements hook_entity_property_info_alter() on top of node module.
+ * @see entity_metadata_entity_property_info_alter()
+ */
+function entity_metadata_node_entity_property_info_alter(&$info) {
+  // Move the body property to the node by default, as its usually there this
+  // makes dealing with it more convenient.
+  $info['node']['properties']['body'] = array(
+    'type' => 'text_formatted',
+    'label' => t('The main body text'),
+    'getter callback' => 'entity_metadata_field_verbatim_get',
+    'setter callback' => 'entity_metadata_field_verbatim_set',
+    'property info' => entity_property_text_formatted_info(),
+    'auto creation' => 'entity_property_create_array',
+    'field' => TRUE,
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/poll.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Provides info about poll nodes.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() on top of poll module.
+ *
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_poll_entity_property_info_alter(&$info) {
+  $properties = &$info['node']['bundles']['poll']['properties'];
+
+  $properties['poll_votes'] = array(
+    'label' => t("Poll votes"),
+    'description' => t("The number of votes that have been cast on a poll node."),
+    'type' => 'integer',
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['poll_winner'] = array(
+    'label' => t("Poll winner"),
+    'description' => t("The winning poll answer."),
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'sanitize' => 'filter_xss',
+    'computed' => TRUE,
+  );
+  $properties['poll_winner_votes'] = array(
+    'label' => t("Poll winner votes"),
+    'description' => t("The number of votes received by the winning poll answer."),
+    'type' => 'integer',
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['poll_winner_percent'] = array(
+    'label' => t("Poll winner percent"),
+    'description' => t("The percentage of votes received by the winning poll answer."),
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'type' => 'decimal',
+    'computed' => TRUE,
+  );
+  $properties['poll_duration'] = array(
+    'label' => t("Poll duration"),
+    'description' => t("The length of time the poll node is set to run."),
+    'getter callback' => 'entity_metadata_poll_node_get_properties',
+    'type' => 'duration',
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/statistics.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Provides info about statistics.
+ */
+
+/**
+ * Implements hook_entity_property_info_alter() on top of statistics module.
+ *
+ * @see entity_entity_property_info_alter()
+ */
+function entity_metadata_statistics_entity_property_info_alter(&$info) {
+  $properties = &$info['node']['properties'];
+
+  $properties['views'] = array(
+    'label' => t("Number of views"),
+    'description' => t("The number of visitors who have read the node."),
+    'type' => 'integer',
+    'getter callback' => 'entity_metadata_statistics_node_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['day_views'] = array(
+    'label' => t("Views today"),
+    'description' => t("The number of visitors who have read the node today."),
+    'type' => 'integer',
+    'getter callback' => 'entity_metadata_statistics_node_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['last_view'] = array(
+    'label' => t("Last view"),
+    'description' => t("The date on which a visitor last read the node."),
+    'type' => 'date',
+    'getter callback' => 'entity_metadata_statistics_node_get_properties',
+    'computed' => TRUE,
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/system.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * @file
+ * Provides info about system-wide entities.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of system module.
+ *
+ * @see entity_entity_property_info()
+ * @see entity_metadata_site_wrapper()
+ */
+function entity_metadata_system_entity_property_info() {
+  $info = array();
+
+  // There is no site entity, but still add metadata for global site properties
+  // here. That way modules can alter and add further properties at this place.
+  // In order to make use of this metadata modules may use the wrapper returned
+  // by entity_metadata_site_wrapper().
+  $properties = &$info['site']['properties'];
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The name of the site."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'sanitize' => 'check_plain',
+  );
+  $properties['slogan'] = array(
+    'label' => t("Slogan"),
+    'description' => t("The slogan of the site."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'sanitize' => 'check_plain',
+  );
+  $properties['mail'] = array(
+    'label' => t("Email"),
+    'description' => t("The administrative email address for the site."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the site's front page."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'uri',
+  );
+  $properties['login_url'] = array(
+    'label' => t("Login page"),
+    'description' => t("The URL of the site's login page."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'uri',
+  );
+  $properties['current_user'] = array(
+    'label' => t("Logged in user"),
+    'description' => t("The currently logged in user."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'user',
+  );
+  $properties['current_date'] = array(
+    'label' => t("Current date"),
+    'description' => t("The current date and time."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'date',
+  );
+  $properties['current_page'] = array(
+    'label' => t("Current page"),
+    'description' => t("Information related to the current page request."),
+    'getter callback' => 'entity_metadata_system_get_properties',
+    'type' => 'struct',
+    'property info' => array(
+      'path' => array(
+        'label' => t("Path"),
+        'description' => t("The internal Drupal path of the current page request."),
+        'getter callback' => 'current_path',
+        'type' => 'text',
+      ),
+      'url' => array(
+        'label' => t("URL"),
+        'description' => t("The full URL of the current page request."),
+        'getter callback' => 'entity_metadata_system_get_page_properties',
+        'type' => 'uri',
+      ),
+    ),
+  );
+
+  // Files.
+  $properties = &$info['file']['properties'];
+  $properties['fid'] = array(
+    'label' => t("File ID"),
+    'description' => t("The unique ID of the uploaded file."),
+    'type' => 'integer',
+    'validation callback' => 'entity_metadata_validate_integer_positive',
+    'schema field' => 'fid',
+  );
+  $properties['name'] = array(
+    'label' => t("File name"),
+    'description' => t("The name of the file on disk."),
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+    'schema field' => 'filename',
+  );
+  $properties['mime'] = array(
+    'label' => t("MIME type"),
+    'description' => t("The MIME type of the file."),
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+    'sanitize' => 'filter_xss',
+    'schema field' => 'filemime',
+  );
+  $properties['size'] = array(
+    'label' => t("File size"),
+    'description' => t("The size of the file, in kilobytes."),
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+    'type' => 'integer',
+    'schema field' => 'filesize',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The web-accessible URL for the file."),
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+  );
+  $properties['timestamp'] = array(
+    'label' => t("Timestamp"),
+    'description' => t("The date the file was most recently changed."),
+    'type' => 'date',
+    'schema field' => 'timestamp',
+  );
+  $properties['owner'] = array(
+    'label' => t("Owner"),
+    'description' => t("The user who originally uploaded the file."),
+    'type' => 'user',
+    'getter callback' => 'entity_metadata_system_get_file_properties',
+    'schema field' => 'uid',
+  );
+  return $info;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/taxonomy.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @file
+ * Provides info about the taxonomy entity.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of taxonomy module.
+ *
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_taxonomy_entity_property_info() {
+  $info = array();
+  // Add meta-data about the basic taxonomy properties.
+  $properties = &$info['taxonomy_term']['properties'];
+
+  $properties['tid'] = array(
+    'label' => t("Term ID"),
+    'description' => t("The unique ID of the taxonomy term."),
+    'type' => 'integer',
+    'schema field' => 'tid',
+  );
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The name of the taxonomy term."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'required' => TRUE,
+    'schema field' => 'name',
+  );
+  $properties['description'] = array(
+    'label' => t("Description"),
+    'description' => t("The optional description of the taxonomy term."),
+    'sanitized' => TRUE,
+    'raw getter callback' => 'entity_property_verbatim_get',
+    'getter callback' => 'entity_metadata_taxonomy_term_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'schema field' => 'description',
+  );
+  $properties['weight'] = array(
+    'label' => t("Weight"),
+    'type' => 'integer',
+    'description' => t('The weight of the term, which is used for ordering terms during display.'),
+    'setter callback' => 'entity_property_verbatim_set',
+    'schema field' => 'weight',
+  );
+  $properties['node_count'] = array(
+    'label' => t("Node count"),
+    'type' => 'integer',
+    'description' => t("The number of nodes tagged with the taxonomy term."),
+    'getter callback' => 'entity_metadata_taxonomy_term_get_properties',
+    'computed' => TRUE,
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the taxonomy term."),
+    'getter callback' => 'entity_metadata_entity_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['vocabulary'] = array(
+    'label' => t("Vocabulary"),
+    'description' => t("The vocabulary the taxonomy term belongs to."),
+    'setter callback' => 'entity_metadata_taxonomy_term_setter',
+    'type' => 'taxonomy_vocabulary',
+    'required' => TRUE,
+    'schema field' => 'vid',
+  );
+  $properties['parent'] = array(
+    'label' => t("Parent terms"),
+    'description' => t("The parent terms of the taxonomy term."),
+    'getter callback' => 'entity_metadata_taxonomy_term_get_properties',
+    'setter callback' => 'entity_metadata_taxonomy_term_setter',
+    'type' => 'list<taxonomy_term>',
+  );
+  $properties['parents_all'] = array(
+    'label' => t("All parent terms"),
+    'description' => t("Ancestors of the term, i.e. parent of all above hierarchy levels."),
+    'getter callback' => 'entity_metadata_taxonomy_term_get_properties',
+    'type' => 'list<taxonomy_term>',
+    'computed' => TRUE,
+  );
+
+  // Add meta-data about the basic vocabulary properties.
+  $properties = &$info['taxonomy_vocabulary']['properties'];
+
+  // Taxonomy vocabulary related variables.
+  $properties['vid'] = array(
+    'label' => t("Vocabulary ID"),
+    'description' => t("The unique ID of the taxonomy vocabulary."),
+    'type' => 'integer',
+    'schema field' => 'vid',
+  );
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The name of the taxonomy vocabulary."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'required' => TRUE,
+    'schema field' => 'name',
+  );
+  $properties['machine_name'] = array(
+    'label' => t("Machine name"),
+    'type' => 'token',
+    'description' => t("The machine name of the taxonomy vocabulary."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'required' => TRUE,
+    'schema field' => 'machine_name',
+  );
+  $properties['description'] = array(
+    'label' => t("Description"),
+    'description' => t("The optional description of the taxonomy vocabulary."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'sanitize' => 'filter_xss',
+    'schema field' => 'description',
+  );
+  $properties['term_count'] = array(
+    'label' => t("Term count"),
+    'type' => 'integer',
+    'description' => t("The number of terms belonging to the taxonomy vocabulary."),
+    'getter callback' => 'entity_metadata_taxonomy_vocabulary_get_properties',
+    'computed' => TRUE,
+  );
+  return $info;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/modules/user.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ * Provides info about the user entity.
+ */
+
+/**
+ * Implements hook_entity_property_info() on top of user module.
+ *
+ * @see entity_entity_property_info()
+ */
+function entity_metadata_user_entity_property_info() {
+  $info = array();
+  // Add meta-data about the user properties.
+  $properties = &$info['user']['properties'];
+
+  $properties['uid'] = array(
+    'label' => t("User ID"),
+    'type' => 'integer',
+    'description' => t("The unique ID of the user account."),
+    'schema field' => 'uid',
+  );
+  $properties['name'] = array(
+    'label' => t("Name"),
+    'description' => t("The login name of the user account."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'sanitize' => 'filter_xss',
+    'required' => TRUE,
+    'access callback' => 'entity_metadata_user_properties_access',
+    'schema field' => 'name',
+  );
+  $properties['mail'] = array(
+    'label' => t("Email"),
+    'description' => t("The email address of the user account."),
+    'setter callback' => 'entity_property_verbatim_set',
+    'validation callback' => 'valid_email_address',
+    'required' => TRUE,
+    'access callback' => 'entity_metadata_user_properties_access',
+    'schema field' => 'mail',
+  );
+  $properties['url'] = array(
+    'label' => t("URL"),
+    'description' => t("The URL of the account profile page."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['edit_url'] = array(
+    'label' => t("Edit URL"),
+    'description' => t("The url of the account edit page."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'type' => 'uri',
+    'computed' => TRUE,
+  );
+  $properties['last_access'] = array(
+    'label' => t("Last access"),
+    'description' => t("The date the user last accessed the site."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'type' => 'date',
+    'schema field' => 'access',
+  );
+  $properties['last_login'] = array(
+    'label' => t("Last login"),
+    'description' => t("The date the user last logged in to the site."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'type' => 'date',
+    'schema field' => 'login',
+  );
+  $properties['created'] = array(
+    'label' => t("Created"),
+    'description' => t("The date the user account was created."),
+    'type' => 'date',
+    'schema field' => 'created',
+  );
+  $properties['roles'] = array(
+    'label' => t("User roles"),
+    'description' => t("The roles of the user."),
+    'type' => 'list<integer>',
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'setter callback' => 'entity_metadata_user_set_properties',
+    'setter permission' => 'administer users',
+    'options list' => 'entity_metadata_user_roles',
+    'access callback' => 'entity_metadata_user_properties_access',
+  );
+  $properties['status'] = array(
+    'label' => t("Status"),
+    'description' => t("Whether the user is active or blocked."),
+    'setter callback' => 'entity_property_verbatim_set',
+    // Although the status is expected to be boolean, its schema suggests
+    // it is an integer, so we follow the schema definition.
+    'type' => 'integer',
+    'options list' => 'entity_metadata_user_status_options_list',
+    'setter permission' => 'administer users',
+    'schema field' => 'status',
+  );
+  $properties['theme'] = array(
+    'label' => t("Default theme"),
+    'description' => t("The user's default theme."),
+    'getter callback' => 'entity_metadata_user_get_properties',
+    'setter callback' => 'entity_property_verbatim_set',
+    'access callback' => 'entity_metadata_user_properties_access',
+    'schema field' => 'theme',
+  );
+  return $info;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/tests/entity_feature.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Entity feature module
+description = Provides some entities in code.
+version = VERSION
+core = 7.x
+files[] = entity_feature.module
+dependencies[] = entity_test
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2013-08-14
+version = "7.x-1.2"
+core = "7.x"
+project = "entity"
+datestamp = "1376493705"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/tests/entity_feature.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Test module providing some entities in code.
+ */
+
+/**
+ * Implements hook_default_entity_test_type().
+ */
+function entity_feature_default_entity_test_type() {
+  $types['main'] = entity_create('entity_test_type', array(
+    'name' => 'main',
+    'label' => t('Main test type'),
+    'weight' => 0,
+    'locked' => TRUE,
+  ));
+
+  // Types used during CRUD testing.
+  $types['test'] = entity_create('entity_test_type', array(
+    'name' => 'test',
+    'label' => 'label',
+    'weight' => 0,
+  ));
+  $types['test2'] = entity_create('entity_test_type', array(
+      'name' => 'test2',
+      'label' => 'label2',
+      'weight' => 2,
+  ));
+
+  return $types;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/tests/entity_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+name = Entity CRUD test module
+description = Provides entity types based upon the CRUD API.
+version = VERSION
+core = 7.x
+files[] = entity_test.module
+files[] = entity_test.install
+dependencies[] = entity
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2013-08-14
+version = "7.x-1.2"
+core = "7.x"
+project = "entity"
+datestamp = "1376493705"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/tests/entity_test.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the entity_test module.
+ */
+
+/**
+ * Implements hook_uninstall().
+ */
+function entity_test_uninstall() {
+  // Bypass entity_load() as we cannot use it here.
+  $types = db_select('entity_test_type', 'et')
+    ->fields('et')
+    ->execute()
+    ->fetchAllAssoc('name');
+
+  foreach ($types as $name => $type) {
+    field_attach_delete_bundle('entity_test', $name);
+  }
+}
+
+/**
+ * Implements hook_schema().
+ */
+function entity_test_schema() {
+  $schema['entity_test'] = array(
+    'description' => 'Stores entity_test items.',
+    'fields' => array(
+      'pid' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique entity_test item ID.',
+      ),
+      'name' => array(
+        'description' => 'The name of the entity_test.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'uid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => FALSE,
+        'default' => NULL,
+        'description' => "The {users}.uid of the associated user.",
+      ),
+    ),
+    'indexes' => array(
+      'uid' => array('uid'),
+    ),
+    'foreign keys' => array(
+      'uid' => array('users' => 'uid'),
+      'name' => array('entity_test_types' => 'name'),
+    ),
+    'primary key' => array('pid'),
+  );
+
+  $schema['entity_test_type'] = array(
+    'description' => 'Stores information about all defined entity_test types.',
+    'fields' => array(
+      'id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique entity_test type ID.',
+      ),
+      'name' => array(
+        'description' => 'The machine-readable name of this entity_test type.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+      ),
+      'label' => array(
+        'description' => 'The human-readable name of this entity_test type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'weight' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'The weight of this entity_test type in relation to others.',
+      ),
+      'locked' => array(
+        'description' => 'A boolean indicating whether the administrator may delete this type.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'data' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+        'size' => 'big',
+        'serialize' => TRUE,
+        'description' => 'A serialized array of additional data related to this entity_test type.',
+        'merge' => TRUE,
+      ),
+      'status' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        // Set the default to ENTITY_CUSTOM without using the constant as it is
+        // not safe to use it at this point.
+        'default' => 0x01,
+        'size' => 'tiny',
+        'description' => 'The exportable status of the entity.',
+      ),
+      'module' => array(
+        'description' => 'The name of the providing module if the entity has been defined in code.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+      ),
+    ),
+    'primary key' => array('id'),
+    'unique keys' => array(
+      'name' => array('name'),
+    ),
+  );
+
+  // Add schema for the revision-test-entity.
+  $schema['entity_test2'] = $schema['entity_test'];
+  $schema['entity_test2']['fields']['revision_id'] = array(
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'not null' => FALSE,
+    'default' => NULL,
+    'description' => 'The ID of the entity\'s default revision.',
+  );
+  $schema['entity_test2']['fields']['title'] = array(
+    'type' => 'varchar',
+    'length' => 255,
+    'not null' => TRUE,
+    'default' => '',
+  );
+
+  $schema['entity_test2_revision'] = $schema['entity_test'];
+  $schema['entity_test2_revision']['fields']['revision_id'] = array(
+    'type' => 'serial',
+    'not null' => TRUE,
+    'description' => 'Primary Key: Unique revision ID.',
+  );
+  $schema['entity_test2_revision']['fields']['pid'] = array(
+    'type' => 'int',
+    'unsigned' => TRUE,
+    'not null' => FALSE,
+    'default' => NULL,
+    'description' => 'The ID of the attached entity.',
+  );
+  $schema['entity_test2_revision']['fields']['title'] = array(
+    'type' => 'varchar',
+    'length' => 255,
+    'not null' => TRUE,
+    'default' => '',
+  );
+  $schema['entity_test2_revision']['primary key'] = array('revision_id');
+
+  return $schema;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/tests/entity_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,280 @@
+<?php
+
+/**
+ * @file
+ * Test moduel for the entity API.
+ */
+
+/**
+ * Implements hook_entity_info().
+ */
+function entity_test_entity_info() {
+  $return = array(
+    'entity_test' => array(
+      'label' => t('Test Entity'),
+      'plural label' => t('Test Entities'),
+      'description' => t('An entity type used by the entity API tests.'),
+      'entity class' => 'EntityClass',
+      'controller class' => 'EntityAPIController',
+      'base table' => 'entity_test',
+      'fieldable' => TRUE,
+      'entity keys' => array(
+        'id' => 'pid',
+        'bundle' => 'name',
+      ),
+      // Make use the class' label() and uri() implementation by default.
+      'label callback' => 'entity_class_label',
+      'uri callback' => 'entity_class_uri',
+      'bundles' => array(),
+      'bundle keys' => array(
+        'bundle' => 'name',
+      ),
+      'module' => 'entity_test',
+    ),
+    'entity_test_type' => array(
+      'label' => t('Test entity type'),
+      'entity class' => 'Entity',
+      'controller class' => 'EntityAPIControllerExportable',
+      'base table' => 'entity_test_type',
+      'fieldable' => FALSE,
+      'bundle of' => 'entity_test',
+      'exportable' => TRUE,
+      'entity keys' => array(
+        'id' => 'id',
+        'name' => 'name',
+      ),
+      'module' => 'entity_test',
+    ),
+
+    'entity_test2' => array(
+      'label' => t('Test Entity (revision support)'),
+      'entity class' => 'EntityClassRevision',
+      'controller class' => 'EntityAPIController',
+      'base table' => 'entity_test2',
+      'revision table' => 'entity_test2_revision',
+      'fieldable' => TRUE,
+      'entity keys' => array(
+        'id' => 'pid',
+        'revision' => 'revision_id',
+      ),
+      // Make use of the class label() and uri() implementation by default.
+      'label callback' => 'entity_class_label',
+      'uri callback' => 'entity_class_uri',
+      'bundles' => array(),
+      'bundle keys' => array(
+        'bundle' => 'name',
+      ),
+    ),
+  );
+
+  // Add bundle info but bypass entity_load() as we cannot use it here.
+  $types = db_select('entity_test_type', 'et')
+    ->fields('et')
+    ->execute()
+    ->fetchAllAssoc('name');
+
+  foreach ($types as $name => $type) {
+    $return['entity_test']['bundles'][$name] = array(
+      'label' => $type->label,
+    );
+  }
+
+  // Support entity cache module.
+  if (module_exists('entitycache')) {
+    $return['entity_test']['field cache'] = FALSE;
+    $return['entity_test']['entity cache'] = TRUE;
+  }
+
+  return $return;
+}
+
+/**
+ * Gets an array of all test entity types, keyed by the name.
+ *
+ * @param $name
+ *   If set, the type with the given name is returned.
+ */
+function entity_test_get_types($name = NULL) {
+  $types = entity_load_multiple_by_name('entity_test_type', isset($name) ? array($name) : FALSE);
+  return isset($name) ? reset($types) : $types;
+}
+
+/**
+ * Load multiple test entities based on certain conditions.
+ *
+ * @param $pids
+ *   An array of entity IDs.
+ * @param $conditions
+ *   An array of conditions to match against the {entity} table.
+ * @param $reset
+ *   A boolean indicating that the internal cache should be reset.
+ * @return
+ *   An array of test entity objects, indexed by pid.
+ */
+function entity_test_load_multiple($pids = array(), $conditions = array(), $reset = FALSE) {
+  return entity_load('entity_test', $pids, $conditions, $reset);
+}
+
+/**
+ * Delete multiple test entities.
+ *
+ * @param $pids
+ *   An array of test entity IDs.
+ */
+function entity_test_delete_multiple(array $pids) {
+  entity_get_controller('entity_test')->delete($pids);
+}
+
+
+/**
+ * Main class for test entities.
+ */
+class EntityClass extends Entity {
+
+  public function __construct(array $values = array(), $entityType = NULL) {
+    parent::__construct($values, 'entity_test');
+  }
+
+  /**
+   * Override buildContent() to add the username to the output.
+   */
+  public function buildContent($view_mode = 'full', $langcode = NULL) {
+    $content['user'] = array(
+      '#markup' => "User: ". format_username(user_load($this->uid)),
+    );
+    return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode, $content);
+  }
+
+  /**
+   * Specifies the default label, which is picked up by label() by default.
+   */
+  protected function defaultLabel() {
+    $type = entity_test_get_types($this->name);
+    return $type->label;
+  }
+
+  /**
+   * Specifies the default uri, which is picked up by uri() by default.
+   */
+  protected function defaultURI() {
+    return array('path' => 'custom/' . $this->identifier());
+  }
+}
+
+/**
+ * Main class for test entities (with revision support).
+ */
+class EntityClassRevision extends EntityClass {
+
+  public function __construct(array $values = array(), $entityType = NULL) {
+    Entity::__construct($values, 'entity_test2');
+  }
+
+}
+
+/**
+ *
+ *
+ * Some hook implementations used by the tests.
+ *
+ *
+ */
+
+
+/**
+ * Implements hook_entity_insert().
+ */
+function entity_test_entity_insert($entity, $entity_type) {
+  if ($entity_type == 'entity_test_type') {
+    $_SESSION['entity_hook_test']['entity_insert'][] = entity_id($entity_type, $entity);
+  }
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function entity_test_entity_update($entity, $entity_type) {
+  $_SESSION['entity_hook_test']['entity_update'][] = entity_id($entity_type, $entity);
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function entity_test_entity_delete($entity, $entity_type) {
+  if ($entity_type == 'entity_test_type') {
+    $_SESSION['entity_hook_test']['entity_delete'][] = entity_id($entity_type, $entity);
+  }
+}
+
+/**
+ * Implements hook_entity_test_type_insert().
+ */
+function entity_test_entity_test_type_insert($entity) {
+  $_SESSION['entity_hook_test']['entity_test_type_insert'][] = $entity->identifier();
+}
+
+/**
+ * Implements hook_entity_test_type_update().
+ */
+function entity_test_entity_test_type_update($entity) {
+  $_SESSION['entity_hook_test']['entity_test_type_update'][] = $entity->identifier();
+
+  // Determine changes on update.
+  if (!empty($entity->original) && $entity->original->label == 'test_changes') {
+    if ($entity->original->label != $entity->label) {
+      $entity->label .= '_update';
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_test_type_delete().
+ */
+function entity_test_entity_test_type_delete($entity) {
+  $_SESSION['entity_hook_test']['entity_test_type_delete'][] = $entity->identifier();
+}
+
+/**
+ * Implements hook_entity_test_type_presave().
+ */
+function entity_test_entity_test_type_presave($entity) {
+  // Determine changes.
+  if (!empty($entity->original) && $entity->original->label == 'test_changes') {
+    if ($entity->original->label != $entity->label) {
+      $entity->label .= '_presave';
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_property_info_alter() for testing an property of type
+ * 'entity'.
+ */
+function entity_test_entity_property_info_alter(&$info) {
+  $info['node']['properties']['reference'] = array(
+    'label' => t('Test reference'),
+    'description' => t('A generic entity reference.'),
+    'getter callback' => 'entity_test_entity_getter',
+    'setter callback' => 'entity_test_entity_setter',
+    'type' => 'entity',
+  );
+}
+
+/**
+ * Getter callback for the 'reference' property.
+ */
+function entity_test_entity_getter($node) {
+  if (empty($node->entity)) {
+    $node->entity = array('type' => 'user', 'id' => $node->uid);
+  }
+  // We have to return the entity wrapped.
+  return entity_metadata_wrapper($node->entity['type'], $node->entity['id']);
+}
+
+/**
+ * Setter callback for the 'reference' property.
+ */
+function entity_test_entity_setter($node, $property_name, $wrapper) {
+  // The entity has to be passed wrapped.
+  $node->entity = array('type' => $wrapper->type(), 'id' => $wrapper->getIdentifier());
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/tests/entity_test_i18n.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Entity-test type translation
+description = Allows translating entity-test types.
+dependencies[] = entity_test
+dependencies[] = i18n_string
+package = Multilingual - Internationalization
+core = 7.x
+hidden = TRUE
+; Information added by drupal.org packaging script on 2013-08-14
+version = "7.x-1.2"
+core = "7.x"
+project = "entity"
+datestamp = "1376493705"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/tests/entity_test_i18n.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @file
+ * Entity-test i18n integration module via entity API i18n support.
+ *
+ * @see EntityDefaultI18nController
+ */
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function entity_test_i18n_entity_info_alter(&$info) {
+  // Enable i18n support via the entity API.
+  $info['entity_test_type']['i18n controller class'] = 'EntityDefaultI18nStringController';
+}
+
+/**
+ * Implements hook_entity_property_info_alter().
+ */
+function entity_test_i18n_entity_property_info_alter(&$info) {
+  // Mark some properties as translatable, but also denote that translation
+  // works with i18n_string.
+  foreach (array('label') as $name) {
+    $info['entity_test_type']['properties'][$name]['translatable'] = TRUE;
+    $info['entity_test_type']['properties'][$name]['i18n string'] = TRUE;
+  }
+}
+
+/**
+ * Implements hook_{entity_test_type}_insert().
+ */
+function entity_test_i18n_entity_test_type_insert($test_type) {
+  i18n_string_object_update('entity_test_type', $test_type);
+}
+
+/**
+ * Implements hook_{entity_test_type}_update().
+ */
+function entity_test_i18n_entity_test_type_update($test_type) {
+  // Account for name changes.
+  if ($test_type->original->name != $test_type->name) {
+    i18n_string_update_context("entity_test:entity_test_type:{$test_type->original->name}:*", "entity_test:entity_test_type:{$test_type->name}:*");
+  }
+  i18n_string_object_update('entity_test_type', $test_type);
+}
+
+/**
+ * Implements hook_{entity_test_type}_delete().
+ */
+function entity_test_i18n_entity_test_type_delete($test_type) {
+  i18n_string_object_remove('entity_test_type', $test_type);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/theme/entity.theme.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,4 @@
+
+.entity-property-label {
+  font-weight: bold;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/theme/entity.theme.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,212 @@
+<?php
+
+/**
+ * @file
+ * Holds entity module's theme functions.
+ */
+
+/**
+ * Returns HTML for an entity property.
+ *
+ * This is the default theme implementation to display the value of a property.
+ * This function can be overridden with varying levels of specificity. For
+ * example, for a property named 'title' displayed on the 'article' bundle,
+ * any of the following functions will override this default implementation.
+ * The first of these functions that exists is used:
+ * - THEMENAME_property__body__article()
+ * - THEMENAME_property__article()
+ * - THEMENAME_property__body()
+ * - THEMENAME_property()
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - label: A boolean indicating to show or hide the property label.
+ *   - title_attributes: A string containing the attributes for the title.
+ *   - label: The label for the property.
+ *   - content_attributes: A string containing the attributes for the content's
+ *     div.
+ *   - content: The rendered property value.
+ *   - attributes: A string containing the attributes for the wrapping div.
+ *
+ * @ingroup themeable
+ */
+function theme_entity_property($variables) {
+  $output = '';
+
+  // Render the label, if it's not hidden.
+  if (!$variables['label_hidden']) {
+    $output .= '<div' . $variables['title_attributes'] . '>' . $variables['label'] . ':&nbsp;</div>';
+  }
+
+  // Render the content.
+  $content_suffix = '';
+  if (!$variables['label_hidden'] || $variables['content_attributes']) {
+    $output .= '<div' . $variables['content_attributes'] . '>';
+    $content_suffix = '</div>';
+  }
+  $output .= $variables['content'] . $content_suffix;
+
+  // Render the top-level DIV.
+  return '<div' . $variables['attributes'] . '>' . $output . '</div>';
+}
+
+/**
+ * Theme preprocess function for theme_entity_property().
+ *
+ * @see theme_entity_property()
+ */
+function template_preprocess_entity_property(&$variables, $hook) {
+  $element = $variables['elements'];
+
+  $variables += array(
+    'theme_hook_suggestions' => array(),
+    'attributes_array' => array(),
+  );
+  // Generate variables from element properties.
+  foreach (array('label_hidden', 'label', 'property_name') as $name) {
+    $variables[$name] = check_plain($element['#' . $name]);
+  }
+  $variables['title_attributes_array']['class'][] = 'entity-property-label';
+  $variables['attributes_array'] = array_merge($variables['attributes_array'], isset($element['#attributes']) ? $element['#attributes'] : array());
+
+  $variables['property_name_css'] = strtr($element['#property_name'], '_', '-');
+  $variables['attributes_array']['class'][] = 'entity-property';
+  $variables['attributes_array']['class'][] = 'entity-property-' . $variables['property_name_css'];
+
+  // Add specific suggestions that can override the default implementation.
+  $variables['theme_hook_suggestions'] += array(
+    'entity_property__' . $element['#property_name'],
+    'entity_property__' . $element['#entity_type'] . '__' . $element['#property_name'],
+  );
+
+  // Populate the content with sensible defaults.
+  if (!isset($variables['content'])) {
+    $variables['content'] = entity_property_default_render_value_by_type($element['#entity_wrapped']->{$element['#property_name']});
+  }
+}
+
+/**
+ * Renders a property using simple defaults based upon the property type.
+ *
+ * @return string
+ */
+function entity_property_default_render_value_by_type(EntityMetadataWrapper $property) {
+  // If there is an options list or entity label, render that by default.
+  if ($label = $property->label()) {
+    if ($property instanceof EntityDrupalWrapper && $uri = entity_uri($property->type(), $property->value())) {
+      return l($label, $uri['path'], $uri['options']);
+    }
+    else {
+      return check_plain($label);
+    }
+  }
+  switch ($property->type()) {
+    case 'boolean':
+      return $property->value() ? t('yes') : t('no');
+    default:
+      return check_plain($property->value());
+  }
+}
+
+/**
+ * Theme process function for theme_entity_property().
+ *
+ * Taken over from template_process_field()
+ *
+ * @see theme_entity_property()
+ */
+function template_process_entity_property(&$variables, $hook) {
+  $element = $variables['elements'];
+  // The default theme implementation is a function, so template_process() does
+  // not automatically run, so we need to flatten the classes and attributes
+  // here. For best performance, only call drupal_attributes() when needed, and
+  // note that template_preprocess_field() does not initialize the
+  // *_attributes_array variables.
+  $variables['attributes'] = empty($variables['attributes_array']) ? '' : drupal_attributes($variables['attributes_array']);
+  $variables['title_attributes'] = empty($variables['title_attributes_array']) ? '' : drupal_attributes($variables['title_attributes_array']);
+  $variables['content_attributes'] = empty($variables['content_attributes_array']) ? '' : drupal_attributes($variables['content_attributes_array']);
+}
+
+/**
+ * Themes the exportable status of an entity.
+ */
+function theme_entity_status($variables) {
+  $status = $variables['status'];
+  $html = $variables['html'];
+  if (($status & ENTITY_FIXED) == ENTITY_FIXED) {
+    $label = t('Fixed');
+    $help = t('The configuration is fixed and cannot be changed.');
+    return $html ? "<span class='entity-status-fixed' title='$help'>" . $label . "</span>" : $label;
+  }
+  elseif (($status & ENTITY_OVERRIDDEN) == ENTITY_OVERRIDDEN) {
+    $label = t('Overridden');
+    $help = t('This configuration is provided by a module, but has been changed.');
+    return $html ? "<span class='entity-status-overridden' title='$help'>" . $label . "</span>" : $label;
+  }
+  elseif ($status & ENTITY_IN_CODE) {
+    $label = t('Default');
+    $help = t('A module provides this configuration.');
+    return $html ? "<span class='entity-status-default' title='$help'>" . $label . "</span>" : $label;
+  }
+  elseif ($status & ENTITY_CUSTOM) {
+    $label = t('Custom');
+    $help = t('A custom configuration by a user.');
+    return $html ? "<span class='entity-status-custom' title='$help'>" . $label . "</span>" : $label;
+  }
+}
+
+/**
+ * Process variables for entity.tpl.php.
+ */
+function template_preprocess_entity(&$variables) {
+  $variables['view_mode'] = $variables['elements']['#view_mode'];
+  $entity_type = $variables['elements']['#entity_type'];
+  $variables['entity_type'] = $entity_type;
+  $entity = $variables['elements']['#entity'];
+  $variables[$variables['elements']['#entity_type']] = $entity;
+  $info = entity_get_info($entity_type);
+
+  $variables['title'] = check_plain(entity_label($entity_type, $entity));
+
+  $uri = entity_uri($entity_type, $entity);
+  $variables['url'] = $uri ? url($uri['path'], $uri['options']) : FALSE;
+
+  if (isset($variables['elements']['#page'])) {
+    // If set by the caller, respect the page property.
+    $variables['page'] = $variables['elements']['#page'];
+  }
+  else {
+    // Else, try to automatically detect it.
+    $variables['page'] = $uri && $uri['path'] == $_GET['q'];
+  }
+
+  // Helpful $content variable for templates.
+  $variables['content'] = array();
+  foreach (element_children($variables['elements']) as $key) {
+    $variables['content'][$key] = $variables['elements'][$key];
+  }
+
+  if (!empty($info['fieldable'])) {
+    // Make the field variables available with the appropriate language.
+    field_attach_preprocess($entity_type, $entity, $variables['content'], $variables);
+  }
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+
+  // Gather css classes.
+  $variables['classes_array'][] = drupal_html_class('entity-' . $entity_type);
+  $variables['classes_array'][] = drupal_html_class($entity_type . '-' . $bundle);
+
+  // Add RDF type and about URI.
+  if (module_exists('rdf')) {
+    $variables['attributes_array']['about'] = empty($uri['path']) ? NULL: url($uri['path']);
+    $variables['attributes_array']['typeof'] = empty($entity->rdf_mapping['rdftype']) ? NULL : $entity->rdf_mapping['rdftype'];
+  }
+
+  // Add suggestions.
+  $variables['theme_hook_suggestions'][] = $entity_type;
+  $variables['theme_hook_suggestions'][] = $entity_type . '__' . $bundle;
+  $variables['theme_hook_suggestions'][] = $entity_type . '__' . $bundle . '__' . $variables['view_mode'];
+  if ($id = entity_id($entity_type, $entity)) {
+    $variables['theme_hook_suggestions'][] = $entity_type . '__' . $id;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/theme/entity.tpl.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Default theme implementation for entities.
+ *
+ * Available variables:
+ * - $content: An array of comment items. Use render($content) to print them all, or
+ *   print a subset such as render($content['field_example']). Use
+ *   hide($content['field_example']) to temporarily suppress the printing of a
+ *   given element.
+ * - $title: The (sanitized) entity label.
+ * - $url: Direct url of the current entity if specified.
+ * - $page: Flag for the full page state.
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS. It can be manipulated through the variable $classes_array from
+ *   preprocess functions. By default the following classes are available, where
+ *   the parts enclosed by {} are replaced by the appropriate values:
+ *   - entity-{ENTITY_TYPE}
+ *   - {ENTITY_TYPE}-{BUNDLE}
+ *
+ * Other variables:
+ * - $classes_array: Array of html class attribute values. It is flattened
+ *   into a string within the variable $classes.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_entity()
+ * @see template_process()
+ */
+?>
+<div class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
+
+  <?php if (!$page): ?>
+    <h2<?php print $title_attributes; ?>>
+      <?php if ($url): ?>
+        <a href="<?php print $url; ?>"><?php print $title; ?></a>
+      <?php else: ?>
+        <?php print $title; ?>
+      <?php endif; ?>
+    </h2>
+  <?php endif; ?>
+
+  <div class="content"<?php print $content_attributes; ?>>
+    <?php
+      print render($content);
+    ?>
+  </div>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/entity.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,636 @@
+<?php
+
+/**
+ * @file
+ * Provide views data for modules making use of the entity CRUD API.
+ */
+
+/**
+ * Implements hook_views_data().
+ *
+ * Provides Views integration for entities if they satisfy one of these
+ * conditions:
+ *  - hook_entity_info() specifies a 'views controller class' key.
+ *  - hook_entity_info() specifies a 'module' key, and the module does not
+ *    implement hook_views_data().
+ *
+ * @see entity_crud_hook_entity_info()
+ * @see entity_views_table_definition()
+ */
+function entity_views_data() {
+  $data = array();
+
+  foreach (entity_crud_get_info() as $type => $info) {
+    // Provide default integration with the basic controller class if we know
+    // the module providing the entity and it does not provide views integration.
+    if (!isset($info['views controller class'])) {
+      $info['views controller class'] = isset($info['module']) && !module_hook($info['module'], 'views_data') ? 'EntityDefaultViewsController' : FALSE;
+    }
+    if ($info['views controller class']) {
+      $controller = new $info['views controller class']($type);
+      // Relationship data may return views data for already existing tables,
+      // so merge results on the second level.
+      foreach ($controller->views_data() as $table => $table_data) {
+        $data += array($table => array());
+        $data[$table] = array_merge($data[$table], $table_data);
+      }
+    }
+  }
+
+  // Add tables based upon data selection "queries" for all entity types.
+  foreach (entity_get_info() as $type => $info) {
+    $table = entity_views_table_definition($type);
+    if ($table) {
+      $data['entity_' . $type] = $table;
+    }
+    // Generally expose properties marked as 'entity views field'.
+    $data['views_entity_' . $type] = array();
+    foreach (entity_get_all_property_info($type) as $key => $property) {
+      if (!empty($property['entity views field'])) {
+        entity_views_field_definition($key, $property, $data['views_entity_' . $type]);
+      }
+    }
+  }
+
+  // Expose generally usable entity-related fields.
+  foreach (entity_get_info() as $entity_type => $info) {
+    if (entity_type_supports($entity_type, 'view')) {
+      // Expose a field allowing to display the rendered entity.
+      $data['views_entity_' . $entity_type]['rendered_entity'] = array(
+        'title' => t('Rendered @entity-type', array('@entity-type' => $info['label'])),
+        'help' => t('The @entity-type of the current relationship rendered using a view mode.', array('@entity-type' => $info['label'])),
+        'field' => array(
+          'handler' => 'entity_views_handler_field_entity',
+          'type' => $entity_type,
+          // The EntityFieldHandlerHelper treats the 'entity object' data
+          // selector as special case for loading the base entity.
+          'real field' => 'entity object',
+        ),
+      );
+    }
+  }
+
+  $data['entity__global']['table']['group'] = t('Entity');
+  $data['entity__global']['table']['join'] = array(
+    // #global let's it appear all the time.
+    '#global' => array(),
+  );
+  $data['entity__global']['entity'] = array(
+    'title' => t('Rendered entity'),
+    'help' => t('Displays a single chosen entity.'),
+    'area' => array(
+      'handler' => 'entity_views_handler_area_entity',
+    ),
+  );
+
+  return $data;
+}
+
+/**
+ * Helper function for getting data selection based entity Views table definitions.
+ *
+ * This creates extra tables for each entity type that are not associated with a
+ * query plugin (and thus are not base tables) and just rely on the entities to
+ * retrieve the displayed data. To obtain the entities corresponding to a
+ * certain result set, the field handlers defined on the table use a generic
+ * interface defined for query plugins that are based on entity handling, and
+ * which is described in the entity_views_example_query class.
+ *
+ * These tables are called "data selection tables".
+ *
+ * Other modules providing Views integration with new query plugins that are
+ * based on entities can then use these tables as a base for their own tables
+ * (by directly using this method and modifying the returned table) and/or by
+ * specifying relationships to them. The tables returned here already specify
+ * relationships to each other wherever an entity contains a reference to
+ * another (e.g., the node author constructs a relationship from nodes to
+ * users).
+ *
+ * As filtering and other query manipulation is potentially more plugin-specific
+ * than the display, only field handlers and relationships are provided with
+ * these tables. By providing a add_selector_orderby() method, the query plugin
+ * can, however, support click-sorting for the field handlers in these tables.
+ *
+ * For a detailed discussion see http://drupal.org/node/1266036
+ *
+ * For example use see the Search API views module in the Search API project:
+ * http://drupal.org/project/search_api
+ *
+ * @param $type
+ *   The entity type whose table definition should be returned.
+ * @param $exclude
+ *   Whether properties already exposed as 'entity views field' should be
+ *   excluded. Defaults to TRUE, as they are available for all views tables for
+ *   the entity type anyways.
+ *
+ * @return
+ *   An array containing the data selection Views table definition for the
+ *   entity type.
+ *
+ * @see entity_views_field_definition()
+ */
+function entity_views_table_definition($type, $exclude = TRUE) {
+  // As other modules might want to copy these tables as a base for their own
+  // Views integration, we statically cache the tables to save some time.
+  $tables = &drupal_static(__FUNCTION__, array());
+
+  if (!isset($tables[$type])) {
+    // Work-a-round to fix updating, see http://drupal.org/node/1330874.
+    // Views data might be rebuilt on update.php before the registry is rebuilt,
+    // thus the class cannot be auto-loaded.
+    if (!class_exists('EntityFieldHandlerHelper')) {
+      module_load_include('inc', 'entity', 'views/handlers/entity_views_field_handler_helper');
+    }
+
+    $info = entity_get_info($type);
+    $tables[$type]['table'] = array(
+      'group' => $info['label'],
+      'entity type' => $type,
+    );
+    foreach (entity_get_all_property_info($type) as $key => $property) {
+      if (!$exclude || empty($property['entity views field'])) {
+        entity_views_field_definition($key, $property, $tables[$type]);
+      }
+    }
+  }
+
+  return $tables[$type];
+}
+
+/**
+ * Helper function for adding a Views field definition to data selection based Views tables.
+ *
+ * @param $field
+ *   The data selector of the field to add. E.g. "title" would derive the node
+ *   title property, "body:summary" the node body's summary.
+ * @param array $property_info
+ *   The property information for which to create a field definition.
+ * @param array $table
+ *   The table into which the definition should be inserted.
+ * @param $title_prefix
+ *   Internal use only.
+ *
+ * @see entity_views_table_definition()
+ */
+function entity_views_field_definition($field, array $property_info, array &$table, $title_prefix = '') {
+  $additional = array();
+  $additional_field = array();
+
+  // Create a valid Views field identifier (no colons, etc.). Keep the original
+  // data selector as real field though.
+  $key = _entity_views_field_identifier($field, $table);
+  if ($key != $field) {
+    $additional['real field'] = $field;
+  }
+  $field_name = EntityFieldHandlerHelper::get_selector_field_name($field);
+
+  $field_handlers = entity_views_get_field_handlers();
+
+  $property_info += entity_property_info_defaults();
+  $type = entity_property_extract_innermost_type($property_info['type']);
+  $title = $title_prefix . $property_info['label'];
+  if ($info = entity_get_info($type)) {
+    $additional['relationship'] = array(
+      'handler' => $field_handlers['relationship'],
+      'base' => 'entity_' . $type,
+      'base field' => $info['entity keys']['id'],
+      'relationship field' => $field,
+      'label' => $title,
+    );
+    if ($property_info['type'] != $type) {
+      // This is a list of entities, so we should mark the relationship as such.
+      $additional['relationship']['multiple'] = TRUE;
+    }
+    // Implementers of the field handlers alter hook could add handlers for
+    // specific entity types.
+    if (!isset($field_handlers[$type])) {
+      $type = 'entity';
+    }
+  }
+  elseif (!empty($property_info['field'])) {
+    $type = 'field';
+    // Views' Field API field handler needs some extra definitions to work.
+    $additional_field['field_name'] = $field_name;
+    $additional_field['entity_tables'] = array();
+    $additional_field['entity type'] = $table['table']['entity type'];
+    $additional_field['is revision'] = FALSE;
+  }
+  // Copied from EntityMetadataWrapper::optionsList()
+  elseif (isset($property_info['options list']) && is_callable($property_info['options list'])) {
+    // If this is a nested property, we need to get rid of all prefixes first.
+    $type = 'options';
+    $additional_field['options callback'] = array(
+      'function' => $property_info['options list'],
+      'info' => $property_info,
+    );
+  }
+  elseif ($type == 'decimal') {
+    $additional_field['float'] = TRUE;
+  }
+
+  if (isset($field_handlers[$type])) {
+    $table += array($key => array());
+    $table[$key] += array(
+      'title' => $title,
+      'help' => empty($property_info['description']) ? t('(No information available)') : $property_info['description'],
+      'field' => array(),
+    );
+    $table[$key]['field'] += array(
+      'handler' => $field_handlers[$type],
+      'type' => $property_info['type'],
+    );
+    $table[$key] += $additional;
+    $table[$key]['field'] += $additional_field;
+  }
+  if (!empty($property_info['property info'])) {
+    foreach ($property_info['property info'] as $nested_key => $nested_property) {
+      entity_views_field_definition($field . ':' . $nested_key, $nested_property, $table, $title . ' » ');
+    }
+  }
+}
+
+/**
+ * @return array
+ *   The handlers to use for the data selection based Views tables.
+ *
+ * @see hook_entity_views_field_handlers_alter()
+ */
+function entity_views_get_field_handlers() {
+  $field_handlers = drupal_static(__FUNCTION__);
+  if (!isset($field_handlers)) {
+    // Field handlers for the entity tables, by type.
+    $field_handlers = array(
+      'text'         => 'entity_views_handler_field_text',
+      'token'        => 'entity_views_handler_field_text',
+      'integer'      => 'entity_views_handler_field_numeric',
+      'decimal'      => 'entity_views_handler_field_numeric',
+      'date'         => 'entity_views_handler_field_date',
+      'duration'     => 'entity_views_handler_field_duration',
+      'boolean'      => 'entity_views_handler_field_boolean',
+      'uri'          => 'entity_views_handler_field_uri',
+      'options'      => 'entity_views_handler_field_options',
+      'field'        => 'entity_views_handler_field_field',
+      'entity'       => 'entity_views_handler_field_entity',
+      'relationship' => 'entity_views_handler_relationship',
+    );
+    drupal_alter('entity_views_field_handlers', $field_handlers);
+  }
+  return $field_handlers;
+}
+
+/**
+ * Helper function for creating valid Views field identifiers out of data selectors.
+ *
+ * Uses $table to test whether the identifier is already used, and also
+ * recognizes if a definition for the same field is already present and returns
+ * that definition's identifier.
+ *
+ * @return string
+ *   A valid Views field identifier that is not yet used as a key in $table.
+ */
+function _entity_views_field_identifier($field, array $table) {
+  $key = $base = preg_replace('/[^a-zA-Z0-9]+/S', '_', $field);
+  $i = 0;
+  // The condition checks whether this sanitized field identifier is already
+  // used for another field in this table (and whether the identifier is
+  // "table", which can never be used).
+  // If $table[$key] is set, the identifier is already used, but this might be
+  // already for the same field. To test that, we need the original field name,
+  // which is either $table[$key]['real field'], if set, or $key. If this
+  // original field name is equal to $field, we can use that key. Otherwise, we
+  // append numeric suffixes until we reach an unused key.
+  while ($key == 'table' || (isset($table[$key]) && (isset($table[$key]['real field']) ? $table[$key]['real field'] : $key) != $field)) {
+    $key = $base . '_' . ++$i;
+  }
+  return $key;
+}
+
+/**
+ * Implements hook_views_plugins().
+ */
+function entity_views_plugins() {
+  // Have views cache the table list for us so it gets
+  // cleared at the appropriate times.
+  $data = views_cache_get('entity_base_tables', TRUE);
+  if (!empty($data->data)) {
+    $base_tables = $data->data;
+  }
+  else {
+    $base_tables = array();
+    foreach (views_fetch_data() as $table => $data) {
+      if (!empty($data['table']['entity type']) && !empty($data['table']['base'])) {
+        $base_tables[] = $table;
+      }
+    }
+    views_cache_set('entity_base_tables', $base_tables, TRUE);
+  }
+  if (!empty($base_tables)) {
+    return array(
+      'module' => 'entity',
+      'row' => array(
+        'entity' => array(
+          'title' => t('Rendered entity'),
+          'help' => t('Renders a single entity in a specific view mode (e.g. teaser).'),
+          'handler' => 'entity_views_plugin_row_entity_view',
+          'uses fields' => FALSE,
+          'uses options' => TRUE,
+          'type' => 'normal',
+          'base' => $base_tables,
+        ),
+      ),
+    );
+  }
+}
+
+/**
+ * Default controller for generating basic views integration.
+ *
+ * The controller tries to generate suiting views integration for the entity
+ * based upon the schema information of its base table and the provided entity
+ * property information.
+ * For that it is possible to map a property name to its schema/views field
+ * name by adding a 'schema field' key with the name of the field as value to
+ * the property info.
+ */
+class EntityDefaultViewsController {
+
+  protected $type, $info, $relationships;
+
+  public function __construct($type) {
+    $this->type = $type;
+    $this->info = entity_get_info($type);
+  }
+
+  /**
+   * Defines the result for hook_views_data().
+   */
+  public function views_data() {
+    $data = array();
+    $this->relationships = array();
+
+    if (!empty($this->info['base table'])) {
+      $table = $this->info['base table'];
+      // Define the base group of this table. Fields that don't
+      // have a group defined will go into this field by default.
+      $data[$table]['table']['group']  = drupal_ucfirst($this->info['label']);
+      $data[$table]['table']['entity type'] = $this->type;
+
+      // If the plural label isn't available, use the regular label.
+      $label = isset($this->info['plural label']) ? $this->info['plural label'] : $this->info['label'];
+      $data[$table]['table']['base'] = array(
+        'field' => $this->info['entity keys']['id'],
+        'access query tag' => $this->type . '_access',
+        'title' => drupal_ucfirst($label),
+        'help' => isset($this->info['description']) ? $this->info['description'] : '',
+      );
+      $data[$table]['table']['entity type'] = $this->type;
+      $data[$table] += $this->schema_fields();
+
+      // Add in any reverse-relationships which have been determined.
+      $data += $this->relationships;
+    }
+    return $data;
+  }
+
+  /**
+   * Try to come up with some views fields with the help of the schema and
+   * the entity property information.
+   */
+  protected function schema_fields() {
+    $schema = drupal_get_schema($this->info['base table']);
+    $properties = entity_get_property_info($this->type) + array('properties' => array());
+    $data = array();
+
+    foreach ($properties['properties'] as $name => $property_info) {
+      if (isset($property_info['schema field']) && isset($schema['fields'][$property_info['schema field']])) {
+        if ($views_info = $this->map_from_schema_info($name, $schema['fields'][$property_info['schema field']], $property_info)) {
+          $data[$name] = $views_info;
+        }
+      }
+    }
+    return $data;
+  }
+
+  /**
+   * Comes up with views information based on the given schema and property
+   * info.
+   */
+  protected function map_from_schema_info($property_name, $schema_field_info, $property_info) {
+    $type = isset($property_info['type']) ? $property_info['type'] : 'text';
+    $views_field_name = $property_info['schema field'];
+
+    $return = array();
+
+    if (!empty($schema_field_info['serialize'])) {
+      return FALSE;
+    }
+
+    $description = array(
+      'title' => $property_info['label'],
+      'help' => isset($property_info['description']) ? $property_info['description'] : NULL,
+    );
+
+      // Add in relationships to related entities.
+    if (($info = entity_get_info($type)) && !empty($info['base table'])) {
+
+      // Prepare reversed relationship data.
+      $label_lowercase = drupal_strtolower($this->info['label'][0]) . drupal_substr($this->info['label'], 1);
+      $property_label_lowercase = drupal_strtolower($property_info['label'][0]) . drupal_substr($property_info['label'], 1);
+
+      // We name the field of the first reverse-relationship just with the
+      // base table to be backward compatible, for subsequents relationships we
+      // append the views field name in order to get a unique name.
+      $name = !isset($this->relationships[$info['base table']][$this->info['base table']]) ? $this->info['base table'] : $this->info['base table'] . '_' . $views_field_name;
+      $this->relationships[$info['base table']][$name] = array(
+        'title' => $this->info['label'],
+        'help' => t("Associated @label via the @label's @property.", array('@label' => $label_lowercase, '@property' => $property_label_lowercase)),
+        'relationship' => array(
+          'label' => $this->info['label'],
+          'handler' => $this->getRelationshipHandlerClass($this->type, $type),
+          'base' => $this->info['base table'],
+          'base field' => $views_field_name,
+          'relationship field' => isset($info['entity keys']['name']) ? $info['entity keys']['name'] : $info['entity keys']['id'],
+        ),
+      );
+
+      $return['relationship'] = array(
+        'label' => drupal_ucfirst($info['label']),
+        'handler' => $this->getRelationshipHandlerClass($type, $this->type),
+        'base' => $info['base table'],
+        'base field' => isset($info['entity keys']['name']) ? $info['entity keys']['name'] : $info['entity keys']['id'],
+        'relationship field' => $views_field_name,
+      );
+
+      // Add in direct field/filters/sorts for the id itself too.
+      $type = isset($info['entity keys']['name']) ? 'token' : 'integer';
+      // Append the views-field-name to the title if it is different to the
+      // property name.
+      if ($property_name != $views_field_name) {
+        $description['title'] .= ' ' . $views_field_name;
+      }
+    }
+
+    switch ($type) {
+      case 'token':
+      case 'text':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field',
+            'click sortable' => TRUE,
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_string',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_string',
+          ),
+        );
+      break;
+
+      case 'decimal':
+      case 'integer':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field_numeric',
+            'click sortable' => TRUE,
+            'float' => ($type == 'decimal'),
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_numeric',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_numeric',
+          ),
+        );
+      break;
+
+      case 'date':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field_date',
+            'click sortable' => TRUE,
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort_date',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_date',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_date',
+          ),
+        );
+      break;
+
+      case 'uri':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field_url',
+            'click sortable' => TRUE,
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_string',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_string',
+          ),
+        );
+      break;
+
+      case 'boolean':
+        $return += $description + array(
+          'field' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_field_boolean',
+            'click sortable' => TRUE,
+           ),
+          'sort' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_sort',
+          ),
+          'filter' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_filter_boolean_operator',
+          ),
+          'argument' => array(
+            'real field' => $views_field_name,
+            'handler' => 'views_handler_argument_string',
+          ),
+        );
+      break;
+    }
+
+    // If there is an options list callback, add to the filter and field.
+    if (isset($return['filter']) && !empty($property_info['options list'])) {
+      $return['filter']['handler'] = 'views_handler_filter_in_operator';
+      $return['filter']['options callback'] = array('EntityDefaultViewsController', 'optionsListCallback');
+      $return['filter']['options arguments'] = array($this->type, $property_name, 'view');
+    }
+    // @todo: This class_exists is needed until views 3.2.
+    if (isset($return['field']) && !empty($property_info['options list']) && class_exists('views_handler_field_machine_name')) {
+      $return['field']['handler'] = 'views_handler_field_machine_name';
+      $return['field']['options callback'] = array('EntityDefaultViewsController', 'optionsListCallback');
+      $return['field']['options arguments'] = array($this->type, $property_name, 'view');
+    }
+    return $return;
+  }
+
+  /**
+   * Determines the handler to use for a relationship to an entity type.
+   *
+   * @param $entity_type
+   *   The entity type to join to.
+   * @param $left_type
+   *   The data type from which to join.
+   */
+  function getRelationshipHandlerClass($entity_type, $left_type) {
+    // Look for an entity type which is used as bundle for the given entity
+    // type. If there is one, allow filtering the relation by bundle by using
+    // our own handler.
+    foreach (entity_get_info() as $type => $info) {
+      // In case we already join from the bundle entity we do not need to filter
+      // by bundle entity any more, so we stay with the general handler.
+      if (!empty($info['bundle of']) && $info['bundle of'] == $entity_type && $type != $left_type) {
+        return 'entity_views_handler_relationship_by_bundle';
+      }
+    }
+    return 'views_handler_relationship';
+  }
+
+  /**
+   * A callback returning property options, suitable to be used as views options callback.
+   */
+  public static function optionsListCallback($type, $selector, $op = 'view') {
+    $wrapper = entity_metadata_wrapper($type, NULL);
+    $parts = explode(':', $selector);
+    foreach ($parts as $part) {
+      $wrapper = $wrapper->get($part);
+    }
+    return $wrapper->optionsList($op);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/entity_views_example_query.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * @file
+ * Contains an example for a Views query plugin that could use the data selection tables.
+ */
+
+/**
+ * Describes the additional methods looked for on a query plugin if data selection based tables or fields are used.
+ *
+ * Only get_result_entities() needs to be present, so results can be retrieved.
+ * The other methods are optional.
+ *
+ * If the table does not contain entities, however, the get_result_wrappers()
+ * method is necessary, too. If this is the case and there are no relations to
+ * entity tables, the get_result_entities() method is not needed.
+ *
+ * @see entity_views_table_definition()
+ */
+abstract class entity_views_example_query extends views_plugin_query {
+
+  /**
+   * Add a sort to the query.
+   *
+   * This is used to add a sort based on an Entity API data selector instead
+   * of a field alias.
+   *
+   * This method has to be present if click-sorting on fields should be allowed
+   * for some fields using the default Entity API field handlers.
+   *
+   * @param $selector
+   *   The field to sort on, as an Entity API data selector.
+   * @param $order
+   *   The order to sort items in - either 'ASC' or 'DESC'. Defaults to 'ASC'.
+   */
+  public abstract function add_selector_orderby($selector, $order = 'ASC');
+
+  /**
+   * Returns the according entity objects for the given query results.
+   *
+   * This is compatible to the get_result_entities() method used by Views.
+   *
+   * The method is responsible for resolving the relationship and returning the
+   * entity objects for that relationship. The helper methods
+   * EntityFieldHandlerHelper::construct_property_selector() and
+   * EntityFieldHandlerHelper::extract_property_multiple() can be used to do
+   * this.
+   *
+   * @param $results
+   *   The results of the query, as returned by this query plugin.
+   * @param $relationship
+   *   (optional) A relationship for which the entities should be returned.
+   * @param $field
+   *   (optional) The field for which the entity should be returned. This is
+   *   only needed in case a field is derived via a referenced entity without
+   *   using a relationship. For example, if the node's field "author:name" is
+   *   used, the user entity would be returned instead of the node entity.
+   *
+   * @return
+   *   A numerically indexed array containing two items: the entity type of
+   *   entities returned by this method; and the array of entities, keyed by the
+   *   same indexes as the results.
+   *
+   * @see EntityFieldHandlerHelper::extract_property_multiple()
+   */
+  public abstract function get_result_entities($results, $relationship = NULL, $field = NULL);
+
+  /**
+   * Returns the according metadata wrappers for the given query results.
+   *
+   * This can be used if no entities for the results can be given, but entity
+   * metadata wrappers can be constructed for them.
+   *
+   * @param $results
+   *   The results of the query, as returned by this query plugin.
+   * @param $relationship
+   *   (optional) A relationship for which the wrappers should be returned.
+   * @param $field
+   *   (optional) The field of which a wrapper should be returned.
+   *
+   * @return
+   *   A numerically indexed array containing two items: the data type of
+   *   the wrappers returned by this method; and the array of retrieved
+   *   EntityMetadataWrapper objects, keyed by the same indexes as the results.
+   */
+  public abstract function get_result_wrappers($results, $relationship = NULL, $field = NULL);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_field_handler_helper.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,521 @@
+<?php
+
+/**
+ * @file
+ * Contains the EntityFieldHandlerHelper class.
+ */
+
+/**
+ * Helper class containing static implementations of common field handler methods.
+ *
+ * Used by the data selection entity field handlers to avoid code duplication.
+ *
+ * @see entity_views_table_definition()
+ */
+class EntityFieldHandlerHelper {
+
+  /**
+   * Provide appropriate default options for a handler.
+   */
+  public static function option_definition($handler) {
+    if (entity_property_list_extract_type($handler->definition['type'])) {
+      $options['list']['contains']['mode'] = array('default' => 'collapse');
+      $options['list']['contains']['separator'] = array('default' => ', ');
+      $options['list']['contains']['type'] = array('default' => 'ul');
+    }
+    $options['link_to_entity'] = array('default' => FALSE);
+
+    return $options;
+  }
+
+  /**
+   * Provide an appropriate default option form for a handler.
+   */
+  public static function options_form($handler, &$form, &$form_state) {
+    if (entity_property_list_extract_type($handler->definition['type'])) {
+      $form['list']['mode'] = array(
+        '#type' => 'select',
+        '#title' => t('List handling'),
+        '#options' => array(
+          'collapse' => t('Concatenate values using a seperator'),
+          'list' => t('Output values as list'),
+          'first' => t('Show first (if present)'),
+          'count' => t('Show item count'),
+        ),
+        '#default_value' => $handler->options['list']['mode'],
+      );
+      $form['list']['separator'] = array(
+        '#type' => 'textfield',
+        '#title' => t('List seperator'),
+        '#default_value' => $handler->options['list']['separator'],
+        '#dependency' => array('edit-options-list-mode' => array('collapse')),
+      );
+      $form['list']['type'] = array(
+        '#type' => 'select',
+        '#title' => t('List type'),
+        '#options' => array(
+          'ul' => t('Unordered'),
+          'ol' => t('Ordered'),
+        ),
+        '#default_value' => $handler->options['list']['type'],
+        '#dependency' => array('edit-options-list-mode' => array('list')),
+      );
+    }
+    $form['link_to_entity'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Link this field to its entity'),
+      '#description' => t("When using this, you should not set any other link on the field."),
+      '#default_value' => $handler->options['link_to_entity'],
+    );
+  }
+
+  /**
+   * Add the field for the entity ID (if necessary).
+   */
+  public static function query($handler) {
+    // Copied over from views_handler_field_entity::query().
+    // Sets table_alias (entity table), base_field (entity id field) and
+    // field_alias (the field's alias).
+    $handler->table_alias = $base_table = $handler->view->base_table;
+    $handler->base_field = $handler->view->base_field;
+
+    if (!empty($handler->relationship)) {
+      foreach ($handler->view->relationship as $relationship) {
+        if ($relationship->alias == $handler->relationship) {
+          $base_table = $relationship->definition['base'];
+          $handler->table_alias = $relationship->alias;
+
+          $table_data = views_fetch_data($base_table);
+          $handler->base_field = empty($relationship->definition['base field']) ? $table_data['table']['base']['field'] : $relationship->definition['base field'];
+        }
+      }
+    }
+
+    // Add the field if the query back-end implements an add_field() method,
+    // just like the default back-end.
+    if (method_exists($handler->query, 'add_field')) {
+      $handler->field_alias = $handler->query->add_field($handler->table_alias, $handler->base_field, '');
+    }
+    else {
+      // To ensure there is an alias just set the field alias to the real field.
+      $handler->field_alias = $handler->real_field;
+    }
+  }
+
+  /**
+   * Extracts the innermost field name from a data selector.
+   *
+   * @param $selector
+   *   The data selector.
+   *
+   * @return
+   *   The last component of the data selector.
+   */
+  public static function get_selector_field_name($selector) {
+    return ltrim(substr($selector, strrpos($selector, ':')), ':');
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   *
+   * @param $order
+   *   Either 'ASC' or 'DESC'.
+   */
+  public static function click_sort($handler, $order) {
+    // The normal orderby() method for this usually won't work here. So we need
+    // query plugins to provide their own method for this.
+    if (method_exists($handler->query, 'add_selector_orderby')) {
+      $selector = self::construct_property_selector($handler, TRUE);
+      $handler->query->add_selector_orderby($selector, $order);
+    }
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   *
+   * Automatically takes care of relationships, including data selection
+   * relationships. Results are written into @code $handler->wrappers @endcode
+   * and @code $handler->entity_type @endcode is set.
+   */
+  public static function pre_render($handler, &$values, $load_always = FALSE) {
+    if (empty($values)) {
+      return;
+    }
+    if (!$load_always && empty($handler->options['link_to_entity'])) {
+      // Check whether we even need to load the entities.
+      $selector = self::construct_property_selector($handler, TRUE);
+      $load = FALSE;
+      foreach ($values as $row) {
+        if (empty($row->_entity_properties) || !array_key_exists($selector, $row->_entity_properties)) {
+          $load = TRUE;
+          break;
+        }
+      }
+      if (!$load) {
+        return;
+      }
+    }
+
+    if (method_exists($handler->query, 'get_result_wrappers')) {
+      list($handler->entity_type, $handler->wrappers) = $handler->query->get_result_wrappers($values, $handler->relationship, $handler->real_field);
+    }
+    else {
+      list($handler->entity_type, $entities) = $handler->query->get_result_entities($values, $handler->relationship, $handler->real_field);
+      $handler->wrappers = array();
+      foreach ($entities as $id => $entity) {
+        $handler->wrappers[$id] = entity_metadata_wrapper($handler->entity_type, $entity);
+      }
+    }
+  }
+
+  /**
+   * Return an Entity API data selector for the given handler's relationship.
+   *
+   * A data selector is a concatenation of properties which should be followed
+   * to arrive at a desired property that may be nested in related entities or
+   * structures. The separate properties are herein concatenated with colons.
+   *
+   * For instance, a data selector of "author:roles" would mean to first
+   * access the "author" property of the given wrapper, and then for this new
+   * wrapper to access and return the "roles" property.
+   *
+   * Lists of entities are handled automatically by always returning only the
+   * first entity.
+   *
+   * @param $handler
+   *   The handler for which to construct the selector.
+   * @param $complete
+   *   If TRUE, the complete selector for the field is returned, not just the
+   *   one for its parent. Defaults to FALSE.
+   *
+   * @return
+   *   An Entity API data selector for the given handler's relationship.
+   */
+  public static function construct_property_selector($handler, $complete = FALSE) {
+    $return = '';
+    if ($handler->relationship) {
+      $current_handler = $handler;
+      $view = $current_handler->view;
+      while (!empty($current_handler->relationship) && !empty($view->relationship[$current_handler->relationship])) {
+        $current_handler = $view->relationship[$current_handler->relationship];
+        $return = $current_handler->real_field . ($return ? ":$return" : '');
+      }
+    }
+
+    if ($complete) {
+      $return .= ($return ? ':' : '') . $handler->real_field;
+    }
+    elseif ($pos = strrpos($handler->real_field, ':')) {
+      // If we have a selector as the real_field, append this to the returned
+      // relationship selector.
+      $return .= ($return ? ':' : '') . substr($handler->real_field, 0, $pos);
+    }
+
+    return $return;
+  }
+
+  /**
+   * Extracts data from several metadata wrappers based on a data selector.
+   *
+   * All metadata wrappers passed to this function have to be based on the exact
+   * same property information. The data will be returned wrapped by one or more
+   * metadata wrappers.
+   *
+   * Can be used in query plugins for the get_result_entities() and
+   * get_result_wrappers() methods.
+   *
+   * @param array $wrappers
+   *   The EntityMetadataWrapper objects from which to extract data.
+   * @param $selector
+   *   The selector specifying the data to extract.
+   *
+   * @return array
+   *   An array with numeric indices, containing the type of the extracted
+   *   wrappers in the first element. The second element of the array contains
+   *   the extracted property value(s) for each wrapper, keyed to the same key
+   *   that was used for the respecive wrapper in $wrappers. All extracted
+   *   properties are returned as metadata wrappers.
+   */
+  public static function extract_property_multiple(array $wrappers, $selector) {
+    $parts = explode(':', $selector, 2);
+    $name = $parts[0];
+
+    $results = array();
+    $entities = array();
+    $type = '';
+    foreach ($wrappers as $i => $wrapper) {
+      try {
+        $property = $wrapper->$name;
+        $type = $property->type();
+        if ($property instanceof EntityDrupalWrapper) {
+          // Remember the entity IDs to later load all at once (so as to
+          // properly utilize multiple load functionality).
+          $id = $property->getIdentifier();
+          // Only accept valid ids. $id can be FALSE for entity values that are
+          // NULL.
+          if ($id) {
+            $entities[$type][$i] = $id;
+          }
+        }
+        elseif ($property instanceof EntityStructureWrapper) {
+          $results[$i] = $property;
+        }
+        elseif ($property instanceof EntityListWrapper) {
+          foreach ($property as $item) {
+            $results[$i] = $item;
+            $type = $item->type();
+            break;
+          }
+        }
+        // Do nothing in case it cannot be applied.
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // Skip single empty properties.
+      }
+    }
+
+    if ($entities) {
+      // Map back the loaded entities back to the results array.
+      foreach ($entities as $type => $id_map) {
+        $loaded = entity_load($type, $id_map);
+        foreach ($id_map as $i => $id) {
+          if (isset($loaded[$id])) {
+            $results[$i] = entity_metadata_wrapper($type, $loaded[$id]);
+          }
+        }
+      }
+    }
+
+    // If there are no further parts in the selector, we are done now.
+    if (empty($parts[1])) {
+      return array($type, $results);
+    }
+    return self::extract_property_multiple($results, $parts[1]);
+  }
+
+  /**
+   * Get the value of a certain data selector.
+   *
+   * Uses $values->_entity_properties to look for already extracted properties.
+   *
+   * @param $handler
+   *   The field handler for which to return a value.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   * @param $field
+   *   The field to extract. If no value is given, the field of the given
+   *   handler is used instead. The special "entity object" value can be used to
+   *   get the base entity instead of a special field.
+   * @param $default
+   *   The value to return if the entity or field are not present.
+   */
+  public static function get_value($handler, $values, $field = NULL, $default = NULL) {
+    // There is a value cache on each handler so parent handlers rendering a
+    // single field value from a list will get the single value, not the whole
+    // list.
+    if (!isset($field) && isset($handler->current_value)) {
+      return $handler->current_value;
+    }
+    $field = isset($field) ? $field : self::get_selector_field_name($handler->real_field);
+    $selector = self::construct_property_selector($handler);
+    $selector = $selector ? "$selector:$field" : $field;
+    if (!isset($values->_entity_properties)) {
+      $values->_entity_properties = array();
+    }
+    if (!array_key_exists($selector, $values->_entity_properties)) {
+      if (!isset($handler->wrappers[$handler->view->row_index])) {
+        $values->_entity_properties[$selector] = $default;
+      }
+      elseif (is_array($handler->wrappers[$handler->view->row_index])) {
+        $values->_entity_properties[$selector] = self::extract_list_wrapper_values($handler->wrappers[$handler->view->row_index], $field);
+      }
+      else {
+        $wrapper = $handler->wrappers[$handler->view->row_index];
+        try {
+          if ($field === 'entity object') {
+            $values->_entity_properties[$selector] = $wrapper->value();
+          }
+          else {
+            $values->_entity_properties[$selector] = isset($wrapper->$field) ? $wrapper->$field->value(array('identifier' => TRUE)) : $default;
+          }
+        }
+        catch (EntityMetadataWrapperException $e) {
+          $values->_entity_properties[$selector] = $default;
+        }
+      }
+    }
+    return $values->_entity_properties[$selector];
+  }
+
+  /**
+   * Helper method for extracting the values from an array of wrappers.
+   *
+   * Nested arrays of wrappers are also handled, the values are returned in a
+   * flat (not nested) array.
+   */
+  public static function extract_list_wrapper_values(array $wrappers, $field) {
+    $return = array();
+    foreach ($wrappers as $wrapper) {
+      if (is_array($wrapper)) {
+        $values = self::extract_list_wrapper_values($wrapper, $field);
+        if ($values) {
+          $return = array_merge($return, $values);
+        }
+      }
+      else {
+        try {
+          if ($field == 'entity object') {
+            $return[] = $wrapper->value();
+          }
+          elseif (isset($wrapper->$field)) {
+            $return[] = $wrapper->$field->value(array('identifier' => TRUE));
+          }
+        }
+        catch (EntityMetadataWrapperException $e) {
+          // An exception probably signifies a non-present property, so we just
+          // ignore it.
+        }
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Render the field.
+   *
+   * Implements the entity link functionality and list handling. Basic handling
+   * of the single values is delegated back to the field handler.
+   *
+   * @param $handler
+   *   The field handler whose field should be rendered.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   *
+   * @return
+   *   The rendered value for the field.
+   */
+  public static function render($handler, $values) {
+    $value = $handler->get_value($values);
+    if (is_array($value)) {
+      return self::render_list($handler, $value, $values);
+    }
+    return self::render_entity_link($handler, $value, $values);
+  }
+
+  /**
+   * Render a list of values.
+   *
+   * @param $handler
+   *   The field handler whose field is rendered.
+   * @param $list
+   *   The list of values to render.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   *
+   * @return
+   *   The rendered value for the given list.
+   */
+  public static function render_list($handler, $list, $values) {
+    // Allow easy overriding of this behaviour in the specific field handler.
+    if (method_exists($handler, 'render_list')) {
+      return $handler->render_list($list, $values);
+    }
+    $mode = isset($handler->options['list']['mode']) ? $handler->options['list']['mode'] : NULL;
+    switch ($mode) {
+      case 'first':
+        $list = count($list) ? array_shift($list) : NULL;
+        if (is_array($list)) {
+          return self::render_list($handler, $list, $values);
+        }
+        elseif (isset($list)) {
+          return self::render_entity_link($handler, $list, $values);
+        }
+        return NULL;
+
+      case 'count':
+        return count($list);
+
+      // Handles both collapse and list output. Fallback is to collapse.
+      default:
+        $inner_values = array();
+        foreach ($list as $value) {
+          $value = is_array($value) ? self::render_list($handler, $value, $values) : self::render_entity_link($handler, $value, $values);
+          if ($value) {
+            $inner_values[] = $value;
+          }
+        }
+
+        // Format output as list.
+        if ($mode == 'list') {
+          $type = isset($handler->options['list']['type']) ? $handler->options['list']['type'] : 'ul';
+          return theme('item_list', array(
+            'items' => $inner_values,
+            'type' => $type,
+          ));
+        }
+
+        $separator = isset($handler->options['list']['separator']) ? $handler->options['list']['separator'] : ', ';
+        return implode($separator, $inner_values);
+    }
+  }
+
+  /**
+   * Render a single value as a link to the entity if applicable.
+   *
+   * @param $handler
+   *   The field handler whose field is rendered.
+   * @param $value
+   *   The single value to render.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   *
+   * @return
+   *   The rendered value.
+   */
+  public static function render_entity_link($handler, $value, $values) {
+    // Allow easy overriding of this behaviour in the specific field handler.
+    if (method_exists($handler, 'render_entity_link')) {
+      return $handler->render_entity_link($value, $values);
+    }
+    $render = self::render_single_value($handler, $value, $values);
+    if (!$handler->options['link_to_entity']) {
+      return $render;
+    }
+    $entity = $handler->get_value($values, 'entity object');
+    if (is_object($entity) && ($url = entity_uri($handler->entity_type, $entity))) {
+      return l($render, $url['path'], array('html' => TRUE) + $url['options']);
+    }
+    return $render;
+  }
+
+  /**
+   * Render a single value.
+   *
+   * @param $handler
+   *   The field handler whose field is rendered.
+   * @param $value
+   *   The single value to render.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   *
+   * @return
+   *   The rendered value.
+   */
+  public static function render_single_value($handler, $value, $values) {
+    // Try to use the method in the specific field handler.
+    if (method_exists($handler, 'render_single_value')) {
+      $handler->current_value = $value;
+      $return = $handler->render_single_value($value, $values);
+      unset($handler->current_value);
+      return $return;
+    }
+    // Default fallback in case the field handler doesn't provide the method.
+    return is_scalar($value) ? check_plain($value) : nl2br(check_plain(print_r($value, TRUE)));
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_area_entity.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,120 @@
+<?php
+/**
+ * @file
+ * Renders a full entity in a views area.
+ */
+
+class entity_views_handler_area_entity extends views_handler_area {
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options['entity_type'] = array('default' => 'node');
+    $options['entity_id'] = array('default' => '');
+    $options['view_mode'] = array('default' => 'full');
+    $options['bypass_access'] = array('default' => FALSE);
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $entity_type_options = array();
+    foreach (entity_get_info() as $entity_type => $entity_info) {
+      $entity_type_options[$entity_type] = $entity_info['label'];
+    }
+
+    $entity_type = $this->options['entity_type'];
+
+    $form['entity_type'] = array(
+      '#type' => 'select',
+      '#title' => t('Entity type'),
+      '#options' => $entity_type_options,
+      '#description' => t('Choose the entity type you want to display in the area.'),
+      '#default_value' => $entity_type,
+      '#ajax' => array(
+        'path' => views_ui_build_form_url($form_state),
+      ),
+      '#submit' => array('views_ui_config_item_form_submit_temporary'),
+      '#executes_submit_callback' => TRUE,
+    );
+
+    $form['entity_id'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Entity id'),
+      '#description' => t('Choose the entity you want to display in the area.'),
+      '#default_value' => $this->options['entity_id'],
+    );
+
+    if ($entity_type) {
+      $entity_info = entity_get_info($entity_type);
+      $options = array();
+      if (!empty($entity_info['view modes'])) {
+        foreach ($entity_info['view modes'] as $mode => $settings) {
+          $options[$mode] = $settings['label'];
+        }
+      }
+
+      if (count($options) > 1) {
+        $form['view_mode'] = array(
+          '#type' => 'select',
+          '#options' => $options,
+          '#title' => t('View mode'),
+          '#default_value' => $this->options['view_mode'],
+        );
+      }
+      else {
+        $form['view_mode_info'] = array(
+          '#type' => 'item',
+          '#title' => t('View mode'),
+          '#description' => t('Only one view mode is available for this entity type.'),
+          '#markup' => $options ? current($options) : t('Default'),
+        );
+        $form['view_mode'] = array(
+          '#type' => 'value',
+          '#value' => $options ? key($options) : 'default',
+        );
+      }
+    }
+    $form['bypass_access'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Bypass access checks'),
+      '#description' => t('If enabled, access permissions for rendering the entity are not checked.'),
+      '#default_value' => !empty($this->options['bypass_access']),
+    );
+    return $form;
+  }
+
+  public function admin_summary() {
+    $label = parent::admin_summary();
+    if (!empty($this->options['entity_id'])) {
+      return t('@label @entity_type:@entity_id', array(
+        '@label' => $label,
+        '@entity_type' => $this->options['entity_type'],
+        '@entity_id' => $this->options['entity_id'],
+      ));
+    }
+  }
+
+  public function render($empty = FALSE) {
+    if (!$empty || !empty($this->options['empty'])) {
+      return $this->render_entity($this->options['entity_type'], $this->options['entity_id'], $this->options['view_mode']);
+    }
+    return '';
+  }
+
+  /**
+   * Render an entity using the view mode.
+   */
+  public function render_entity($entity_type, $entity_id, $view_mode) {
+    if (!empty($entity_type) && !empty($entity_id) && !empty($view_mode)) {
+      $entity = entity_load_single($entity_type, $entity_id);
+      if (!empty($this->options['bypass_access']) || entity_access('view', $entity_type, $entity)) {
+        $render = entity_view($entity_type, array($entity), $view_mode);
+        $render_entity = reset($render);
+        return drupal_render($render_entity);
+      }
+    }
+    else {
+      return '';
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_boolean.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_boolean class.
+ */
+
+/**
+ * A handler to provide proper displays for booleans.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_boolean extends views_handler_field_boolean {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return parent::render($values);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_date.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_date class.
+ */
+
+/**
+ * A handler to provide proper displays for dates.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_date extends views_handler_field_date {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return parent::render($values);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_duration.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_duration class.
+ */
+
+/**
+ * A handler to provide proper displays for duration properties retrieved via data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_duration extends views_handler_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options += EntityFieldHandlerHelper::option_definition($this);
+
+    $options['format_interval'] = array('default' => TRUE);
+    $options['granularity'] = array('default' => 2);
+    $options['prefix'] = array('default' => '', 'translatable' => TRUE);
+    $options['suffix'] = array('default' => '', 'translatable' => TRUE);
+
+    return $options;
+  }
+
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+
+    $form['format_interval'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Format interval'),
+      '#description' => t('If checked, the value will be formatted as a time interval. Otherwise, just the number of seconds will be displayed.'),
+      '#default_value' => $this->options['format_interval'],
+    );
+    $form['granularity'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Granularity'),
+      '#default_value' => $this->options['granularity'],
+      '#description' => t('Specify how many different units to display.'),
+      '#dependency' => array('edit-options-format-interval' => array(TRUE)),
+      '#size' => 2,
+    );
+    $form['prefix'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Prefix'),
+      '#default_value' => $this->options['prefix'],
+      '#description' => t('Text to put before the duration text.'),
+    );
+    $form['suffix'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Suffix'),
+      '#default_value' => $this->options['suffix'],
+      '#description' => t('Text to put after the duration text.'),
+    );
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    if ($this->options['format_interval']) {
+      $value = format_interval($value, (int) $this->options['granularity']);
+    }
+    return $this->sanitize_value($this->options['prefix'], 'xss') .
+        $this->sanitize_value($value) .
+        $this->sanitize_value($this->options['suffix'], 'xss');
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_entity.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,207 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_entity class.
+ */
+
+/**
+ * A handler to provide proper displays for entities retrieved via data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_entity extends views_handler_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * The entity type of the entity displayed by this field.
+   */
+  public $field_entity_type;
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Initialize the entity type with the field's entity type.
+   */
+  public function init(&$view, &$options) {
+    parent::init($view, $options);
+    $this->field_entity_type = entity_property_extract_innermost_type($this->definition['type']);
+  }
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options += EntityFieldHandlerHelper::option_definition($this);
+
+    $options['display'] = array('default' => 'label');
+    $options['link_to_entity']['default'] = TRUE;
+    $options['view_mode'] = array('default' => 'default');
+    $options['bypass_access'] = array('default' => FALSE);
+
+    return $options;
+  }
+
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+    // We want a different form field at a different place.
+    unset($form['link_to_entity']);
+
+    $options = array(
+      'label' => t('Show entity label'),
+      'id' => t('Show entity ID'),
+      'view' => t('Show complete entity'),
+    );
+    $form['display'] = array(
+      '#type' => 'select',
+      '#title' => t('Display'),
+      '#description' => t('Decide how this field will be displayed.'),
+      '#options' => $options,
+      '#default_value' => $this->options['display'],
+    );
+    $form['link_to_entity'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Link to entity'),
+      '#description' => t('Link this field to the entity.'),
+      '#default_value' => $this->options['link_to_entity'],
+      '#dependency' => array('edit-options-display' => array('label', 'id')),
+    );
+
+    // Stolen from entity_views_plugin_row_entity_view.
+    $entity_info = entity_get_info($this->field_entity_type);
+    $options = array();
+    if (!empty($entity_info['view modes'])) {
+      foreach ($entity_info['view modes'] as $mode => $settings) {
+        $options[$mode] = $settings['label'];
+      }
+    }
+
+    if (count($options) > 1) {
+      $form['view_mode'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#title' => t('View mode'),
+        '#default_value' => $this->options['view_mode'],
+        '#dependency' => array('edit-options-display' => array('view')),
+      );
+    }
+    else {
+      $form['view_mode'] = array(
+        '#type' => 'value',
+        '#value' => $options ? key($options) : 'default',
+      );
+    }
+    $form['bypass_access'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Bypass access checks'),
+      '#description' => t('If enabled, access permissions for rendering the entity are not checked.'),
+      '#default_value' => !empty($this->options['bypass_access']),
+    );
+  }
+
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a value as a link to the entity if applicable.
+   *
+   * @param $value
+   *   The value to render.
+   * @param $values
+   *   The values for the current row retrieved from the Views query, as an
+   *   object.
+   */
+  public function render_entity_link($entity, $values) {
+    $type = $this->field_entity_type;
+    if (!is_object($entity) && isset($entity) && $entity !== FALSE) {
+      $entity = entity_load_single($type, $entity);
+    }
+    if (!$entity) {
+      return '';
+    }
+    $render = $this->render_single_value($entity, $values);
+    if (!$this->options['link_to_entity'] || $this->options['display'] == 'view') {
+      return $render;
+    }
+    if (is_object($entity) && ($url = entity_uri($type, $entity))) {
+      return l($render, $url['path'], array('html' => TRUE) + $url['options']);
+    }
+    return $render;
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($entity, $values) {
+    $type = $this->field_entity_type;
+    if (!is_object($entity) && isset($entity) && $entity !== FALSE) {
+      $entity = entity_load_single($type, $entity);
+    }
+    // Make sure the entity exists and access is either given or bypassed.
+    if (!$entity || !(!empty($this->options['bypass_access']) || entity_access('view', $type, $entity))) {
+      return '';
+    }
+
+    if ($this->options['display'] === 'view') {
+      $entity_view = entity_view($type, array($entity), $this->options['view_mode']);
+      return render($entity_view);
+    }
+
+    if ($this->options['display'] == 'label') {
+      $value = entity_label($type, $entity);
+    }
+    // Either $options[display] == 'id', or we have no label.
+    if (empty($value)) {
+      $value = entity_id($type, $entity);
+    }
+    $value = $this->sanitize_value($value);
+
+    return $value;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_field class.
+ */
+
+/**
+ * A handler to provide proper displays for Field API fields.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_field extends views_handler_field_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * The entity for which this field is currently rendered.
+   */
+  public $entity;
+
+  /**
+   * Return TRUE if the user has access to view this field.
+   */
+  public function access() {
+    return field_access('view', $this->field_info, $this->definition['entity type']);
+  }
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query($use_groupby = FALSE) {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Override so it doesn't do any harm (or, anything at all).
+   */
+  public function post_execute(&$values) { }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values, TRUE);
+  }
+
+  /**
+   * Overridden to get the items our way.
+   */
+  public function get_items($values) {
+    $items = array();
+    // Set the entity type for the parent handler.
+    $values->_field_data[$this->field_alias]['entity_type'] = $this->entity_type;
+    // We need special handling for lists of entities as the base.
+    $entities = EntityFieldHandlerHelper::get_value($this, $values, 'entity object');
+    if (!is_array($entities)) {
+      $entities = $entities ? array($entities) : array();
+    }
+    foreach ($entities as $entity) {
+      // Only try to render the field if it is even present on this bundle.
+      // Otherwise, field_view_field() will trigger a fatal.
+      list (, , $bundle) = entity_extract_ids($this->entity_type, $entity);
+      if (field_info_instance($this->entity_type, $this->definition['field_name'], $bundle)) {
+        // Set the currently rendered entity.
+        $values->_field_data[$this->field_alias]['entity'] = $entity;
+        $items = array_merge($items, $this->set_items($values, $this->view->row_index));
+      }
+    }
+    return $items;
+  }
+
+  /**
+   * Overridden to force displaying multiple values in a single row.
+   */
+  function multiple_options_form(&$form, &$form_state) {
+    parent::multiple_options_form($form, $form_state);
+    $form['group_rows']['#default_value'] = TRUE;
+    $form['group_rows']['#disabled'] = TRUE;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_numeric.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_numeric class.
+ */
+
+/**
+ * Render a field as a numeric value.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_numeric extends views_handler_field_numeric {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return parent::render($values);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_options.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_options class.
+ */
+
+/**
+ * A handler to provide proper displays for values chosen from a set of options.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_options extends views_handler_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * The key / name mapping for the options.
+   */
+  public $option_list;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Specifies the options this handler uses.
+   */
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options += EntityFieldHandlerHelper::option_definition($this);
+    $options['format_name'] = array('default' => TRUE);
+    return $options;
+  }
+
+  /**
+   * Returns an option form for setting this handler's options.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+
+    $form['format_name'] = array(
+      '#title' => t('Use human-readable name'),
+      '#type' => 'checkbox',
+      '#description' => t("If this is checked, the values' names will be displayed instead of their internal identifiers."),
+      '#default_value' => $this->options['format_name'],
+      '#weight' => -5,
+    );
+  }
+
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    if (!isset($this->option_list)) {
+      $this->option_list = array();
+      $callback = $this->definition['options callback'];
+      if (is_callable($callback['function'])) {
+        // If a selector is used, get the name of the selected field.
+        $field_name = EntityFieldHandlerHelper::get_selector_field_name($this->real_field);
+        $this->option_list = call_user_func($callback['function'], $field_name, $callback['info'], 'view');
+      }
+    }
+    if ($this->options['format_name'] && isset($this->option_list[$value])) {
+      $value = $this->option_list[$value];
+    }
+
+    return $this->sanitize_value($value);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_text.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_text class.
+ */
+
+/**
+ * A handler to display text data.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_text extends views_handler_field {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return $this->sanitize_value($value, 'xss');
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_field_uri.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_field_uri class.
+ */
+
+/**
+ * Field handler to provide simple renderer that turns a URL into a clickable link.
+ *
+ * Overrides the default Views handler to retrieve the data from an entity via
+ * data selection.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_field_uri extends views_handler_field_url {
+
+  /**
+   * Stores the entity type of the result entities.
+   */
+  public $entity_type;
+
+  /**
+   * Stores the result entities' metadata wrappers.
+   */
+  public $wrappers = array();
+
+  /**
+   * Stores the current value when rendering list fields.
+   */
+  public $current_value;
+
+  /**
+   * Overridden to add the field for the entity ID (if necessary).
+   */
+  public function query() {
+    EntityFieldHandlerHelper::query($this);
+  }
+
+  /**
+   * Adds a click-sort to the query.
+   */
+  public function click_sort($order) {
+    EntityFieldHandlerHelper::click_sort($this, $order);
+  }
+
+  /**
+   * Load the entities for all rows that are about to be displayed.
+   */
+  public function pre_render(&$values) {
+    parent::pre_render($values);
+    EntityFieldHandlerHelper::pre_render($this, $values);
+  }
+
+  /**
+   * Overridden to use a metadata wrapper.
+   */
+  public function get_value($values, $field = NULL) {
+    return EntityFieldHandlerHelper::get_value($this, $values, $field);
+  }
+
+  /**
+   * Provide options for this handler.
+   */
+  public function option_definition() {
+    return parent::option_definition() + EntityFieldHandlerHelper::option_definition($this);
+  }
+
+  /**
+   * Provide a options form for this handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    EntityFieldHandlerHelper::options_form($this, $form, $form_state);
+  }
+
+  /**
+   * Render the field.
+   *
+   * @param $values
+   *   The values retrieved from the database.
+   */
+  public function render($values) {
+    return EntityFieldHandlerHelper::render($this, $values);
+  }
+
+  /**
+   * Render a single field value.
+   */
+  public function render_single_value($value, $values) {
+    return parent::render($values);
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_relationship.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains the entity_views_handler_relationship class.
+ */
+
+/**
+ * Relationship handler for data selection tables.
+ *
+ * This handler may only be used in conjunction with data selection based Views
+ * tables or other base tables using a query plugin that supports data
+ * selection.
+ *
+ * @see entity_views_field_definition()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_relationship extends views_handler_relationship {
+
+  /**
+   * Slightly modify the options form provided by the parent handler.
+   */
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    // This won't work with data selector-based relationships, as we only
+    // inspect those *after* the results are known.
+    $form['required']['#access'] = FALSE;
+    // Notify the user of our restrictions regarding lists of entities, if
+    // appropriate.
+    if (!empty($this->definition['multiple'])) {
+      $form['multiple_note'] = array(
+        '#markup' => t('<strong>Note:</strong> This is a multi-valued relationship, which is currently not supported. ' .
+            'Only the first related entity will be shown.'),
+        '#weight' => -5,
+      );
+    }
+  }
+
+  /**
+   * Called to implement a relationship in a query.
+   *
+   * As we don't add any data to the query itself, we don't have to do anything
+   * here. Views just don't thinks we have been called unless we set our
+   * $alias property. Otherwise, this override is just here to keep PHP from
+   * blowing up by calling inexistent methods on the query plugin.
+   */
+  public function query() {
+    $this->alias = $this->options['id'];
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/handlers/entity_views_handler_relationship_by_bundle.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,117 @@
+<?php
+/**
+ * @file
+ * Contains the entity_views_handler_relationship_by_bundle class.
+ */
+
+/**
+ * Relationship handler for entity relationships that may limit the join to one or more bundles.
+ *
+ * This handler is only applicable for entities that are using bundle entities,
+ * i.e. entities having the 'bundle of' entity info key set.
+ *
+ * For example, this allows a relationship from users to profiles of a certain
+ * profile type.
+ *
+ * @see entity_crud_hook_entity_info()
+ * @ingroup views_field_handlers
+ */
+class entity_views_handler_relationship_by_bundle extends views_handler_relationship {
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['bundle_types'] = array('default' => array());
+
+    return $options;
+  }
+
+  /**
+   * Add an entity type option.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Get the entity type and info from the table data for the base on the
+    // right hand side of the relationship join.
+    $table_data = views_fetch_data($this->definition['base']);
+    $entity_type = $table_data['table']['entity type'];
+    $entity_info = entity_get_info($entity_type);
+
+    // Get the info of the bundle entity.
+    foreach (entity_get_info() as $type => $info) {
+      if (isset($info['bundle of']) && $info['bundle of'] == $entity_type) {
+        $entity_bundle_info = $info;
+        break;
+      }
+    }
+
+    $plural_label = isset($entity_bundle_info['plural label']) ? $entity_bundle_info['plural label'] : $entity_bundle_info['label'] . 's';
+    $bundle_options = array();
+    foreach ($entity_info['bundles'] as $name => $info) {
+      $bundle_options[$name] = $info['label'];
+    }
+
+    $form['bundle_types'] = array(
+      '#title' => $plural_label,
+      '#type' => 'checkboxes',
+      '#description' => t('Restrict this relationship to one or more @bundles.', array('@bundles' => strtolower($entity_bundle_info['plural label']))),
+      '#options' => $bundle_options,
+      '#default_value' => $this->options['bundle_types'],
+    );
+  }
+
+  /**
+   * Make sure only checked bundle types are left.
+   */
+  function options_submit(&$form, &$form_state) {
+    $form_state['values']['options']['bundle_types'] = array_filter($form_state['values']['options']['bundle_types']);
+    parent::options_submit($form, $form_state);
+  }
+
+  /**
+   * Called to implement a relationship in a query.
+   *
+   * Mostly the same as the parent method, except we add an extra clause to
+   * the join.
+   */
+  function query() {
+    $table_data = views_fetch_data($this->definition['base']);
+    $base_field = empty($this->definition['base field']) ? $table_data['table']['base']['field'] : $this->definition['base field'];
+    $this->ensure_my_table();
+
+    $def = $this->definition;
+    $def['table'] = $this->definition['base'];
+    $def['field'] = $base_field;
+    $def['left_table'] = $this->table_alias;
+    $def['left_field'] = $this->field;
+    if (!empty($this->options['required'])) {
+      $def['type'] = 'INNER';
+    }
+
+    // Add an extra clause to the join if there are bundle types selected.
+    if ($this->options['bundle_types']) {
+      $entity_info = entity_get_info($table_data['table']['entity type']);
+      $def['extra'] = array(
+        array(
+          // The table and the IN operator are implicit.
+          'field' => $entity_info['bundle keys']['bundle'],
+          'value' => $this->options['bundle_types'],
+        ),
+      );
+    }
+
+    if (!empty($def['join_handler']) && class_exists($def['join_handler'])) {
+      $join = new $def['join_handler'];
+    }
+    else {
+      $join = new views_join();
+    }
+
+    $join->definition = $def;
+    $join->construct();
+    $join->adjusted = TRUE;
+
+    // Use a short alias for this.
+    $alias = $def['table'] . '_' . $this->table;
+    $this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entity/views/plugins/entity_views_plugin_row_entity_view.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * @file
+ * Row style plugin for displaying the results as entities.
+ */
+
+/**
+ * Plugin class for displaying Views results with entity_view.
+ */
+class entity_views_plugin_row_entity_view extends views_plugin_row {
+
+  protected $entity_type, $entities;
+
+  public function init(&$view, &$display, $options = NULL) {
+    parent::init($view, $display, $options);
+
+    // Initialize the entity-type used.
+    $table_data = views_fetch_data($this->view->base_table);
+    $this->entity_type = $table_data['table']['entity type'];
+    // Set base table and field information as used by views_plugin_row to
+    // select the entity id if used with default query class.
+    $info = entity_get_info($this->entity_type);
+    if (!empty($info['base table']) && $info['base table'] == $this->view->base_table) {
+      $this->base_table = $info['base table'];
+      $this->base_field = $info['entity keys']['id'];
+    }
+  }
+
+  public function option_definition() {
+    $options = parent::option_definition();
+    $options['view_mode'] = array('default' => 'full');
+    return $options;
+  }
+
+  public function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $entity_info = entity_get_info($this->entity_type);
+    $options = array();
+    if (!empty($entity_info['view modes'])) {
+      foreach ($entity_info['view modes'] as $mode => $settings) {
+        $options[$mode] = $settings['label'];
+      }
+    }
+
+    if (count($options) > 1) {
+      $form['view_mode'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#title' => t('View mode'),
+        '#default_value' => $this->options['view_mode'],
+      );
+    }
+    else {
+      $form['view_mode_info'] = array(
+        '#type' => 'item',
+        '#title' => t('View mode'),
+        '#description' => t('Only one view mode is available for this entity type.'),
+        '#markup' => $options ? current($options) : t('Default'),
+      );
+      $form['view_mode'] = array(
+        '#type' => 'value',
+        '#value' => $options ? key($options) : 'default',
+      );
+    }
+    return $form;
+  }
+
+  public function pre_render($values) {
+    if (!empty($values)) {
+      list($this->entity_type, $this->entities) = $this->view->query->get_result_entities($values, !empty($this->relationship) ? $this->relationship : NULL, isset($this->field_alias) ? $this->field_alias : NULL);
+    }
+    // Render the entities.
+    if ($this->entities) {
+      $render = entity_view($this->entity_type, $this->entities, $this->options['view_mode']);
+      // Remove the first level of the render array.
+      $this->rendered_content = reset($render);
+    }
+  }
+
+  /**
+   * Overridden to return the entity object.
+   */
+  function get_value($values, $field = NULL) {
+    return isset($this->entities[$this->view->row_index]) ? $this->entities[$this->view->row_index] : FALSE;
+  }
+
+  public function render($values) {
+    if ($entity = $this->get_value($values)) {
+      $render = $this->rendered_content[entity_id($this->entity_type, $entity)];
+      return drupal_render($render);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,16 @@
+DESCRIPTION
+===========
+Provides a field type that can reference arbitrary entities.
+
+SITE BUILDERS
+=============
+Note that when using a select widget, Entity reference loads all the
+entities in that list in order to get the entity's label. If there are
+too many loaded entities that site might reach its memory limit and crash
+(also known as WSOD). In such a case you are advised to change the widget
+to "autocomplete". If you get a WSOD when trying to edit the field
+settings, you can reach the widget settings directly by navigation to
+
+  admin/structure/types/manage/[ENTITY-TYPE]/fields/[FIELD-NAME]/widget-type
+
+Replace ENTITY-TYPE and FIELD_NAME with the correct values.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/entityreference.admin.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,4 @@
+
+.entityreference-settings {
+  margin-left: 1.5em;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/entityreference.devel_generate.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * @file
+ * Support for processing entity reference fields in devel generate.
+ */
+
+function entityreference_devel_generate($object, $field, $instance, $bundle) {
+  if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
+    return devel_generate_multiple('_entityreference_devel_generate', $object, $field, $instance, $bundle);
+  }
+  else {
+    return _entityreference_devel_generate($object, $field, $instance, $bundle);
+  }
+}
+
+function _entityreference_devel_generate($object, $field, $instance, $bundle) {
+  $object_field = array();
+  // Get all the entity that are referencable here.
+  $referencable_entity = entityreference_get_selection_handler($field, $instance)->getReferencableEntities();
+  if (is_array($referencable_entity) && !empty($referencable_entity)) {
+    // Get a random key.
+    $object_field['target_id'] = array_rand($referencable_entity);
+  }
+  return $object_field;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/entityreference.diff.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Provide Diff module field callbacks for the Entity Reference module.
+ */
+
+/**
+ * Diff field callback for preloading entities.
+ */
+function entityreference_field_diff_view_prepare(&$old_items, &$new_items, $context) {
+  $field = $context['field'];
+
+  // Build an array of entities ID.
+  $entity_ids = array();
+  foreach (array_merge_recursive($old_items, $new_items) as $item) {
+    $entity_ids[] = $item['target_id'];
+  }
+
+  // Load those entities and loop through them to extract their labels.
+  $entities = entity_load($field['settings']['target_type'], $entity_ids);
+
+  foreach ($old_items as $delta => $info) {
+    $old_items[$delta]['entity'] = isset($entities[$info['target_id']]) ? $entities[$info['target_id']] : NULL;
+  }
+  foreach ($new_items as $delta => $info) {
+    $new_items[$delta]['entity'] = isset($entities[$info['target_id']]) ? $entities[$info['target_id']] : NULL;
+  }
+}
+
+/**
+ * Diff field callback for parsing entity field comparative values.
+ */
+function entityreference_field_diff_view($items, $context) {
+  $field = $context['field'];
+  $instance = $context['instance'];
+  $settings = $context['settings'];
+  $entity_type = $field['settings']['target_type'];
+
+  $diff_items = array();
+
+  // We populate as much as possible to allow the best flexability in any
+  // string overrides.
+  $t_args = array();
+  $t_args['!entity_type'] = $entity_type;
+
+  $entity_info = entity_get_info($entity_type);
+  $t_args['!entity_type_label'] = $entity_info['label'];
+
+  foreach ($items as $delta => $item) {
+    if (isset($item['entity'])) {
+      $output = array();
+
+      list($id,, $bundle) = entity_extract_ids($entity_type, $item['entity']);
+      $t_args['!id'] = $id;
+      $t_args['!bundle'] = $bundle;
+      $t_args['!diff_entity_label'] = entity_label($entity_type, $item['entity']);
+
+      $output['entity'] = t('!diff_entity_label', $t_args);
+      if ($settings['show_id']) {
+        $output['id'] = t('ID: !id', $t_args);
+      }
+      $diff_items[$delta] = implode('; ', $output);
+    }
+  }
+
+  return $diff_items;
+}
+
+/**
+ * Provide default field comparison options.
+ */
+function entityreference_field_diff_default_options($field_type) {
+  return array(
+    'show_id' => 0,
+  );
+}
+
+/**
+ * Provide a form for setting the field comparison options.
+ */
+function entityreference_field_diff_options_form($field_type, $settings) {
+  $options_form = array();
+  $options_form['show_id'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Show ID'),
+    '#default_value' => $settings['show_id'],
+  );
+  return $options_form;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/entityreference.feeds.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * @file
+ * Feeds mapping implementation for the Entity reference module
+ */
+
+/**
+ * Implements hook_feeds_processor_targets_alter().
+ *
+ * @see FeedsNodeProcessor::getMappingTargets().
+ */
+function entityreference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+
+  foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
+    $info = field_info_field($name);
+    if ($info['type'] == 'entityreference') {
+      $targets[$name] = array(
+        'name'        => check_plain($instance['label']),
+        'callback'    => 'entityreference_feeds_set_target',
+        'description' => t('The field instance @label of @id', array(
+          '@label' => $instance['label'],
+          '@id'    => $name,
+        )),
+      );
+    }
+  }
+}
+
+/**
+ * Entity reference callback for mapping.
+ *
+ * When the callback is invoked, $target contains the name of the field the
+ * user has decided to map to and $value contains the value of the feed item
+ * element the user has picked as a source.
+ *
+ * @param $source
+ *   A FeedsSource object.
+ * @param $entity
+ *   The entity to map to.
+ * @param $target
+ *   The target key on $entity to map to.
+ * @param $value
+ *   The value to map. MUST be an array.
+ * @param $mapping
+ *   Array of mapping settings for current value.
+ * @param $input_format
+ *   TRUE if an input format should be applied.
+ */
+function entityreference_feeds_set_target($source, $entity, $target, $value, $mapping, $input_format = FALSE) {
+
+  // Don't do anything if we weren't given any data.
+  if (empty($value)) {
+    return;
+  }
+
+  // Assume that the passed in value could really be any number of values.
+  if (is_array($value)) {
+    $values = $value;
+  }
+  else {
+    $values = array($value);
+  }
+
+  // Get some useful field information.
+  $info = field_info_field($target);
+
+  // Set the language of the field depending on the mapping.
+  $language = isset($mapping['language']) ? $mapping['language'] : LANGUAGE_NONE;
+
+  // Iterate over all values.
+  $iterator = 0;
+  $field = isset($entity->$target) ? $entity->$target : array();
+  foreach ($values as $value) {
+
+    // Only process if this value was set for this instance.
+    if ($value) {
+
+      // Fetch the entity ID resulting from the mapping table look-up.
+      $entity_id = db_query(
+        'SELECT entity_id FROM {feeds_item} WHERE guid = :guid',
+        array(':guid' => $value)
+      )->fetchField();
+
+      /*
+       * Only add a reference to an existing entity ID if there exists a
+       * mapping between it and the provided GUID.  In cases where no such
+       * mapping exists (yet), don't do anything here.  There may be a mapping
+       * defined later in the CSV file.  If so, and the user re-runs the import
+       * (as a second pass), we can add this reference then.  (The "Update
+       * existing nodes" option must be selected during the second pass.)
+       */
+      if ($entity_id) {
+
+        // Assign the target ID.
+        $field[$language][$iterator]['target_id']   = $entity_id;
+      }
+      else /* there is no $entity_id, no mapping */ {
+
+        /*
+         * Feeds stores a hash of every line imported from CSVs in order to
+         * make the import process more efficient by ignoring lines it's
+         * already seen.  We need to short-circuit this process in this case
+         * because users may want to re-import the same line as an update later
+         * when (and if) a map to a reference exists.  So in order to provide
+         * this opportunity later, we need to destroy the hash.
+         */
+        unset($entity->feeds_item->hash);
+      }
+    }
+
+    // Break out of the loop if this field is single-valued.
+    if ($info['cardinality'] == 1) {
+      break;
+    }
+    $iterator++;
+  }
+
+  // Add the field to the entity definition.
+  $entity->{$target} = $field;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/entityreference.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,30 @@
+name = Entity Reference
+description = Provides a field that can reference other entities.
+core = 7.x
+package = Fields
+dependencies[] = entity
+dependencies[] = ctools
+
+; Migrate handler.
+files[] = entityreference.migrate.inc
+
+; Our plugins interfaces and abstract implementations.
+files[] = plugins/selection/abstract.inc
+files[] = plugins/selection/views.inc
+files[] = plugins/behavior/abstract.inc
+
+files[] = views/entityreference_plugin_display.inc
+files[] = views/entityreference_plugin_style.inc
+files[] = views/entityreference_plugin_row_fields.inc
+
+; Tests.
+files[] = tests/entityreference.handlers.test
+files[] = tests/entityreference.taxonomy.test
+files[] = tests/entityreference.admin.test
+
+; Information added by drupal.org packaging script on 2012-11-18
+version = "7.x-1.0"
+core = "7.x"
+project = "entityreference"
+datestamp = "1353230808"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/entityreference.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * Implements hook_uninstall().
+ */
+function entityreference_uninstall() {
+  variable_del('entityreference:base-tables');
+}
+
+/**
+ * Implements hook_field_schema().
+ */
+function entityreference_field_schema($field) {
+  if ($field['type'] == 'entityreference') {
+    // Load the base table configuration from the cache.
+    $base_tables = variable_get('entityreference:base-tables', array());
+
+    $schema = array(
+      'columns' => array(
+        'target_id' => array(
+          'description' => 'The id of the target entity.',
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        ),
+      ),
+      'indexes' => array(
+        'target_id' => array('target_id'),
+      ),
+      'foreign keys' => array(),
+    );
+
+    // Create a foreign key to the target entity type base type, if available.
+    $entity_type = $field['settings']['target_type'];
+    if (isset($base_tables[$entity_type])) {
+      list($base_table, $id_column) = $base_tables[$entity_type];
+      $schema['foreign keys'][$base_table] = array(
+        'table' => $base_table,
+        'columns' => array('target_id' => $id_column),
+      );
+    }
+
+    // Invoke the behaviors to allow them to change the schema.
+    foreach (entityreference_get_behavior_handlers($field) as $handler) {
+      $handler->schema_alter($schema, $field);
+    }
+
+    return $schema;
+  }
+}
+
+/**
+ * Update the field configuration to the new plugin structure.
+ */
+function entityreference_update_7000() {
+  // Enable ctools.
+  if (!module_enable(array('ctools'))) {
+    throw new DrupalUpdateException('This version of Entity Reference requires ctools, but it could not be enabled.');
+  }
+
+  // Get the list of fields of type 'entityreference'.
+  $fields = array();
+  foreach (field_info_fields() as $field_name => $field) {
+    // Update the field configuration.
+    if ($field['type'] == 'entityreference') {
+      $settings = &$field['settings'];
+      if (!isset($settings['handler'])) {
+        $settings['handler'] = 'base';
+        $settings['handler_settings']['target_bundles'] = $settings['target_bundles'];
+        unset($settings['target_bundles']);
+        field_update_field($field);
+      }
+    }
+
+    // Update the instance configurations.
+    foreach ($field['bundles'] as $entity_type => $bundles) {
+      foreach ($bundles as $bundle) {
+        $instance = field_info_instance($entity_type, $field_name, $bundle);
+        $save = FALSE;
+        if ($instance['widget']['type'] == 'entityreference_autocomplete') {
+          $instance['widget']['type'] = 'entityreference_autocomplete_tags';
+          $save = TRUE;
+        }
+        // When the autocomplete path is the default value, remove it from
+        // the configuration.
+        if (isset($instance['widget']['settings']['path']) && $instance['widget']['settings']['path'] == 'entityreference/autocomplete') {
+          unset($instance['widget']['settings']['path']);
+          $save = TRUE;
+        }
+        if ($save) {
+          field_update_instance($instance);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Drop "target_type" from the field schema.
+ */
+function entityreference_update_7001() {
+  if (!module_exists('field_sql_storage')) {
+    return;
+  }
+  foreach (field_info_fields() as $field_name => $field) {
+    if ($field['type'] != 'entityreference') {
+      // Not an entity reference field.
+      continue;
+    }
+
+    // Update the field settings.
+    $field = field_info_field($field_name);
+    unset($field['indexes']['target_entity']);
+    $field['indexes']['target_id'] = array('target_id');
+    field_update_field($field);
+
+    if ($field['storage']['type'] !== 'field_sql_storage') {
+      // Field doesn't use SQL storage, we cannot modify the schema.
+      continue;
+    }
+    $table_name = _field_sql_storage_tablename($field);
+    $revision_name = _field_sql_storage_revision_tablename($field);
+
+    db_drop_index($table_name, $field_name . '_target_entity');
+    db_drop_index($table_name, $field_name . '_target_id');
+    db_drop_field($table_name, $field_name . '_target_type');
+    db_add_index($table_name, $field_name . '_target_id', array($field_name . '_target_id'));
+
+    db_drop_index($revision_name, $field_name . '_target_entity');
+    db_drop_index($revision_name, $field_name . '_target_id');
+    db_drop_field($revision_name, $field_name . '_target_type');
+    db_add_index($revision_name, $field_name . '_target_id', array($field_name . '_target_id'));
+  }
+}
+
+/**
+ * Make the target_id column NOT NULL.
+ */
+function entityreference_update_7002() {
+  if (!module_exists('field_sql_storage')) {
+    return;
+  }
+  foreach (field_info_fields() as $field_name => $field) {
+    if ($field['type'] != 'entityreference') {
+      // Not an entity reference field.
+      continue;
+    }
+
+    if ($field['storage']['type'] !== 'field_sql_storage') {
+      // Field doesn't use SQL storage, we cannot modify the schema.
+      continue;
+    }
+
+    $table_name = _field_sql_storage_tablename($field);
+    $revision_name = _field_sql_storage_revision_tablename($field);
+
+    db_change_field($table_name, $field_name . '_target_id', $field_name . '_target_id', array(
+      'description' => 'The id of the target entity.',
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+    ));
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/entityreference.migrate.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Support for processing entity reference fields in Migrate.
+ */
+
+/**
+ * Implement hook_migrate_api().
+ */
+function entityreference_migrate_api() {
+  return array(
+    'api' => 2,
+    'field_handlers' => array('MigrateEntityReferenceFieldHandler'),
+  );
+}
+
+class MigrateEntityReferenceFieldHandler extends MigrateSimpleFieldHandler {
+  public function __construct() {
+    parent::__construct(array(
+      'value_key' => 'target_id',
+      'skip_empty' => TRUE,
+    ));
+
+    $this->registerTypes(array('entityreference'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/entityreference.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1270 @@
+<?php
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function entityreference_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'entityreference') {
+    return 'plugins/' . $plugin;
+  }
+}
+
+/**
+ * Implements hook_init().
+ */
+function entityreference_init() {
+  // Include feeds.module integration.
+  if (module_exists('feeds')) {
+    module_load_include('inc', 'entityreference', 'entityreference.feeds');
+  }
+}
+
+/**
+ * Implements hook_ctools_plugin_type().
+ */
+function entityreference_ctools_plugin_type() {
+  $plugins['selection'] = array(
+    'classes' => array('class'),
+  );
+  $plugins['behavior'] = array(
+    'classes' => array('class'),
+    'process' => 'entityreference_behavior_plugin_process',
+  );
+  return $plugins;
+}
+
+/**
+ * CTools callback; Process the behavoir plugins.
+ */
+function entityreference_behavior_plugin_process(&$plugin, $info) {
+  $plugin += array(
+    'description' => '',
+    'behavior type' => 'field',
+    'access callback' => FALSE,
+    'force enabled' => FALSE,
+  );
+}
+
+/**
+ * Implements hook_field_info().
+ */
+function entityreference_field_info() {
+  $field_info['entityreference'] = array(
+    'label' => t('Entity Reference'),
+    'description' => t('This field reference another entity.'),
+    'settings' => array(
+      // Default to the core target entity type node.
+      'target_type' => 'node',
+      // The handler for this field.
+      'handler' => 'base',
+      // The handler settings.
+      'handler_settings' => array(),
+    ),
+    'instance_settings' => array(),
+    'default_widget' => 'entityreference_autocomplete',
+    'default_formatter' => 'entityreference_label',
+    'property_callbacks' => array('entityreference_field_property_callback'),
+  );
+  return $field_info;
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function entityreference_flush_caches() {
+  // Because of the intricacies of the info hooks, we are forced to keep a
+  // separate list of the base tables of each entities, so that we can use
+  // it in entityreference_field_schema() without calling entity_get_info().
+  // See http://drupal.org/node/1416558 for details.
+  $base_tables = array();
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if (!empty($entity_info['base table']) && !empty($entity_info['entity keys']['id'])) {
+      $base_tables[$entity_type] = array($entity_info['base table'], $entity_info['entity keys']['id']);
+    }
+  }
+  // We are using a variable because cache is going to be cleared right after
+  // hook_flush_caches() is finished.
+  variable_set('entityreference:base-tables', $base_tables);
+}
+
+/**
+ * Implements hook_menu().
+ */
+function entityreference_menu() {
+  $items = array();
+
+  $items['entityreference/autocomplete/single/%/%/%'] = array(
+    'title' => 'Entity Reference Autocomplete',
+    'page callback' => 'entityreference_autocomplete_callback',
+    'page arguments' => array(2, 3, 4, 5),
+    'access callback' => 'entityreference_autocomplete_access_callback',
+    'access arguments' => array(2, 3, 4, 5),
+    'type' => MENU_CALLBACK,
+  );
+  $items['entityreference/autocomplete/tags/%/%/%'] = array(
+    'title' => 'Entity Reference Autocomplete',
+    'page callback' => 'entityreference_autocomplete_callback',
+    'page arguments' => array(2, 3, 4, 5),
+    'access callback' => 'entityreference_autocomplete_access_callback',
+    'access arguments' => array(2, 3, 4, 5),
+    'type' => MENU_CALLBACK,
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function entityreference_field_is_empty($item, $field) {
+  $empty = !isset($item['target_id']) || !is_numeric($item['target_id']);
+
+  // Invoke the behaviors to allow them to override the empty status.
+  foreach (entityreference_get_behavior_handlers($field) as $handler) {
+    $handler->is_empty_alter($empty, $item, $field);
+  }
+  return $empty;
+}
+
+/**
+ * Get the behavior handlers for a given entityreference field.
+ */
+function entityreference_get_behavior_handlers($field, $instance = NULL) {
+  $object_cache = drupal_static(__FUNCTION__);
+  $identifier = $field['field_name'];
+  if (!empty($instance)) {
+    $identifier .= ':' . $instance['entity_type'] . ':' . $instance['bundle'];
+  }
+
+  if (!isset($object_cache[$identifier])) {
+    $object_cache[$identifier] = array();
+
+    // Merge in defaults.
+    $field['settings'] += array('behaviors' => array());
+
+    $object_cache[$field['field_name']] = array();
+    $behaviors = !empty($field['settings']['handler_settings']['behaviors']) ? $field['settings']['handler_settings']['behaviors'] : array();
+    if (!empty($instance['settings']['behaviors'])) {
+      $behaviors = array_merge($behaviors, $instance['settings']['behaviors']);
+    }
+    foreach ($behaviors as $behavior => $settings) {
+      if (empty($settings['status'])) {
+        // Behavior is not enabled.
+        continue;
+      }
+
+      $object_cache[$identifier][] = _entityreference_get_behavior_handler($behavior);
+    }
+  }
+
+  return $object_cache[$identifier];
+}
+
+/**
+ * Get the behavior handler for a given entityreference field and instance.
+ *
+ * @param $handler
+ *   The behavior handler name.
+ */
+function _entityreference_get_behavior_handler($behavior) {
+  $object_cache = drupal_static(__FUNCTION__);
+
+  if (!isset($object_cache[$behavior])) {
+    ctools_include('plugins');
+    $class = ctools_plugin_load_class('entityreference', 'behavior', $behavior, 'class');
+
+    $class = class_exists($class) ? $class : 'EntityReference_BehaviorHandler_Broken';
+    $object_cache[$behavior] = new $class($behavior);
+  }
+
+  return $object_cache[$behavior];
+}
+
+/**
+ * Get the selection handler for a given entityreference field.
+ */
+function entityreference_get_selection_handler($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+  ctools_include('plugins');
+  $handler = $field['settings']['handler'];
+  $class = ctools_plugin_load_class('entityreference', 'selection', $handler, 'class');
+
+  if (class_exists($class)) {
+    return call_user_func(array($class, 'getInstance'), $field, $instance, $entity_type, $entity);
+  }
+  else {
+    return EntityReference_SelectionHandler_Broken::getInstance($field, $instance, $entity_type, $entity);
+  }
+}
+
+/**
+ * Implements hook_field_load().
+ */
+function entityreference_field_load($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field) as $handler) {
+    $handler->load($entity_type, $entities, $field, $instances, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_validate().
+ */
+function entityreference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  $ids = array();
+  foreach ($items as $delta => $item) {
+    if (!entityreference_field_is_empty($item, $field) && $item['target_id'] !== NULL) {
+      $ids[$item['target_id']] = $delta;
+    }
+  }
+
+  if ($ids) {
+    $valid_ids = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->validateReferencableEntities(array_keys($ids));
+
+    $invalid_entities = array_diff_key($ids, array_flip($valid_ids));
+    if ($invalid_entities) {
+      foreach ($invalid_entities as $id => $delta) {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'entityreference_invalid_entity',
+          'message' => t('The referenced entity (@type: @id) is invalid.', array('@type' => $field['settings']['target_type'], '@id' => $id)),
+        );
+      }
+    }
+  }
+
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->validate($entity_type, $entity, $field, $instance, $langcode, $items, $errors);
+  }
+}
+
+/**
+ * Implements hook_field_presave().
+ *
+ * Adds the target type to the field data structure when saving.
+ */
+function entityreference_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->presave($entity_type, $entity, $field, $instance, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_insert().
+ */
+function entityreference_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->insert($entity_type, $entity, $field, $instance, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_attach_insert().
+ *
+ * Emulates a post-insert hook.
+ */
+function entityreference_field_attach_insert($entity_type, $entity) {
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
+    $field = field_info_field($field_name);
+    if ($field['type'] == 'entityreference') {
+      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+        $handler->postInsert($entity_type, $entity, $field, $instance);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_update().
+ */
+function entityreference_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->update($entity_type, $entity, $field, $instance, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_attach_update().
+ *
+ * Emulates a post-update hook.
+ */
+function entityreference_field_attach_update($entity_type, $entity) {
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
+    $field = field_info_field($field_name);
+    if ($field['type'] == 'entityreference') {
+      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+        $handler->postUpdate($entity_type, $entity, $field, $instance);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_delete().
+ */
+function entityreference_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Invoke the behaviors.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->delete($entity_type, $entity, $field, $instance, $langcode, $items);
+  }
+}
+
+/**
+ * Implements hook_field_attach_delete().
+ *
+ * Emulates a post-delete hook.
+ */
+function entityreference_field_attach_delete($entity_type, $entity) {
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
+    $field = field_info_field($field_name);
+    if ($field['type'] == 'entityreference') {
+      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+        $handler->postDelete($entity_type, $entity, $field, $instance);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_insert().
+ */
+function entityreference_entity_insert($entity, $entity_type) {
+  entityreference_entity_crud($entity, $entity_type, 'entityPostInsert');
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function entityreference_entity_update($entity, $entity_type) {
+  entityreference_entity_crud($entity, $entity_type, 'entityPostUpdate');
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function entityreference_entity_delete($entity, $entity_type) {
+  entityreference_entity_crud($entity, $entity_type, 'entityPostDelete');
+}
+
+/**
+ * Invoke a behavior based on entity CRUD.
+ *
+ * @param $entity
+ *   The entity object.
+ * @param $entity_type
+ *   The entity type.
+ * @param $method_name
+ *   The method to invoke.
+ */
+function entityreference_entity_crud($entity, $entity_type, $method_name) {
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+  foreach (field_info_instances($entity_type, $bundle) as $field_name => $instance) {
+    $field = field_info_field($field_name);
+    if ($field['type'] == 'entityreference') {
+      foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+        $handler->{$method_name}($entity_type, $entity, $field, $instance);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function entityreference_field_settings_form($field, $instance, $has_data) {
+  // The field settings infrastructure is not AJAX enabled by default,
+  // because it doesn't pass over the $form_state.
+  // Build the whole form into a #process in which we actually have access
+  // to the form state.
+  $form = array(
+    '#type' => 'container',
+    '#attached' => array(
+      'css' => array(drupal_get_path('module', 'entityreference') . '/entityreference.admin.css'),
+    ),
+    '#process' => array(
+      '_entityreference_field_settings_process',
+      '_entityreference_field_settings_ajax_process',
+    ),
+    '#element_validate' => array('_entityreference_field_settings_validate'),
+    '#field' => $field,
+    '#instance' => $instance,
+    '#has_data' => $has_data,
+  );
+  return $form;
+}
+
+function _entityreference_field_settings_process($form, $form_state) {
+  $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
+  $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
+  $has_data = $form['#has_data'];
+
+  $settings = $field['settings'];
+  $settings += array('handler' => 'base');
+
+  // Select the target entity type.
+  $entity_type_options = array();
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    $entity_type_options[$entity_type] = $entity_info['label'];
+  }
+
+  $form['target_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Target type'),
+    '#options' => $entity_type_options,
+    '#default_value' => $field['settings']['target_type'],
+    '#required' => TRUE,
+    '#description' => t('The entity type that can be referenced through this field.'),
+    '#disabled' => $has_data,
+    '#size' => 1,
+    '#ajax' => TRUE,
+    '#limit_validation_errors' => array(),
+  );
+
+  ctools_include('plugins');
+  $handlers = ctools_get_plugins('entityreference', 'selection');
+  uasort($handlers, 'ctools_plugin_sort');
+  $handlers_options = array();
+  foreach ($handlers as $handler => $handler_info) {
+    $handlers_options[$handler] = check_plain($handler_info['title']);
+  }
+
+  $form['handler'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Entity selection'),
+    '#tree' => TRUE,
+    '#process' => array('_entityreference_form_process_merge_parent'),
+  );
+
+  $form['handler']['handler'] = array(
+    '#type' => 'select',
+    '#title' => t('Mode'),
+    '#options' => $handlers_options,
+    '#default_value' => $settings['handler'],
+    '#required' => TRUE,
+    '#ajax' => TRUE,
+    '#limit_validation_errors' => array(),
+  );
+  $form['handler_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Change handler'),
+    '#limit_validation_errors' => array(),
+    '#attributes' => array(
+      'class' => array('js-hide'),
+    ),
+    '#submit' => array('entityreference_settings_ajax_submit'),
+  );
+
+  $form['handler']['handler_settings'] = array(
+    '#type' => 'container',
+    '#attributes' => array('class' => array('entityreference-settings')),
+  );
+
+  $handler = entityreference_get_selection_handler($field, $instance);
+  $form['handler']['handler_settings'] += $handler->settingsForm($field, $instance);
+
+  _entityreference_get_behavior_elements($form, $field, $instance, 'field');
+  if (!empty($form['behaviors'])) {
+    $form['behaviors'] += array(
+      '#type' => 'fieldset',
+      '#title' => t('Additional behaviors'),
+      '#parents' => array_merge($form['#parents'], array('handler_settings', 'behaviors')),
+    );
+  }
+
+  return $form;
+}
+
+function _entityreference_field_settings_ajax_process($form, $form_state) {
+  _entityreference_field_settings_ajax_process_element($form, $form);
+  return $form;
+}
+
+function _entityreference_field_settings_ajax_process_element(&$element, $main_form) {
+  if (isset($element['#ajax']) && $element['#ajax'] === TRUE) {
+    $element['#ajax'] = array(
+      'callback' => 'entityreference_settings_ajax',
+      'wrapper' => $main_form['#id'],
+      'element' => $main_form['#array_parents'],
+    );
+  }
+
+  foreach (element_children($element) as $key) {
+    _entityreference_field_settings_ajax_process_element($element[$key], $main_form);
+  }
+}
+
+function _entityreference_form_process_merge_parent($element) {
+  $parents = $element['#parents'];
+  array_pop($parents);
+  $element['#parents'] = $parents;
+  return $element;
+}
+
+function _entityreference_element_validate_filter(&$element, &$form_state) {
+  $element['#value'] = array_filter($element['#value']);
+  form_set_value($element, $element['#value'], $form_state);
+}
+
+function _entityreference_field_settings_validate($form, &$form_state) {
+  // Store the new values in the form state.
+  $field = $form['#field'];
+  if (isset($form_state['values']['field'])) {
+    $field['settings'] = $form_state['values']['field']['settings'];
+  }
+  $form_state['entityreference']['field'] = $field;
+
+  unset($form_state['values']['field']['settings']['handler_submit']);
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function entityreference_field_instance_settings_form($field, $instance) {
+  $form['settings'] = array(
+    '#type' => 'container',
+    '#attached' => array(
+      'css' => array(drupal_get_path('module', 'entityreference') . '/entityreference.admin.css'),
+    ),
+    '#weight' => 10,
+    '#tree' => TRUE,
+    '#process' => array(
+      '_entityreference_form_process_merge_parent',
+      '_entityreference_field_instance_settings_form',
+      '_entityreference_field_settings_ajax_process',
+    ),
+    '#element_validate' => array('_entityreference_field_instance_settings_validate'),
+    '#field' => $field,
+    '#instance' => $instance,
+  );
+
+  return $form;
+}
+
+function _entityreference_field_instance_settings_form($form, $form_state) {
+  $field = isset($form_state['entityreference']['field']) ? $form_state['entityreference']['field'] : $form['#field'];
+  $instance = isset($form_state['entityreference']['instance']) ? $form_state['entityreference']['instance'] : $form['#instance'];
+
+  _entityreference_get_behavior_elements($form, $field, $instance, 'instance');
+  if (!empty($form['behaviors'])) {
+    $form['behaviors'] += array(
+      '#type' => 'fieldset',
+      '#title' => t('Additional behaviors'),
+      '#process' => array(
+        '_entityreference_field_settings_ajax_process',
+      ),
+    );
+  }
+  return $form;
+}
+
+function _entityreference_field_instance_settings_validate($form, &$form_state) {
+  // Store the new values in the form state.
+  $instance = $form['#instance'];
+  if (isset($form_state['values']['instance'])) {
+    $instance = drupal_array_merge_deep($instance, $form_state['values']['instance']);
+  }
+  $form_state['entityreference']['instance'] = $instance;
+}
+
+/**
+ * Get the field or instance elements for the field configuration.
+ */
+function _entityreference_get_behavior_elements(&$element, $field, $instance, $level) {
+  // Add the accessible behavior handlers.
+  $behavior_plugins = entityreference_get_accessible_behavior_plugins($field, $instance);
+
+  if ($behavior_plugins[$level]) {
+    $element['behaviors'] = array();
+
+    foreach ($behavior_plugins[$level] as $name => $plugin) {
+      if ($level == 'field') {
+        $settings = !empty($field['settings']['handler_settings']['behaviors'][$name]) ? $field['settings']['handler_settings']['behaviors'][$name] : array();
+      }
+      else {
+        $settings = !empty($instance['settings']['behaviors'][$name]) ? $instance['settings']['behaviors'][$name] : array();
+      }
+      $settings += array('status' => $plugin['force enabled']);
+
+      // Render the checkbox.
+      $element['behaviors'][$name] = array(
+        '#tree' => TRUE,
+      );
+      $element['behaviors'][$name]['status'] = array(
+        '#type' => 'checkbox',
+        '#title' => check_plain($plugin['title']),
+        '#description' => $plugin['description'],
+        '#default_value' => $settings['status'],
+        '#disabled' => $plugin['force enabled'],
+        '#ajax' => TRUE,
+      );
+
+      if ($settings['status']) {
+        $handler = _entityreference_get_behavior_handler($name);
+        if ($behavior_elements = $handler->settingsForm($field, $instance)) {
+          foreach ($behavior_elements as $key => &$behavior_element) {
+            $behavior_element += array(
+              '#default_value' => !empty($settings[$key]) ? $settings[$key] : NULL,
+            );
+          }
+
+          // Get the behavior settings.
+          $behavior_elements += array(
+            '#type' => 'container',
+            '#process' => array('_entityreference_form_process_merge_parent'),
+            '#attributes' => array(
+              'class' => array('entityreference-settings'),
+            ),
+          );
+          $element['behaviors'][$name]['settings'] = $behavior_elements;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Get all accessible behavior plugins.
+ */
+function entityreference_get_accessible_behavior_plugins($field, $instance) {
+  ctools_include('plugins');
+  $plugins = array('field' => array(), 'instance' => array());
+  foreach (ctools_get_plugins('entityreference', 'behavior') as $name => $plugin) {
+    $handler = _entityreference_get_behavior_handler($name);
+    $level = $plugin['behavior type'];
+    if ($handler->access($field, $instance)) {
+      $plugins[$level][$name] = $plugin;
+    }
+  }
+  return $plugins;
+}
+
+/**
+ * Ajax callback for the handler settings form.
+ *
+ * @see entityreference_field_settings_form()
+ */
+function entityreference_settings_ajax($form, $form_state) {
+  $trigger = $form_state['triggering_element'];
+  return drupal_array_get_nested_value($form, $trigger['#ajax']['element']);
+}
+
+/**
+ * Submit handler for the non-JS case.
+ *
+ * @see entityreference_field_settings_form()
+ */
+function entityreference_settings_ajax_submit($form, &$form_state) {
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Property callback for the Entity Metadata framework.
+ */
+function entityreference_field_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  // Set the property type based on the targe type.
+  $field_type['property_type'] = $field['settings']['target_type'];
+
+  // Then apply the default.
+  entity_metadata_field_default_property_callback($info, $entity_type, $field, $instance, $field_type);
+
+  // Invoke the behaviors to allow them to change the properties.
+  foreach (entityreference_get_behavior_handlers($field, $instance) as $handler) {
+    $handler->property_info_alter($info, $entity_type, $field, $instance, $field_type);
+  }
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function entityreference_field_widget_info() {
+  $widgets['entityreference_autocomplete'] = array(
+    'label' => t('Autocomplete'),
+    'description' => t('An autocomplete text field.'),
+    'field types' => array('entityreference'),
+    'settings' => array(
+      'match_operator' => 'CONTAINS',
+      'size' => 60,
+      // We don't have a default here, because it's not the same between
+      // the two widgets, and the Field API doesn't update default
+      // settings when the widget changes.
+      'path' => '',
+    ),
+  );
+
+  $widgets['entityreference_autocomplete_tags'] = array(
+    'label' => t('Autocomplete (Tags style)'),
+    'description' => t('An autocomplete text field.'),
+    'field types' => array('entityreference'),
+    'settings' => array(
+      'match_operator' => 'CONTAINS',
+      'size' => 60,
+      // We don't have a default here, because it's not the same between
+      // the two widgets, and the Field API doesn't update default
+      // settings when the widget changes.
+      'path' => '',
+    ),
+    'behaviors' => array(
+      'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+    ),
+  );
+
+  return $widgets;
+}
+
+/**
+ * Implements hook_field_widget_info_alter().
+ */
+function entityreference_field_widget_info_alter(&$info) {
+  if (module_exists('options')) {
+    $info['options_select']['field types'][] = 'entityreference';
+    $info['options_buttons']['field types'][] = 'entityreference';
+  }
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function entityreference_field_widget_settings_form($field, $instance) {
+  $widget = $instance['widget'];
+  $settings = $widget['settings'] + field_info_widget_settings($widget['type']);
+
+  $form = array();
+
+  if ($widget['type'] == 'entityreference_autocomplete' || $widget['type'] == 'entityreference_autocomplete_tags') {
+    $form['match_operator'] = array(
+      '#type' => 'select',
+      '#title' => t('Autocomplete matching'),
+      '#default_value' => $settings['match_operator'],
+      '#options' => array(
+        'STARTS_WITH' => t('Starts with'),
+        'CONTAINS' => t('Contains'),
+      ),
+      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
+    );
+    $form['size'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Size of textfield'),
+      '#default_value' => $settings['size'],
+      '#element_validate' => array('_element_validate_integer_positive'),
+      '#required' => TRUE,
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Implements hook_options_list().
+ */
+function entityreference_options_list($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+  if (!$options = entityreference_get_selection_handler($field, $instance, $entity_type, $entity)->getReferencableEntities()) {
+    return array();
+  }
+
+  // Rebuild the array, by changing the bundle key into the bundle label.
+  $target_type = $field['settings']['target_type'];
+  $entity_info = entity_get_info($target_type);
+
+  $return = array();
+  foreach ($options as $bundle => $entity_ids) {
+    $bundle_label = check_plain($entity_info['bundles'][$bundle]['label']);
+    $return[$bundle_label] = $entity_ids;
+  }
+
+  return count($return) == 1 ? reset($return) : $return;
+}
+
+/**
+ * Implements hook_query_TAG_alter().
+ */
+function entityreference_query_entityreference_alter(QueryAlterableInterface $query) {
+  $handler = $query->getMetadata('entityreference_selection_handler');
+  $handler->entityFieldQueryAlter($query);
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function entityreference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  $entity_type = $instance['entity_type'];
+  $entity = isset($element['#entity']) ? $element['#entity'] : NULL;
+  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
+
+  if ($instance['widget']['type'] == 'entityreference_autocomplete' || $instance['widget']['type'] == 'entityreference_autocomplete_tags') {
+
+    if ($instance['widget']['type'] == 'entityreference_autocomplete') {
+      // We let the Field API handles multiple values for us, only take
+      // care of the one matching our delta.
+      if (isset($items[$delta])) {
+        $items = array($items[$delta]);
+      }
+      else {
+        $items = array();
+      }
+    }
+
+    $entity_ids = array();
+    $entity_labels = array();
+
+    // Build an array of entities ID.
+    foreach ($items as $item) {
+      $entity_ids[] = $item['target_id'];
+    }
+
+    // Load those entities and loop through them to extract their labels.
+    $entities = entity_load($field['settings']['target_type'], $entity_ids);
+
+    foreach ($entities as $entity_id => $entity_item) {
+      $label = $handler->getLabel($entity_item);
+      $key = "$label ($entity_id)";
+      // Labels containing commas or quotes must be wrapped in quotes.
+      if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
+        $key = '"' . str_replace('"', '""', $key) . '"';
+      }
+      $entity_labels[] = $key;
+    }
+
+    // Prepare the autocomplete path.
+    if (!empty($instance['widget']['settings']['path'])) {
+      $autocomplete_path = $instance['widget']['settings']['path'];
+    }
+    else {
+      $autocomplete_path = $instance['widget']['type'] == 'entityreference_autocomplete' ? 'entityreference/autocomplete/single' : 'entityreference/autocomplete/tags';
+    }
+
+    $autocomplete_path .= '/' . $field['field_name'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/';
+    // Use <NULL> as a placeholder in the URL when we don't have an entity.
+    // Most webservers collapse two consecutive slashes.
+    $id = 'NULL';
+    if ($entity) {
+      list($eid) = entity_extract_ids($entity_type, $entity);
+      if ($eid) {
+        $id = $eid;
+      }
+    }
+    $autocomplete_path .= $id;
+
+    if ($instance['widget']['type'] == 'entityreference_autocomplete') {
+      $element += array(
+        '#type' => 'textfield',
+        '#maxlength' => 1024,
+        '#default_value' => implode(', ', $entity_labels),
+        '#autocomplete_path' => $autocomplete_path,
+        '#size' => $instance['widget']['settings']['size'],
+        '#element_validate' => array('_entityreference_autocomplete_validate'),
+      );
+      return array('target_id' => $element);
+    }
+    else {
+      $element += array(
+        '#type' => 'textfield',
+        '#maxlength' => 1024,
+        '#default_value' => implode(', ', $entity_labels),
+        '#autocomplete_path' => $autocomplete_path,
+        '#size' => $instance['widget']['settings']['size'],
+        '#element_validate' => array('_entityreference_autocomplete_tags_validate'),
+      );
+      return $element;
+    }
+  }
+}
+
+function _entityreference_autocomplete_validate($element, &$form_state, $form) {
+  // If a value was entered into the autocomplete...
+  $value = '';
+  if (!empty($element['#value'])) {
+    // Take "label (entity id)', match the id from parenthesis.
+    if (preg_match("/.+\((\d+)\)/", $element['#value'], $matches)) {
+      $value = $matches[1];
+    }
+    else {
+      // Try to get a match from the input string when the user didn't use the
+      // autocomplete but filled in a value manually.
+      $field = field_info_field($element['#field_name']);
+      $handler = entityreference_get_selection_handler($field);
+      $field_name = $element['#field_name'];
+      $field = field_info_field($field_name);
+      $instance = field_info_instance($element['#entity_type'], $field_name, $element['#bundle']);
+      $handler = entityreference_get_selection_handler($field, $instance);
+      $value = $handler->validateAutocompleteInput($element['#value'], $element, $form_state, $form);
+    }
+  }
+  // Update the value of this element so the field can validate the product IDs.
+  form_set_value($element, $value, $form_state);
+}
+
+function _entityreference_autocomplete_tags_validate($element, &$form_state, $form) {
+  $value = array();
+  // If a value was entered into the autocomplete...
+  if (!empty($element['#value'])) {
+    $entities = drupal_explode_tags($element['#value']);
+    $value = array();
+    foreach ($entities as $entity) {
+      // Take "label (entity id)', match the id from parenthesis.
+      if (preg_match("/.+\((\d+)\)/", $entity, $matches)) {
+        $value[] = array(
+          'target_id' => $matches[1],
+        );
+      }
+      else {
+        // Try to get a match from the input string when the user didn't use the
+        // autocomplete but filled in a value manually.
+        $field = field_info_field($element['#field_name']);
+        $handler = entityreference_get_selection_handler($field);
+        $value[] = array(
+          'target_id' => $handler->validateAutocompleteInput($entity, $element, $form_state, $form),
+        );
+      }
+    }
+  }
+  // Update the value of this element so the field can validate the product IDs.
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Implements hook_field_widget_error().
+ */
+function entityreference_field_widget_error($element, $error) {
+  form_error($element, $error['message']);
+}
+
+/**
+ * Menu Access callback for the autocomplete widget.
+ *
+ * @param $type
+ *   The widget type (i.e. 'single' or 'tags').
+ * @param $field_name
+ *   The name of the entity-reference field.
+ * @param $entity_type
+ *   The entity type.
+ * @param $bundle_name
+ *   The bundle name.
+ * @return
+ *   True if user can access this menu item.
+ */
+function entityreference_autocomplete_access_callback($type, $field_name, $entity_type, $bundle_name) {
+  $field = field_info_field($field_name);
+  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
+
+  if (!$field || !$instance || $field['type'] != 'entityreference' || !field_access('edit', $field, $entity_type)) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * Menu callback: autocomplete the label of an entity.
+ *
+ * @param $type
+ *   The widget type (i.e. 'single' or 'tags').
+ * @param $field_name
+ *   The name of the entity-reference field.
+ * @param $entity_type
+ *   The entity type.
+ * @param $bundle_name
+ *   The bundle name.
+ * @param $entity_id
+ *   Optional; The entity ID the entity-reference field is attached to.
+ *   Defaults to ''.
+ * @param $string
+ *   The label of the entity to query by.
+ */
+function entityreference_autocomplete_callback($type, $field_name, $entity_type, $bundle_name, $entity_id = '', $string = '') {
+  $field = field_info_field($field_name);
+  $instance = field_info_instance($entity_type, $field_name, $bundle_name);
+
+  return entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id, $string);
+}
+
+/**
+ * Return JSON based on given field, instance and string.
+ *
+ * This function can be used by other modules that wish to pass a mocked
+ * definition of the field on instance.
+ *
+ * @param $type
+ *   The widget type (i.e. 'single' or 'tags').
+ * @param $field
+ *   The field array defintion.
+ * @param $instance
+ *   The instance array defintion.
+ * @param $entity_type
+ *   The entity type.
+ * @param $entity_id
+ *   Optional; The entity ID the entity-reference field is attached to.
+ *   Defaults to ''.
+ * @param $string
+ *   The label of the entity to query by.
+ */
+function entityreference_autocomplete_callback_get_matches($type, $field, $instance, $entity_type, $entity_id = '', $string = '') {
+  $matches = array();
+
+  $entity = NULL;
+  if ($entity_id !== 'NULL') {
+    $entity = entity_load_single($entity_type, $entity_id);
+    if (!$entity || !entity_access('view', $entity_type, $entity)) {
+      return MENU_ACCESS_DENIED;
+    }
+  }
+
+  $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
+
+  if ($type == 'tags') {
+    // The user enters a comma-separated list of tags. We only autocomplete the last tag.
+    $tags_typed = drupal_explode_tags($string);
+    $tag_last = drupal_strtolower(array_pop($tags_typed));
+    if (!empty($tag_last)) {
+      $prefix = count($tags_typed) ? implode(', ', $tags_typed) . ', ' : '';
+    }
+  }
+  else {
+    // The user enters a single tag.
+    $prefix = '';
+    $tag_last = $string;
+  }
+
+  if (isset($tag_last)) {
+    // Get an array of matching entities.
+    $entity_labels = $handler->getReferencableEntities($tag_last, $instance['widget']['settings']['match_operator'], 10);
+
+    // Loop through the products and convert them into autocomplete output.
+    foreach ($entity_labels as $values) {
+      foreach ($values as $entity_id => $label) {
+        $key = "$label ($entity_id)";
+        // Strip things like starting/trailing white spaces, line breaks and tags.
+        $key = preg_replace('/\s\s+/', ' ', str_replace("\n", '', trim(decode_entities(strip_tags($key)))));
+        // Names containing commas or quotes must be wrapped in quotes.
+        if (strpos($key, ',') !== FALSE || strpos($key, '"') !== FALSE) {
+          $key = '"' . str_replace('"', '""', $key) . '"';
+        }
+        $matches[$prefix . $key] = '<div class="reference-autocomplete">' . $label . '</div>';
+      }
+    }
+  }
+
+  drupal_json_output($matches);
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function entityreference_field_formatter_info() {
+  return array(
+    'entityreference_label' => array(
+      'label' => t('Label'),
+      'description' => t('Display the label of the referenced entities.'),
+      'field types' => array('entityreference'),
+      'settings' => array(
+        'link' => FALSE,
+      ),
+    ),
+    'entityreference_entity_id' => array(
+      'label' => t('Entity id'),
+      'description' => t('Display the id of the referenced entities.'),
+      'field types' => array('entityreference'),
+    ),
+    'entityreference_entity_view' => array(
+      'label' => t('Rendered entity'),
+      'description' => t('Display the referenced entities rendered by entity_view().'),
+      'field types' => array('entityreference'),
+      'settings' => array(
+        'view_mode' => '',
+        'links' => TRUE,
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function entityreference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  if ($display['type'] == 'entityreference_label') {
+    $element['link'] = array(
+      '#title' => t('Link label to the referenced entity'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['link'],
+    );
+  }
+
+  if ($display['type'] == 'entityreference_entity_view') {
+    $entity_info = entity_get_info($field['settings']['target_type']);
+    $options = array();
+    if (!empty($entity_info['view modes'])) {
+      foreach ($entity_info['view modes'] as $view_mode => $view_mode_settings) {
+        $options[$view_mode] = $view_mode_settings['label'];
+      }
+    }
+
+    if (count($options) > 1) {
+      $element['view_mode'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#title' => t('View mode'),
+        '#default_value' => $settings['view_mode'],
+      );
+    }
+
+    $element['links'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show links'),
+      '#default_value' => $settings['links'],
+    );
+  }
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function entityreference_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $summary = array();
+
+  if ($display['type'] == 'entityreference_label') {
+    $summary[] = $settings['link'] ? t('Link to the referenced entity') : t('No link');
+  }
+
+  if ($display['type'] == 'entityreference_entity_view') {
+    $entity_info = entity_get_info($field['settings']['target_type']);
+    $summary[] = t('Rendered as @mode', array('@mode' => isset($entity_info['view modes'][$settings['view_mode']]['label']) ? $entity_info['view modes'][$settings['view_mode']]['label'] : $settings['view_mode']));
+    $summary[] = !empty($settings['links']) ? t('Display links') : t('Do not display links');
+  }
+
+  return implode('<br />', $summary);
+}
+
+/**
+ * Implements hook_field_formatter_prepare_view().
+ */
+function entityreference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
+  $target_ids = array();
+
+  // Collect every possible entity attached to any of the entities.
+  foreach ($entities as $id => $entity) {
+    foreach ($items[$id] as $delta => $item) {
+      if (isset($item['target_id'])) {
+        $target_ids[] = $item['target_id'];
+      }
+    }
+  }
+
+  if ($target_ids) {
+    $target_entities = entity_load($field['settings']['target_type'], $target_ids);
+  }
+  else {
+    $target_entities = array();
+  }
+
+  // Iterate through the fieldable entities again to attach the loaded data.
+  foreach ($entities as $id => $entity) {
+    $rekey = FALSE;
+
+    foreach ($items[$id] as $delta => $item) {
+      // Check whether the referenced entity could be loaded.
+      if (isset($target_entities[$item['target_id']])) {
+        // Replace the instance value with the term data.
+        $items[$id][$delta]['entity'] = $target_entities[$item['target_id']];
+        // Check whether the user has access to the referenced entity.
+        $items[$id][$delta]['access'] = entity_access('view', $field['settings']['target_type'], $target_entities[$item['target_id']]);
+      }
+      // Otherwise, unset the instance value, since the entity does not exist.
+      else {
+        unset($items[$id][$delta]);
+        $rekey = TRUE;
+      }
+    }
+
+    if ($rekey) {
+      // Rekey the items array.
+      $items[$id] = array_values($items[$id]);
+    }
+  }
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function entityreference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $result = array();
+  $settings = $display['settings'];
+
+  // Rebuild the items list to contain only those with access.
+  foreach ($items as $key => $item) {
+    if (empty($item['access'])) {
+      unset($items[$key]);
+    }
+  }
+
+  switch ($display['type']) {
+    case 'entityreference_label':
+      $handler = entityreference_get_selection_handler($field, $instance, $entity_type, $entity);
+
+      foreach ($items as $delta => $item) {
+        $label = $handler->getLabel($item['entity']);
+        // If the link is to be displayed and the entity has a uri, display a link.
+        // Note the assignment ($url = ) here is intended to be an assignment.
+        if ($display['settings']['link'] && ($uri = entity_uri($field['settings']['target_type'], $item['entity']))) {
+          $result[$delta] = array('#markup' => l($label, $uri['path'], $uri['options']));
+        }
+        else {
+          $result[$delta] = array('#markup' => check_plain($label));
+        }
+      }
+      break;
+
+    case 'entityreference_entity_id':
+      foreach ($items as $delta => $item) {
+        $result[$delta] = array('#markup' => check_plain($item['target_id']));
+      }
+      break;
+
+    case 'entityreference_entity_view':
+      foreach ($items as $delta => $item) {
+        // Protect ourselves from recursive rendering.
+        static $depth = 0;
+        $depth++;
+        if ($depth > 20) {
+          throw new EntityReferenceRecursiveRenderingException(t('Recursive rendering detected when rendering entity @entity_type(@entity_id). Aborting rendering.', array('@entity_type' => $entity_type, '@entity_id' => $item['target_id'])));
+        }
+
+        $entity = clone $item['entity'];
+        unset($entity->content);
+        $result[$delta] = entity_view($field['settings']['target_type'], array($item['target_id'] => $entity), $settings['view_mode'], $langcode, FALSE);
+
+        if (empty($settings['links']) && isset($result[$delta][$field['settings']['target_type']][$item['target_id']]['links'])) {
+          $result[$delta][$field['settings']['target_type']][$item['target_id']]['links']['#access'] = FALSE;
+        }
+        $depth = 0;
+      }
+      break;
+  }
+
+  return $result;
+}
+
+/**
+ * Exception thrown when the entity view renderer goes into a potentially infinite loop.
+ */
+class EntityReferenceRecursiveRenderingException extends Exception {}
+
+/**
+ * Implements hook_views_api().
+ */
+function entityreference_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'entityreference') . '/views',
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+name = Entity Reference Behavior Example
+description = Provides some example code for implementing Entity Reference behaviors.
+core = 7.x
+package = Fields
+dependencies[] = entityreference
+
+; Information added by drupal.org packaging script on 2012-11-18
+version = "7.x-1.0"
+core = "7.x"
+project = "entityreference"
+datestamp = "1353230808"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/entityreference_behavior_example.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Example module to demonstrate Entity reference behavior handlers.
+ */
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function entityreference_behavior_example_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'entityreference') {
+    return 'plugins/' . $plugin;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceFieldBehaviorExample.class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,31 @@
+<?php
+
+class EntityReferenceFieldBehaviorExample extends EntityReference_BehaviorHandler_Abstract {
+
+  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {
+    drupal_set_message(t('Do something on load!'));
+  }
+
+  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message(t('Do something on insert!'));
+  }
+
+  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message(t('Do something on update!'));
+  }
+
+  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message(t('Do something on delete!'));
+  }
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public function settingsForm($field, $instance) {
+    $form['test_field'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Field behavior setting'),
+    );
+    return $form;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/EntityReferenceInstanceBehaviorExample.class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,31 @@
+<?php
+
+class EntityReferenceInstanceBehaviorExample extends EntityReference_BehaviorHandler_Abstract {
+
+  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {
+    drupal_set_message(t('Do something on load, on the instance level!'));
+  }
+
+  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message(t('Do something on insert, on the instance level!'));
+  }
+
+  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message(t('Do something on update, on the instance level!'));
+  }
+
+  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+    drupal_set_message(t('Do something on delete, on the instance level!'));
+  }
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public function settingsForm($field, $instance) {
+    $form['test_instance'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Instance behavior setting'),
+    );
+    return $form;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_field_behavior.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,8 @@
+<?php
+
+$plugin = array(
+  'title' => t('Test behavior'),
+  'class' => 'EntityReferenceFieldBehaviorExample',
+  'weight' => 10,
+  'behavior type' => 'field',
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/examples/entityreference_behavior_example/plugins/behavior/test_instance_behavior.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,8 @@
+<?php
+
+$plugin = array(
+  'title' => t('Test instance behavior'),
+  'class' => 'EntityReferenceInstanceBehaviorExample',
+  'weight' => 10,
+  'behavior type' => 'instance',
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/behavior/EntityReferenceBehavior_TaxonomyIndex.class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,189 @@
+<?php
+
+/**
+ * @file
+ * CTools plugin class for the taxonomy-index behavior.
+ */
+
+/**
+ * Extends an entityreference field to maintain its references to taxonomy terms
+ * in the {taxonomy_index} table.
+ *
+ * Note, unlike entityPostInsert() and entityPostUpdate(), entityDelete()
+ * is not needed as cleanup is performed by taxonomy module in
+ * taxonomy_delete_node_index().
+ */
+class EntityReferenceBehavior_TaxonomyIndex extends EntityReference_BehaviorHandler_Abstract {
+
+  /**
+   * Overrides EntityReference_BehaviorHandler_Abstract::access().
+   *
+   * Ensure that it is only enabled for ER instances on nodes targeting
+   * terms, and the core variable to maintain index is enabled.
+   */
+  public function access($field, $instance) {
+    if ($instance['entity_type'] != 'node' || $field['settings']['target_type'] != 'taxonomy_term') {
+      return;
+    }
+
+    if ($field['storage']['type'] !== 'field_sql_storage') {
+      // Field doesn't use SQL storage.
+      return;
+    }
+
+    return variable_get('taxonomy_maintain_index_table', TRUE);
+  }
+
+  /**
+   * Overrides EntityReference_BehaviorHandler_Abstract::entityPostInsert().
+   *
+   * Runs after hook_node_insert() used by taxonomy module.
+   */
+  public function entityPostInsert($entity_type, $entity, $field, $instance) {
+    if ($entity_type != 'node') {
+      return;
+    }
+
+    $this->buildNodeIndex($entity);
+  }
+
+  /**
+   * Overrides EntityReference_BehaviorHandler_Abstract::entityPostUpdate().
+   *
+   * Runs after hook_node_update() used by taxonomy module.
+   */
+  public function entityPostUpdate($entity_type, $entity, $field, $instance) {
+    if ($entity_type != 'node') {
+      return;
+    }
+
+    $this->buildNodeIndex($entity);
+  }
+
+  /**
+   * Builds and inserts taxonomy index entries for a given node.
+   *
+   * The index lists all terms that are related to a given node entity, and is
+   * therefore maintained at the entity level.
+   *
+   * @param $node
+   *   The node object.
+   *
+   * @see taxonomy_build_node_index()
+   */
+  protected function buildNodeIndex($node) {
+    // We maintain a denormalized table of term/node relationships, containing
+    // only data for current, published nodes.
+    $status = NULL;
+    if (variable_get('taxonomy_maintain_index_table', TRUE)) {
+      // If a node property is not set in the node object when node_save() is
+      // called, the old value from $node->original is used.
+      if (!empty($node->original)) {
+        $status = (int)(!empty($node->status) || (!isset($node->status) && !empty($node->original->status)));
+        $sticky = (int)(!empty($node->sticky) || (!isset($node->sticky) && !empty($node->original->sticky)));
+      }
+      else {
+        $status = (int)(!empty($node->status));
+        $sticky = (int)(!empty($node->sticky));
+      }
+    }
+    // We only maintain the taxonomy index for published nodes.
+    if ($status) {
+      // Collect a unique list of all the term IDs from all node fields.
+      $tid_all = array();
+      foreach (field_info_instances('node', $node->type) as $instance) {
+        $field_name = $instance['field_name'];
+        $field = field_info_field($field_name);
+        if (!empty($field['settings']['target_type']) && $field['settings']['target_type'] == 'taxonomy_term' && $field['storage']['type'] == 'field_sql_storage') {
+          // If a field value is not set in the node object when node_save() is
+          // called, the old value from $node->original is used.
+          if (isset($node->{$field_name})) {
+            $items = $node->{$field_name};
+          }
+          elseif (isset($node->original->{$field_name})) {
+            $items = $node->original->{$field_name};
+          }
+          else {
+            continue;
+          }
+          foreach (field_available_languages('node', $field) as $langcode) {
+            if (!empty($items[$langcode])) {
+              foreach ($items[$langcode] as $item) {
+                $tid_all[$item['target_id']] = $item['target_id'];
+              }
+            }
+          }
+        }
+
+        // Re-calculate the terms added in taxonomy_build_node_index() so
+        // we can optimize database queries.
+        $original_tid_all = array();
+        if ($field['module'] == 'taxonomy' && $field['storage']['type'] == 'field_sql_storage') {
+          // If a field value is not set in the node object when node_save() is
+          // called, the old value from $node->original is used.
+          if (isset($node->{$field_name})) {
+            $items = $node->{$field_name};
+          }
+          elseif (isset($node->original->{$field_name})) {
+            $items = $node->original->{$field_name};
+          }
+          else {
+            continue;
+          }
+          foreach (field_available_languages('node', $field) as $langcode) {
+            if (!empty($items[$langcode])) {
+              foreach ($items[$langcode] as $item) {
+                $original_tid_all[$item['tid']] = $item['tid'];
+              }
+            }
+          }
+        }
+      }
+
+      // Insert index entries for all the node's terms, that were not
+      // already inserted in taxonomy_build_node_index().
+      $tid_all = array_diff($tid_all, $original_tid_all);
+
+      // Insert index entries for all the node's terms.
+      if (!empty($tid_all)) {
+        $query = db_insert('taxonomy_index')->fields(array('nid', 'tid', 'sticky', 'created'));
+        foreach ($tid_all as $tid) {
+          $query->values(array(
+            'nid' => $node->nid,
+            'tid' => $tid,
+            'sticky' => $sticky,
+            'created' => $node->created,
+          ));
+        }
+        $query->execute();
+      }
+    }
+  }
+
+  /**
+   * Overrides EntityReference_BehaviorHandler_Abstract::settingsForm().
+   */
+  public function settingsForm($field, $instance) {
+    $form = array();
+    $target = $field['settings']['target_type'];
+    if ($target != 'taxonomy_term') {
+      $form['ti-on-terms'] = array(
+        '#markup' => t('This behavior can only be set when the target type is taxonomy_term, but the target of this field is %target.', array('%target' => $target)),
+      );
+    }
+
+    $entity_type = $instance['entity_type'];
+    if ($entity_type != 'node') {
+      $form['ti-on-nodes'] = array(
+        '#markup' => t('This behavior can only be set when the entity type is node, but the entity type of this instance is %type.', array('%type' => $entity_type)),
+      );
+    }
+
+    if (!variable_get('taxonomy_maintain_index_table', TRUE)) {
+      $form['ti-disabled'] = array(
+        '#markup' => t('This core variable "taxonomy_maintain_index_table" is disabled.'),
+      );
+    }
+    return $form;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/behavior/EntityReferenceBehavior_ViewsFilterSelect.class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+<?php
+
+class EntityReferenceBehavior_ViewsFilterSelect extends EntityReference_BehaviorHandler_Abstract {
+
+  public function views_data_alter(&$data, $field) {
+    $entity_info = entity_get_info($field['settings']['target_type']);
+    $field_name = $field['field_name'] . '_target_id';
+    foreach ($data as $table_name => &$table_data) {
+      if (isset($table_data[$field_name])) {
+        // Set the entity id filter to use the in_operator handler with our
+        // own callback to return the values.
+        $table_data[$field_name]['filter']['handler'] = 'views_handler_filter_in_operator';
+        $table_data[$field_name]['filter']['options callback'] = 'entityreference_views_handler_options_list';
+        $table_data[$field_name]['filter']['options arguments'] = array($field['field_name']);
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/behavior/abstract.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,214 @@
+<?php
+
+/**
+ * Additional behaviors for a Entity Reference field.
+ *
+ * Implementations that wish to provide an implementation of this should
+ * register it using CTools' plugin system.
+ */
+interface EntityReference_BehaviorHandler {
+
+  /**
+   * Constructor for the behavior.
+   *
+   * @param $behavior
+   *   The name of the behavior plugin.
+   */
+  public function __construct($behavior);
+
+  /**
+   * Alter the field schema.
+   *
+   * @see hook_field_schema()
+   */
+  public function schema_alter(&$schema, $field);
+
+  /**
+   * Alter the properties information of a field instance.
+   *
+   * @see entity_hook_field_info()
+   */
+  public function property_info_alter(&$info, $entity_type, $field, $instance, $field_type);
+
+  /**
+   * Alter the views data of a field.
+   *
+   * @see entityreference_field_views_data()
+   */
+  public function views_data_alter(&$data, $field);
+
+  /**
+   * Act on loading entity reference fields of entities.
+   *
+   * @see hook_field_load()
+   */
+  public function load($entity_type, $entities, $field, $instances, $langcode, &$items);
+
+  /**
+   * Alter the empty status of a field item.
+   *
+   * @see hook_field_is_empty()
+   */
+  public function is_empty_alter(&$empty, $item, $field);
+
+  /**
+   * Act on validating an entity reference field.
+   *
+   * @see hook_field_validate()
+   */
+  public function validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors);
+
+  /**
+   * Act on presaving an entity reference field.
+   *
+   * @see hook_field_presave()
+   */
+  public function presave($entity_type, $entity, $field, $instance, $langcode, &$items);
+
+  /**
+   * Act before inserting an entity reference field.
+   *
+   * @see hook_field_insert()
+   */
+  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items);
+
+  /**
+   * Act after inserting an entity reference field.
+   *
+   * @see hook_field_attach_insert()
+   */
+  public function postInsert($entity_type, $entity, $field, $instance);
+
+  /**
+   * Act before updating an entity reference field.
+   *
+   * @see hook_field_update()
+   */
+  public function update($entity_type, $entity, $field, $instance, $langcode, &$items);
+
+  /**
+   * Act after updating an entity reference field.
+   *
+   * @see hook_field_attach_update()
+   */
+  public function postUpdate($entity_type, $entity, $field, $instance);
+
+  /**
+   * Act before deleting an entity with an entity reference field.
+   *
+   * @see hook_field_delete()
+   */
+  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items);
+
+  /**
+   * Act after deleting an entity with an entity reference field.
+   *
+   * @see hook_field_attach_delete()
+   */
+  public function postDelete($entity_type, $entity, $field, $instance);
+
+  /**
+   * Act after inserting an entity.
+   *
+   * @see hook_entity_insert()
+   */
+  public function entityPostInsert($entity_type, $entity, $field, $instance);
+
+  /**
+   * Act after updating an entity.
+   *
+   * @see hook_entity_update()
+   */
+  public function entityPostUpdate($entity_type, $entity, $field, $instance);
+
+  /**
+   * Act after deleting an entity.
+   *
+   * @see hook_entity_delete()
+   */
+  public function entityPostDelete($entity_type, $entity, $field, $instance);
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public function settingsForm($field, $instance);
+
+  /**
+   * Determine if handler should appear.
+   */
+  public function access($field, $instance);
+}
+
+/**
+ * An abstract implementation of EntityReference_BehaviorHandler.
+ */
+abstract class EntityReference_BehaviorHandler_Abstract implements EntityReference_BehaviorHandler {
+
+  /**
+   * The name of the behavior plugin.
+   */
+  protected $behavior;
+
+  /**
+   * The plugin definition.
+   */
+  protected $plugin;
+
+  public function __construct($behavior) {
+    $this->behavior = $behavior;
+
+    ctools_include('plugins');
+    $plugin = ctools_get_plugins('entityreference', 'behavior', $behavior);
+    $this->plugin = $plugin;
+  }
+
+  public function schema_alter(&$schema, $field) {}
+
+  public function property_info_alter(&$info, $entity_type, $field, $instance, $field_type) {}
+
+  public function views_data_alter(&$data, $field) {}
+
+  public function load($entity_type, $entities, $field, $instances, $langcode, &$items) {}
+
+  public function is_empty_alter(&$empty, $item, $field) {}
+
+  public function validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {}
+
+  public function presave($entity_type, $entity, $field, $instance, $langcode, &$items) {}
+
+  public function insert($entity_type, $entity, $field, $instance, $langcode, &$items) {}
+
+  public function postInsert($entity_type, $entity, $field, $instance) {}
+
+  public function update($entity_type, $entity, $field, $instance, $langcode, &$items) {}
+
+  public function postUpdate($entity_type, $entity, $field, $instance) {}
+
+  public function delete($entity_type, $entity, $field, $instance, $langcode, &$items) {}
+
+  public function postDelete($entity_type, $entity, $field, $instance) {}
+
+  public function entityPostInsert($entity_type, $entity, $field, $instance) {}
+
+  public function entityPostUpdate($entity_type, $entity, $field, $instance) {}
+
+  public function entityPostDelete($entity_type, $entity, $field, $instance) {}
+
+  public function settingsForm($field, $instance) {}
+
+  public function access($field, $instance) {
+    return TRUE;
+  }
+}
+
+/**
+ * A broken implementation of EntityReference_BehaviorHandler.
+ */
+class EntityReference_BehaviorHandler_Broken extends EntityReference_BehaviorHandler_Abstract {
+  public function settingsForm($field, $instance) {
+    $form['behavior_handler'] = array(
+      '#markup' => t('The selected behavior handler is broken.'),
+    );
+    return $form;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/behavior/taxonomy-index.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * CTools plugin declaration for taxonomy-index behavior.
+ */
+
+if (module_exists('taxonomy')) {
+  $plugin = array(
+    'title' => t('Taxonomy index'),
+    'description' => t('Include the term references created by instances of this field carried by node entities in the core {taxonomy_index} table. This will allow various modules to handle them like core term_reference fields.'),
+    'class' => 'EntityReferenceBehavior_TaxonomyIndex',
+    'behavior type' => 'instance',
+    'force enabled' => TRUE,
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/behavior/views-select-list.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,10 @@
+<?php
+
+if (module_exists('views')) {
+  $plugin = array(
+    'title' => t('Render Views filters as select list'),
+    'description' => t('Provides a select list for Views filters on this field. This should not be used when there are over 100 entities, as it might cause an out of memory error.'),
+    'class' => 'EntityReferenceBehavior_ViewsFilterSelect',
+    'behavior type' => 'field',
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Generic.class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,553 @@
+<?php
+
+/**
+ * A generic Entity handler.
+ *
+ * The generic base implementation has a variety of overrides to workaround
+ * core's largely deficient entity handling.
+ */
+class EntityReference_SelectionHandler_Generic implements EntityReference_SelectionHandler {
+
+  /**
+   * Implements EntityReferenceHandler::getInstance().
+   */
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    $target_entity_type = $field['settings']['target_type'];
+
+    // Check if the entity type does exist and has a base table.
+    $entity_info = entity_get_info($target_entity_type);
+    if (empty($entity_info['base table'])) {
+      return EntityReference_SelectionHandler_Broken::getInstance($field, $instance);
+    }
+
+    if (class_exists($class_name = 'EntityReference_SelectionHandler_Generic_' . $target_entity_type)) {
+      return new $class_name($field, $instance, $entity_type, $entity);
+    }
+    else {
+      return new EntityReference_SelectionHandler_Generic($field, $instance, $entity_type, $entity);
+    }
+  }
+
+  protected function __construct($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    $this->field = $field;
+    $this->instance = $instance;
+    $this->entity_type = $entity_type;
+    $this->entity = $entity;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::settingsForm().
+   */
+  public static function settingsForm($field, $instance) {
+    $entity_info = entity_get_info($field['settings']['target_type']);
+
+    // Merge-in default values.
+    $field['settings']['handler_settings'] += array(
+      'target_bundles' => array(),
+      'sort' => array(
+        'type' => 'none',
+      )
+    );
+
+    if (!empty($entity_info['entity keys']['bundle'])) {
+      $bundles = array();
+      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+        $bundles[$bundle_name] = $bundle_info['label'];
+      }
+
+      $form['target_bundles'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Target bundles'),
+        '#options' => $bundles,
+        '#default_value' => $field['settings']['handler_settings']['target_bundles'],
+        '#size' => 6,
+        '#multiple' => TRUE,
+        '#description' => t('The bundles of the entity type that can be referenced. Optional, leave empty for all bundles.'),
+        '#element_validate' => array('_entityreference_element_validate_filter'),
+      );
+    }
+    else {
+      $form['target_bundles'] = array(
+        '#type' => 'value',
+        '#value' => array(),
+      );
+    }
+
+    $form['sort']['type'] = array(
+      '#type' => 'select',
+      '#title' => t('Sort by'),
+      '#options' => array(
+        'none' => t("Don't sort"),
+        'property' => t('A property of the base table of the entity'),
+        'field' => t('A field attached to this entity'),
+      ),
+      '#ajax' => TRUE,
+      '#limit_validation_errors' => array(),
+      '#default_value' => $field['settings']['handler_settings']['sort']['type'],
+    );
+
+    $form['sort']['settings'] = array(
+      '#type' => 'container',
+      '#attributes' => array('class' => array('entityreference-settings')),
+      '#process' => array('_entityreference_form_process_merge_parent'),
+    );
+
+    if ($field['settings']['handler_settings']['sort']['type'] == 'property') {
+      // Merge-in default values.
+      $field['settings']['handler_settings']['sort'] += array(
+        'property' => NULL,
+      );
+
+      $form['sort']['settings']['property'] = array(
+        '#type' => 'select',
+        '#title' => t('Sort property'),
+        '#required' => TRUE,
+        '#options' => drupal_map_assoc($entity_info['schema_fields_sql']['base table']),
+        '#default_value' => $field['settings']['handler_settings']['sort']['property'],
+      );
+    }
+    elseif ($field['settings']['handler_settings']['sort']['type'] == 'field') {
+      // Merge-in default values.
+      $field['settings']['handler_settings']['sort'] += array(
+        'field' => NULL,
+      );
+
+      $fields = array();
+      foreach (field_info_instances($field['settings']['target_type']) as $bundle_name => $bundle_instances) {
+        foreach ($bundle_instances as $instance_name => $instance_info) {
+          $field_info = field_info_field($instance_name);
+          foreach ($field_info['columns'] as $column_name => $column_info) {
+            $fields[$instance_name . ':' . $column_name] = t('@label (column @column)', array('@label' => $instance_info['label'], '@column' => $column_name));
+          }
+        }
+      }
+
+      $form['sort']['settings']['field'] = array(
+        '#type' => 'select',
+        '#title' => t('Sort field'),
+        '#required' => TRUE,
+        '#options' => $fields,
+        '#default_value' => $field['settings']['handler_settings']['sort']['field'],
+      );
+    }
+
+    if ($field['settings']['handler_settings']['sort']['type'] != 'none') {
+      // Merge-in default values.
+      $field['settings']['handler_settings']['sort'] += array(
+        'direction' => 'ASC',
+      );
+
+      $form['sort']['settings']['direction'] = array(
+        '#type' => 'select',
+        '#title' => t('Sort direction'),
+        '#required' => TRUE,
+        '#options' => array(
+          'ASC' => t('Ascending'),
+          'DESC' => t('Descending'),
+        ),
+        '#default_value' => $field['settings']['handler_settings']['sort']['direction'],
+      );
+    }
+
+    return $form;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getReferencableEntities().
+   */
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
+    $options = array();
+    $entity_type = $this->field['settings']['target_type'];
+
+    $query = $this->buildEntityFieldQuery($match, $match_operator);
+    if ($limit > 0) {
+      $query->range(0, $limit);
+    }
+
+    $results = $query->execute();
+
+    if (!empty($results[$entity_type])) {
+      $entities = entity_load($entity_type, array_keys($results[$entity_type]));
+      foreach ($entities as $entity_id => $entity) {
+        list(,, $bundle) = entity_extract_ids($entity_type, $entity);
+        $options[$bundle][$entity_id] = check_plain($this->getLabel($entity));
+      }
+    }
+
+    return $options;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::countReferencableEntities().
+   */
+  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
+    $query = $this->buildEntityFieldQuery($match, $match_operator);
+    return $query
+      ->count()
+      ->execute();
+  }
+
+  /**
+   * Implements EntityReferenceHandler::validateReferencableEntities().
+   */
+  public function validateReferencableEntities(array $ids) {
+    if ($ids) {
+      $entity_type = $this->field['settings']['target_type'];
+      $query = $this->buildEntityFieldQuery();
+      $query->entityCondition('entity_id', $ids, 'IN');
+      $result = $query->execute();
+      if (!empty($result[$entity_type])) {
+        return array_keys($result[$entity_type]);
+      }
+    }
+
+    return array();
+  }
+
+  /**
+   * Implements EntityReferenceHandler::validateAutocompleteInput().
+   */
+  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
+      $entities = $this->getReferencableEntities($input, '=', 6);
+      if (empty($entities)) {
+        // Error if there are no entities available for a required field.
+        form_error($element, t('There are no entities matching "%value"', array('%value' => $input)));
+      }
+      elseif (count($entities) > 5) {
+        // Error if there are more than 5 matching entities.
+        form_error($element, t('Many entities are called %value. Specify the one you want by appending the id in parentheses, like "@value (@id)"', array(
+          '%value' => $input,
+          '@value' => $input,
+          '@id' => key($entities),
+        )));
+      }
+      elseif (count($entities) > 1) {
+        // More helpful error if there are only a few matching entities.
+        $multiples = array();
+        foreach ($entities as $id => $name) {
+          $multiples[] = $name . ' (' . $id . ')';
+        }
+        form_error($element, t('Multiple entities match this reference; "%multiple"', array('%multiple' => implode('", "', $multiples))));
+      }
+      else {
+        // Take the one and only matching entity.
+        return key($entities);
+      }
+  }
+
+  /**
+   * Build an EntityFieldQuery to get referencable entities.
+   */
+  protected function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $this->field['settings']['target_type']);
+    if (!empty($this->field['settings']['handler_settings']['target_bundles'])) {
+      $query->entityCondition('bundle', $this->field['settings']['handler_settings']['target_bundles'], 'IN');
+    }
+    if (isset($match)) {
+      $entity_info = entity_get_info($this->field['settings']['target_type']);
+      if (isset($entity_info['entity keys']['label'])) {
+        $query->propertyCondition($entity_info['entity keys']['label'], $match, $match_operator);
+      }
+    }
+
+    // Add a generic entity access tag to the query.
+    $query->addTag($this->field['settings']['target_type'] . '_access');
+    $query->addTag('entityreference');
+    $query->addMetaData('field', $this->field);
+    $query->addMetaData('entityreference_selection_handler', $this);
+
+    // Add the sort option.
+    if (!empty($this->field['settings']['handler_settings']['sort'])) {
+      $sort_settings = $this->field['settings']['handler_settings']['sort'];
+      if ($sort_settings['type'] == 'property') {
+        $query->propertyOrderBy($sort_settings['property'], $sort_settings['direction']);
+      }
+      elseif ($sort_settings['type'] == 'field') {
+        list($field, $column) = explode(':', $sort_settings['field'], 2);
+        $query->fieldOrderBy($field, $column, $sort_settings['direction']);
+      }
+    }
+
+    return $query;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::entityFieldQueryAlter().
+   */
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+
+  }
+
+  /**
+   * Helper method: pass a query to the alteration system again.
+   *
+   * This allow Entity Reference to add a tag to an existing query, to ask
+   * access control mechanisms to alter it again.
+   */
+  protected function reAlterQuery(SelectQueryInterface $query, $tag, $base_table) {
+    // Save the old tags and metadata.
+    // For some reason, those are public.
+    $old_tags = $query->alterTags;
+    $old_metadata = $query->alterMetaData;
+
+    $query->alterTags = array($tag => TRUE);
+    $query->alterMetaData['base_table'] = $base_table;
+    drupal_alter(array('query', 'query_' . $tag), $query);
+
+    // Restore the tags and metadata.
+    $query->alterTags = $old_tags;
+    $query->alterMetaData = $old_metadata;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getLabel().
+   */
+  public function getLabel($entity) {
+    return entity_label($this->field['settings']['target_type'], $entity);
+  }
+
+  /**
+   * Ensure a base table exists for the query.
+   *
+   * If we have a field-only query, we want to assure we have a base-table
+   * so we can later alter the query in entityFieldQueryAlter().
+   *
+   * @param $query
+   *   The Select query.
+   *
+   * @return
+   *   The alias of the base-table.
+   */
+  public function ensureBaseTable(SelectQueryInterface $query) {
+    $tables = $query->getTables();
+
+    // Check the current base table.
+    foreach ($tables as $table) {
+      if (empty($table['join'])) {
+        $alias = $table['alias'];
+        break;
+      }
+    }
+
+    if (strpos($alias, 'field_data_') !== 0) {
+      // The existing base-table is the correct one.
+      return $alias;
+    }
+
+    // Join the known base-table.
+    $target_type = $this->field['settings']['target_type'];
+    $entity_info = entity_get_info($target_type);
+    $id = $entity_info['entity keys']['id'];
+    // Return the alias of the table.
+    return $query->innerJoin($target_type, NULL, "$target_type.$id = $alias.entity_id");
+  }
+}
+
+/**
+ * Override for the Node type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_node extends EntityReference_SelectionHandler_Generic {
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    // Adding the 'node_access' tag is sadly insufficient for nodes: core
+    // requires us to also know about the concept of 'published' and
+    // 'unpublished'. We need to do that as long as there are no access control
+    // modules in use on the site. As long as one access control module is there,
+    // it is supposed to handle this check.
+    if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
+      $base_table = $this->ensureBaseTable($query);
+      $query->condition("$base_table.status", NODE_PUBLISHED);
+    }
+  }
+}
+
+/**
+ * Override for the User type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_user extends EntityReference_SelectionHandler_Generic {
+  public function buildEntityFieldQuery($match = NULL, $match_operator = 'CONTAINS') {
+    $query = parent::buildEntityFieldQuery($match, $match_operator);
+
+    // The user entity doesn't have a label column.
+    if (isset($match)) {
+      $query->propertyCondition('name', $match, $match_operator);
+    }
+
+    // Adding the 'user_access' tag is sadly insufficient for users: core
+    // requires us to also know about the concept of 'blocked' and
+    // 'active'.
+    if (!user_access('administer users')) {
+      $query->propertyCondition('status', 1);
+    }
+    return $query;
+  }
+
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    if (user_access('administer users')) {
+      // In addition, if the user is administrator, we need to make sure to
+      // match the anonymous user, that doesn't actually have a name in the
+      // database.
+      $conditions = &$query->conditions();
+      foreach ($conditions as $key => $condition) {
+        if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'users.name') {
+          // Remove the condition.
+          unset($conditions[$key]);
+
+          // Re-add the condition and a condition on uid = 0 so that we end up
+          // with a query in the form:
+          //    WHERE (name LIKE :name) OR (:anonymous_name LIKE :name AND uid = 0)
+          $or = db_or();
+          $or->condition($condition['field'], $condition['value'], $condition['operator']);
+          // Sadly, the Database layer doesn't allow us to build a condition
+          // in the form ':placeholder = :placeholder2', because the 'field'
+          // part of a condition is always escaped.
+          // As a (cheap) workaround, we separately build a condition with no
+          // field, and concatenate the field and the condition separately.
+          $value_part = db_and();
+          $value_part->condition('anonymous_name', $condition['value'], $condition['operator']);
+          $value_part->compile(Database::getConnection(), $query);
+          $or->condition(db_and()
+            ->where(str_replace('anonymous_name', ':anonymous_name', (string) $value_part), $value_part->arguments() + array(':anonymous_name' => format_username(user_load(0))))
+            ->condition('users.uid', 0)
+          );
+          $query->condition($or);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Override for the Comment type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_comment extends EntityReference_SelectionHandler_Generic {
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    // Adding the 'comment_access' tag is sadly insufficient for comments: core
+    // requires us to also know about the concept of 'published' and
+    // 'unpublished'.
+    if (!user_access('administer comments')) {
+      $base_table = $this->ensureBaseTable($query);
+      $query->condition("$base_table.status", COMMENT_PUBLISHED);
+    }
+
+    // The Comment module doesn't implement any proper comment access,
+    // and as a consequence doesn't make sure that comments cannot be viewed
+    // when the user doesn't have access to the node.
+    $tables = $query->getTables();
+    $base_table = key($tables);
+    $node_alias = $query->innerJoin('node', 'n', '%alias.nid = ' . $base_table . '.nid');
+    // Pass the query to the node access control.
+    $this->reAlterQuery($query, 'node_access', $node_alias);
+
+    // Alas, the comment entity exposes a bundle, but doesn't have a bundle column
+    // in the database. We have to alter the query ourself to go fetch the
+    // bundle.
+    $conditions = &$query->conditions();
+    foreach ($conditions as $key => &$condition) {
+      if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'node_type') {
+        $condition['field'] = $node_alias . '.type';
+        foreach ($condition['value'] as &$value) {
+          if (substr($value, 0, 13) == 'comment_node_') {
+            $value = substr($value, 13);
+          }
+        }
+        break;
+      }
+    }
+
+    // Passing the query to node_query_node_access_alter() is sadly
+    // insufficient for nodes.
+    // @see EntityReferenceHandler_node::entityFieldQueryAlter()
+    if (!user_access('bypass node access') && !count(module_implements('node_grants'))) {
+      $query->condition($node_alias . '.status', 1);
+    }
+  }
+}
+
+/**
+ * Override for the File type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_file extends EntityReference_SelectionHandler_Generic {
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    // Core forces us to know about 'permanent' vs. 'temporary' files.
+    $tables = $query->getTables();
+    $base_table = key($tables);
+    $query->condition('status', FILE_STATUS_PERMANENT);
+
+    // Access control to files is a very difficult business. For now, we are not
+    // going to give it a shot.
+    // @todo: fix this when core access control is less insane.
+    return $query;
+  }
+
+  public function getLabel($entity) {
+    // The file entity doesn't have a label. More over, the filename is
+    // sometimes empty, so use the basename in that case.
+    return $entity->filename !== '' ? $entity->filename : basename($entity->uri);
+  }
+}
+
+/**
+ * Override for the Taxonomy term type.
+ *
+ * This only exists to workaround core bugs.
+ */
+class EntityReference_SelectionHandler_Generic_taxonomy_term extends EntityReference_SelectionHandler_Generic {
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+    // The Taxonomy module doesn't implement any proper taxonomy term access,
+    // and as a consequence doesn't make sure that taxonomy terms cannot be viewed
+    // when the user doesn't have access to the vocabulary.
+    $base_table = $this->ensureBaseTable($query);
+    $vocabulary_alias = $query->innerJoin('taxonomy_vocabulary', 'n', '%alias.vid = ' . $base_table . '.vid');
+    $query->addMetadata('base_table', $vocabulary_alias);
+    // Pass the query to the taxonomy access control.
+    $this->reAlterQuery($query, 'taxonomy_vocabulary_access', $vocabulary_alias);
+
+    // Also, the taxonomy term entity exposes a bundle, but doesn't have a bundle
+    // column in the database. We have to alter the query ourself to go fetch
+    // the bundle.
+    $conditions = &$query->conditions();
+    foreach ($conditions as $key => &$condition) {
+      if ($key !== '#conjunction' && is_string($condition['field']) && $condition['field'] === 'vocabulary_machine_name') {
+        $condition['field'] = $vocabulary_alias . '.machine_name';
+        break;
+      }
+    }
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getReferencableEntities().
+   */
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
+    if ($match || $limit) {
+      return parent::getReferencableEntities($match , $match_operator, $limit);
+    }
+
+    $options = array();
+    $entity_type = $this->field['settings']['target_type'];
+
+    // We imitate core by calling taxonomy_get_tree().
+    $entity_info = entity_get_info('taxonomy_term');
+    $bundles = !empty($this->field['settings']['handler_settings']['target_bundles']) ? $this->field['settings']['handler_settings']['target_bundles'] : array_keys($entity_info['bundles']);
+
+    foreach ($bundles as $bundle) {
+      if ($vocabulary = taxonomy_vocabulary_machine_name_load($bundle)) {
+        if ($terms = taxonomy_get_tree($vocabulary->vid, 0)) {
+          foreach ($terms as $term) {
+            $options[$vocabulary->machine_name][$term->tid] = str_repeat('-', $term->depth) . check_plain($term->name);
+          }
+        }
+      }
+    }
+
+    return $options;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/selection/EntityReference_SelectionHandler_Views.class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,193 @@
+<?php
+
+/**
+ * Entity handler for Views.
+ */
+class EntityReference_SelectionHandler_Views implements EntityReference_SelectionHandler {
+
+  /**
+   * Implements EntityReferenceHandler::getInstance().
+   */
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    return new EntityReference_SelectionHandler_Views($field, $instance);
+  }
+
+  protected function __construct($field, $instance) {
+    $this->field = $field;
+    $this->instance = $instance;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::settingsForm().
+   */
+  public static function settingsForm($field, $instance) {
+    $view_settings = empty($field['settings']['handler_settings']['view']) ? '' : $field['settings']['handler_settings']['view'];
+    $displays = views_get_applicable_views('entityreference display');
+    // Filter views that list the entity type we want, and group the separate
+    // displays by view.
+    $entity_info = entity_get_info($field['settings']['target_type']);
+    $options = array();
+    foreach ($displays as $data) {
+      list($view, $display_id) = $data;
+      if ($view->base_table == $entity_info['base table']) {
+        $options[$view->name . ':' . $display_id] = $view->name . ' - ' . $view->display[$display_id]->display_title;
+      }
+    }
+
+    // The value of the 'view_and_display' select below will need to be split
+    // into 'view_name' and 'view_display' in the final submitted values, so
+    // we massage the data at validate time on the wrapping element (not
+    // ideal).
+    $form['view']['#element_validate'] = array('entityreference_view_settings_validate');
+
+    if ($options) {
+      $default = !empty($view_settings['view_name']) ? $view_settings['view_name'] . ':' . $view_settings['display_name'] : NULL;
+      $form['view']['view_and_display'] = array(
+        '#type' => 'select',
+        '#title' => t('View used to select the entities'),
+        '#required' => TRUE,
+        '#options' => $options,
+        '#default_value' => $default,
+        '#description' => '<p>' . t('Choose the view and display that select the entities that can be referenced.<br />Only views with a display of type "Entity Reference" are eligible.') . '</p>',
+      );
+
+      $default = !empty($view_settings['args']) ? implode(', ', $view_settings['args']) : '';
+      $form['view']['args'] = array(
+        '#type' => 'textfield',
+        '#title' => t('View arguments'),
+        '#default_value' => $default,
+        '#required' => FALSE,
+        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+      );
+    }
+    else {
+      $form['view']['no_view_help'] = array(
+        '#markup' => '<p>' . t('No eligible views were found. <a href="@create">Create a view</a> with an <em>Entity Reference</em> display, or add such a display to an <a href="@existing">existing view</a>.', array(
+          '@create' => url('admin/structure/views/add'),
+          '@existing' => url('admin/structure/views'),
+        )) . '</p>',
+      );
+    }
+    return $form;
+  }
+
+  protected function initializeView($match = NULL, $match_operator = 'CONTAINS', $limit = 0, $ids = NULL) {
+    $view_name = $this->field['settings']['handler_settings']['view']['view_name'];
+    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
+    $args = $this->field['settings']['handler_settings']['view']['args'];
+    $entity_type = $this->field['settings']['target_type'];
+
+    // Check that the view is valid and the display still exists.
+    $this->view = views_get_view($view_name);
+    if (!$this->view || !isset($this->view->display[$display_name]) || !$this->view->access($display_name)) {
+      watchdog('entityreference', 'The view %view_name is no longer eligible for the %field_name field.', array('%view_name' => $view_name, '%field_name' => $this->instance['label']), WATCHDOG_WARNING);
+      return FALSE;
+    }
+    $this->view->set_display($display_name);
+
+    // Make sure the query is not cached.
+    $this->view->is_cacheable = FALSE;
+
+    // Pass options to the display handler to make them available later.
+    $entityreference_options = array(
+      'match' => $match,
+      'match_operator' => $match_operator,
+      'limit' => $limit,
+      'ids' => $ids,
+    );
+    $this->view->display_handler->set_option('entityreference_options', $entityreference_options);
+    return TRUE;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getReferencableEntities().
+   */
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
+    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
+    $args = $this->field['settings']['handler_settings']['view']['args'];
+    $result = array();
+    if ($this->initializeView($match, $match_operator, $limit)) {
+      // Get the results.
+      $result = $this->view->execute_display($display_name, $args);
+    }
+
+    $return = array();
+    if ($result) {
+      $target_type = $this->field['settings']['target_type'];
+      $entities = entity_load($target_type, array_keys($result));
+      foreach($entities as $entity) {
+        list($id,, $bundle) = entity_extract_ids($target_type, $entity);
+        $return[$bundle][$id] = $result[$id];
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::countReferencableEntities().
+   */
+  function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
+    $this->getReferencableEntities($match, $match_operator);
+    return $this->view->total_items;
+  }
+
+  function validateReferencableEntities(array $ids) {
+    $display_name = $this->field['settings']['handler_settings']['view']['display_name'];
+    $args = $this->field['settings']['handler_settings']['view']['args'];
+    $result = array();
+    if ($this->initializeView(NULL, 'CONTAINS', 0, $ids)) {
+      // Get the results.
+      $entities = $this->view->execute_display($display_name, $args);
+      $result = array_keys($entities);
+    }
+    return $result;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::validateAutocompleteInput().
+   */
+  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
+    return NULL;
+  }
+
+  /**
+   * Implements EntityReferenceHandler::getLabel().
+   */
+  public function getLabel($entity) {
+    return entity_label($this->field['settings']['target_type'], $entity);
+  }
+
+  /**
+   * Implements EntityReferenceHandler::entityFieldQueryAlter().
+   */
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {
+
+  }
+
+}
+
+function entityreference_view_settings_validate($element, &$form_state, $form) {
+  // Split view name and display name from the 'view_and_display' value.
+  if (!empty($element['view_and_display']['#value'])) {
+    list($view, $display) = explode(':', $element['view_and_display']['#value']);
+  }
+  else {
+    form_error($element, t('The views entity selection mode requires a view.'));
+    return;
+  }
+
+  // Explode the 'args' string into an actual array. Beware, explode() turns an
+  // empty string into an array with one empty string. We'll need an empty array
+  // instead.
+  $args_string = trim($element['args']['#value']);
+  if ($args_string === '') {
+    $args = array();
+  }
+  else {
+    // array_map is called to trim whitespaces from the arguments.
+    $args = array_map('trim', explode(',', $args_string));
+  }
+
+  $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
+  form_set_value($element, $value, $form_state);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/selection/abstract.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * @file
+ * Abstraction of the selection logic of an entity reference field.
+ *
+ * Implementations that wish to provide an implementation of this should
+ * register it using CTools' plugin system.
+ */
+interface EntityReference_SelectionHandler {
+  /**
+   * Factory function: create a new instance of this handler for a given field.
+   *
+   * @param $field
+   *   A field datastructure.
+   * @return EntityReferenceHandler
+   */
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL);
+
+  /**
+   * Return a list of referencable entities.
+   *
+   * @return
+   *   An array of referencable entities, which keys are entity ids and
+   *   values (safe HTML) labels to be displayed to the user.
+   */
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0);
+
+  /**
+   * Count entities that are referencable by a given field.
+   */
+  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS');
+
+  /**
+   * Validate that entities can be referenced by this field.
+   *
+   * @return
+   *   An array of entity ids that are valid.
+   */
+  public function validateReferencableEntities(array $ids);
+
+  /**
+   * Validate Input from autocomplete widget that has no Id.
+   *
+   * @see _entityreference_autocomplete_validate()
+   *
+   * @param $input
+   * 	 Single string from autocomplete widget.
+   * @param $element
+   *   The form element to set a form error.
+   * @return
+   *   Value of a matching entity id, or NULL if none.
+   */
+  public function validateAutocompleteInput($input, &$element, &$form_state, $form);
+
+  /**
+   * Give the handler a chance to alter the SelectQuery generated by EntityFieldQuery.
+   */
+  public function entityFieldQueryAlter(SelectQueryInterface $query);
+
+  /**
+   * Return the label of a given entity.
+   */
+  public function getLabel($entity);
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public static function settingsForm($field, $instance);
+}
+
+/**
+ * A null implementation of EntityReference_SelectionHandler.
+ */
+class EntityReference_SelectionHandler_Broken implements EntityReference_SelectionHandler {
+  public static function getInstance($field, $instance = NULL, $entity_type = NULL, $entity = NULL) {
+    return new EntityReference_SelectionHandler_Broken($field, $instance, $entity_type, $entity);
+  }
+
+  protected function __construct($field, $instance) {
+    $this->field = $field;
+    $this->instance = $instance;
+  }
+
+  public static function settingsForm($field, $instance) {
+    $form['selection_handler'] = array(
+      '#markup' => t('The selected selection handler is broken.'),
+    );
+    return $form;
+  }
+
+  public function getReferencableEntities($match = NULL, $match_operator = 'CONTAINS', $limit = 0) {
+    return array();
+  }
+
+  public function countReferencableEntities($match = NULL, $match_operator = 'CONTAINS') {
+    return 0;
+  }
+
+  public function validateReferencableEntities(array $ids) {
+    return array();
+  }
+
+  public function validateAutocompleteInput($input, &$element, &$form_state, $form) {
+    return NULL;
+  }
+
+  public function entityFieldQueryAlter(SelectQueryInterface $query) {}
+
+  public function getLabel($entity) {
+    return '';
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/selection/base.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,7 @@
+<?php
+
+$plugin = array(
+  'title' => t('Simple (with optional filter by bundle)'),
+  'class' => 'EntityReference_SelectionHandler_Generic',
+  'weight' => -100,
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/plugins/selection/views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,9 @@
+<?php
+
+if (module_exists('views')) {
+  $plugin = array(
+    'title' => t('Views: Filter by an entity reference view'),
+    'class' => 'EntityReference_SelectionHandler_Views',
+    'weight' => 0,
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/tests/entityreference.admin.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ * Contains EntityReferenceHandlersTestCase
+ */
+
+/**
+ * Test for Entity Reference admin UI.
+ */
+class EntityReferenceAdminTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity Reference UI',
+      'description' => 'Tests for the administrative UI.',
+      'group' => 'Entity Reference',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp(array('field_ui', 'entity', 'ctools', 'entityreference'));
+
+    // Create test user.
+    $this->admin_user = $this->drupalCreateUser(array('access content', 'administer content types'));
+    $this->drupalLogin($this->admin_user);
+
+    // Create content type, with underscores.
+    $type_name = strtolower($this->randomName(8)) . '_test';
+    $type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
+    $this->type = $type->type;
+    // Store a valid URL name, with hyphens instead of underscores.
+    $this->hyphen_type = str_replace('_', '-', $this->type);
+  }
+
+  protected function assertFieldSelectOptions($name, $expected_options) {
+    $xpath = $this->buildXPathQuery('//select[@name=:name]', array(':name' => $name));
+    $fields = $this->xpath($xpath);
+    if ($fields) {
+      $field = $fields[0];
+      $options = $this->getAllOptionsList($field);
+      return $this->assertIdentical($options, $expected_options);
+    }
+    else {
+      return $this->fail(t('Unable to find field @name', array('@name' => $name)));
+    }
+  }
+
+  /**
+   * Extract all the options of a select element.
+   */
+  protected function getAllOptionsList($element) {
+    $options = array();
+    // Add all options items.
+    foreach ($element->option as $option) {
+      $options[] = (string) $option['value'];
+    }
+    // TODO: support optgroup.
+    return $options;
+  }
+
+  public function testFieldAdminHandler() {
+    $bundle_path = 'admin/structure/types/manage/' . $this->hyphen_type;
+
+    // First step: 'Add new field' on the 'Manage fields' page.
+    $this->drupalPost($bundle_path . '/fields', array(
+      'fields[_add_new_field][label]' => 'Test label',
+      'fields[_add_new_field][field_name]' => 'test',
+      'fields[_add_new_field][type]' => 'entityreference',
+      'fields[_add_new_field][widget_type]' => 'entityreference_autocomplete',
+    ), t('Save'));
+
+    // Node should be selected by default.
+    $this->assertFieldByName('field[settings][target_type]', 'node');
+    // The base handler should be selected by default.
+    $this->assertFieldByName('field[settings][handler]', 'base');
+
+    // The base handler settings should be diplayed.
+    $entity_type = 'node';
+    $entity_info = entity_get_info($entity_type);
+    foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+      $this->assertFieldByName('field[settings][handler_settings][target_bundles][' . $bundle_name . ']');
+    }
+
+    // Test the sort settings.
+    $options = array('none', 'property', 'field');
+    $this->assertFieldSelectOptions('field[settings][handler_settings][sort][type]', $options);
+    // Option 0: no sort.
+    $this->assertFieldByName('field[settings][handler_settings][sort][type]', 'none');
+    $this->assertNoFieldByName('field[settings][handler_settings][sort][property]');
+    $this->assertNoFieldByName('field[settings][handler_settings][sort][field]');
+    $this->assertNoFieldByName('field[settings][handler_settings][sort][direction]');
+    // Option 1: sort by property.
+    $this->drupalPostAJAX(NULL, array('field[settings][handler_settings][sort][type]' => 'property'), 'field[settings][handler_settings][sort][type]');
+    $this->assertFieldByName('field[settings][handler_settings][sort][property]', '');
+    $this->assertNoFieldByName('field[settings][handler_settings][sort][field]');
+    $this->assertFieldByName('field[settings][handler_settings][sort][direction]', 'ASC');
+    // Option 2: sort by field.
+    $this->drupalPostAJAX(NULL, array('field[settings][handler_settings][sort][type]' => 'field'), 'field[settings][handler_settings][sort][type]');
+    $this->assertNoFieldByName('field[settings][handler_settings][sort][property]');
+    $this->assertFieldByName('field[settings][handler_settings][sort][field]', '');
+    $this->assertFieldByName('field[settings][handler_settings][sort][direction]', 'ASC');
+    // Set back to no sort.
+    $this->drupalPostAJAX(NULL, array('field[settings][handler_settings][sort][type]' => 'none'), 'field[settings][handler_settings][sort][type]');
+
+    // Second step: 'Instance settings' form.
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+
+    // Third step: confirm.
+    $this->drupalPost(NULL, array(), t('Save settings'));
+
+    // Check that the field appears in the overview form.
+    $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', 'Test label', t('Field was created and appears in the overview page.'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/tests/entityreference.handlers.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,575 @@
+<?php
+
+/**
+ * @file
+ * Contains EntityReferenceHandlersTestCase
+ */
+
+/**
+ * Test for Entity Reference handlers.
+ */
+class EntityReferenceHandlersTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity Reference Handlers',
+      'description' => 'Tests for the base handlers provided by Entity Reference.',
+      'group' => 'Entity Reference',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('entityreference');
+  }
+
+  protected function assertReferencable($field, $tests, $handler_name) {
+    $handler = entityreference_get_selection_handler($field);
+
+    foreach ($tests as $test) {
+      foreach ($test['arguments'] as $arguments) {
+        $result = call_user_func_array(array($handler, 'getReferencableEntities'), $arguments);
+        $this->assertEqual($result, $test['result'], format_string('Valid result set returned by @handler.', array('@handler' => $handler_name)));
+
+        $result = call_user_func_array(array($handler, 'countReferencableEntities'), $arguments);
+        if (!empty($test['result'])) {
+          $bundle = key($test['result']);
+          $count = count($test['result'][$bundle]);
+        }
+        else {
+          $count = 0;
+        }
+
+        $this->assertEqual($result, $count, format_string('Valid count returned by @handler.', array('@handler' => $handler_name)));
+      }
+    }
+  }
+
+  /**
+   * Test the node-specific overrides of the entity handler.
+   */
+  public function testNodeHandler() {
+    // Build a fake field instance.
+    $field = array(
+      'translatable' => FALSE,
+      'entity_types' => array(),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'node',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+        ),
+      ),
+      'field_name' => 'test_field',
+      'type' => 'entityreference',
+      'cardinality' => '1',
+    );
+
+    // Build a set of test data.
+    // Titles contain HTML-special characters to test escaping.
+    $nodes = array(
+      'published1' => (object) array(
+        'type' => 'article',
+        'status' => 1,
+        'title' => 'Node published1 (<&>)',
+        'uid' => 1,
+      ),
+      'published2' => (object) array(
+        'type' => 'article',
+        'status' => 1,
+        'title' => 'Node published2 (<&>)',
+        'uid' => 1,
+      ),
+      'unpublished' => (object) array(
+        'type' => 'article',
+        'status' => 0,
+        'title' => 'Node unpublished (<&>)',
+        'uid' => 1,
+      ),
+    );
+
+    $node_labels = array();
+    foreach ($nodes as $key => $node) {
+      node_save($node);
+      $node_labels[$key] = check_plain($node->title);
+    }
+
+    // Test as a non-admin.
+    $normal_user = $this->drupalCreateUser(array('access content'));
+    $GLOBALS['user'] = $normal_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          'article' => array(
+            $nodes['published1']->nid => $node_labels['published1'],
+            $nodes['published2']->nid => $node_labels['published2'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('published1', 'CONTAINS'),
+          array('Published1', 'CONTAINS'),
+        ),
+        'result' => array(
+          'article' => array(
+            $nodes['published1']->nid => $node_labels['published1'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('published2', 'CONTAINS'),
+          array('Published2', 'CONTAINS'),
+        ),
+        'result' => array(
+          'article' => array(
+            $nodes['published2']->nid => $node_labels['published2'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('invalid node', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+      array(
+        'arguments' => array(
+          array('Node unpublished', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Node handler');
+
+    // Test as an admin.
+    $admin_user = $this->drupalCreateUser(array('access content', 'bypass node access'));
+    $GLOBALS['user'] = $admin_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          'article' => array(
+            $nodes['published1']->nid => $node_labels['published1'],
+            $nodes['published2']->nid => $node_labels['published2'],
+            $nodes['unpublished']->nid => $node_labels['unpublished'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('Node unpublished', 'CONTAINS'),
+        ),
+        'result' => array(
+          'article' => array(
+            $nodes['unpublished']->nid => $node_labels['unpublished'],
+          ),
+        ),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Node handler (admin)');
+  }
+
+  /**
+   * Test the user-specific overrides of the entity handler.
+   */
+  public function testUserHandler() {
+    // Build a fake field instance.
+    $field = array(
+      'translatable' => FALSE,
+      'entity_types' => array(),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'user',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+        ),
+      ),
+      'field_name' => 'test_field',
+      'type' => 'entityreference',
+      'cardinality' => '1',
+    );
+
+    // Build a set of test data.
+    $users = array(
+      'anonymous' => user_load(0),
+      'admin' => user_load(1),
+      'non_admin' => (object) array(
+        'name' => 'non_admin <&>',
+        'mail' => 'non_admin@example.com',
+        'roles' => array(),
+        'pass' => user_password(),
+        'status' => 1,
+      ),
+      'blocked' => (object) array(
+        'name' => 'blocked <&>',
+        'mail' => 'blocked@example.com',
+        'roles' => array(),
+        'pass' => user_password(),
+        'status' => 0,
+      ),
+    );
+
+    // The label of the anonymous user is variable_get('anonymous').
+    $users['anonymous']->name = variable_get('anonymous', t('Anonymous'));
+
+    $user_labels = array();
+    foreach ($users as $key => $user) {
+      if (!isset($user->uid)) {
+        $users[$key] = $user = user_save(drupal_anonymous_user(), (array) $user);
+      }
+      $user_labels[$key] = check_plain($user->name);
+    }
+
+    // Test as a non-admin.
+    $GLOBALS['user'] = $users['non_admin'];
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          'user' => array(
+            $users['admin']->uid => $user_labels['admin'],
+            $users['non_admin']->uid => $user_labels['non_admin'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('non_admin', 'CONTAINS'),
+          array('NON_ADMIN', 'CONTAINS'),
+        ),
+        'result' => array(
+          'user' => array(
+            $users['non_admin']->uid => $user_labels['non_admin'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('invalid user', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+      array(
+        'arguments' => array(
+          array('blocked', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'User handler');
+
+    $GLOBALS['user'] = $users['admin'];
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          'user' => array(
+            $users['anonymous']->uid => $user_labels['anonymous'],
+            $users['admin']->uid => $user_labels['admin'],
+            $users['non_admin']->uid => $user_labels['non_admin'],
+            $users['blocked']->uid => $user_labels['blocked'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('blocked', 'CONTAINS'),
+        ),
+        'result' => array(
+          'user' => array(
+            $users['blocked']->uid => $user_labels['blocked'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('Anonymous', 'CONTAINS'),
+          array('anonymous', 'CONTAINS'),
+        ),
+        'result' => array(
+          'user' => array(
+            $users['anonymous']->uid => $user_labels['anonymous'],
+          ),
+        ),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'User handler (admin)');
+  }
+
+  /**
+   * Test the comment-specific overrides of the entity handler.
+   */
+  public function testCommentHandler() {
+    // Build a fake field instance.
+    $field = array(
+      'translatable' => FALSE,
+      'entity_types' => array(),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'comment',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+        ),
+      ),
+      'field_name' => 'test_field',
+      'type' => 'entityreference',
+      'cardinality' => '1',
+    );
+
+    // Build a set of test data.
+    $nodes = array(
+      'published' => (object) array(
+        'type' => 'article',
+        'status' => 1,
+        'title' => 'Node published',
+        'uid' => 1,
+      ),
+      'unpublished' => (object) array(
+        'type' => 'article',
+        'status' => 0,
+        'title' => 'Node unpublished',
+        'uid' => 1,
+      ),
+    );
+    foreach ($nodes as $node) {
+      node_save($node);
+    }
+
+    $comments = array(
+      'published_published' => (object) array(
+        'nid' => $nodes['published']->nid,
+        'uid' => 1,
+        'cid' => NULL,
+        'pid' => 0,
+        'status' => COMMENT_PUBLISHED,
+        'subject' => 'Comment Published <&>',
+        'hostname' => ip_address(),
+        'language' => LANGUAGE_NONE,
+      ),
+      'published_unpublished' => (object) array(
+        'nid' => $nodes['published']->nid,
+        'uid' => 1,
+        'cid' => NULL,
+        'pid' => 0,
+        'status' => COMMENT_NOT_PUBLISHED,
+        'subject' => 'Comment Unpublished <&>',
+        'hostname' => ip_address(),
+        'language' => LANGUAGE_NONE,
+      ),
+      'unpublished_published' => (object) array(
+        'nid' => $nodes['unpublished']->nid,
+        'uid' => 1,
+        'cid' => NULL,
+        'pid' => 0,
+        'status' => COMMENT_NOT_PUBLISHED,
+        'subject' => 'Comment Published on Unpublished node <&>',
+        'hostname' => ip_address(),
+        'language' => LANGUAGE_NONE,
+      ),
+    );
+
+    $comment_labels = array();
+    foreach ($comments as $key => $comment) {
+      comment_save($comment);
+      $comment_labels[$key] = check_plain($comment->subject);
+    }
+
+    // Test as a non-admin.
+    $normal_user = $this->drupalCreateUser(array('access content', 'access comments'));
+    $GLOBALS['user'] = $normal_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          'comment_node_article' => array(
+            $comments['published_published']->cid => $comment_labels['published_published'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('Published', 'CONTAINS'),
+        ),
+        'result' => array(
+          'comment_node_article' => array(
+            $comments['published_published']->cid => $comment_labels['published_published'],
+          ),
+        ),
+      ),
+      array(
+        'arguments' => array(
+          array('invalid comment', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+      array(
+        'arguments' => array(
+          array('Comment Unpublished', 'CONTAINS'),
+        ),
+        'result' => array(),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Comment handler');
+
+    // Test as a comment admin.
+    $admin_user = $this->drupalCreateUser(array('access content', 'access comments', 'administer comments'));
+    $GLOBALS['user'] = $admin_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          'comment_node_article' => array(
+            $comments['published_published']->cid => $comment_labels['published_published'],
+            $comments['published_unpublished']->cid => $comment_labels['published_unpublished'],
+          ),
+        ),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Comment handler (comment admin)');
+
+    // Test as a node and comment admin.
+    $admin_user = $this->drupalCreateUser(array('access content', 'access comments', 'administer comments', 'bypass node access'));
+    $GLOBALS['user'] = $admin_user;
+    $referencable_tests = array(
+      array(
+        'arguments' => array(
+          array(NULL, 'CONTAINS'),
+        ),
+        'result' => array(
+          'comment_node_article' => array(
+            $comments['published_published']->cid => $comment_labels['published_published'],
+            $comments['published_unpublished']->cid => $comment_labels['published_unpublished'],
+            $comments['unpublished_published']->cid => $comment_labels['unpublished_published'],
+          ),
+        ),
+      ),
+    );
+    $this->assertReferencable($field, $referencable_tests, 'Comment handler (comment + node admin)');
+  }
+
+  /**
+   * Assert sorting by field works for non-admins.
+   *
+   * Since we are sorting on a field, we need to make sure the base-table
+   * is added, and access-control is behaving as expected.
+   */
+  public function testSortByField() {
+    // Add text field to entity, to sort by.
+    $field_info = array(
+      'field_name' => 'field_text',
+      'type' => 'text',
+      'entity_types' => array('node'),
+    );
+    field_create_field($field_info);
+
+    $instance = array(
+      'label' => 'Text Field',
+      'field_name' => 'field_text',
+      'entity_type' => 'node',
+      'bundle' => 'article',
+      'settings' => array(),
+      'required' => FALSE,
+    );
+    field_create_instance($instance);
+
+
+    // Build a fake field instance.
+    $field = array(
+      'translatable' => FALSE,
+      'entity_types' => array(),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'node',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+          // Add sorting.
+          'sort' => array(
+            'type' => 'field',
+            'field' => 'field_text:value',
+            'direction' => 'DESC',
+          ),
+        ),
+      ),
+      'field_name' => 'test_field',
+      'type' => 'entityreference',
+      'cardinality' => '1',
+    );
+
+    // Build a set of test data.
+    $nodes = array(
+      'published1' => (object) array(
+        'type' => 'article',
+        'status' => 1,
+        'title' => 'Node published1 (<&>)',
+        'uid' => 1,
+        'field_text' => array(
+          LANGUAGE_NONE => array(
+            array(
+              'value' => 1,
+            ),
+          ),
+        ),
+      ),
+      'published2' => (object) array(
+        'type' => 'article',
+        'status' => 1,
+        'title' => 'Node published2 (<&>)',
+        'uid' => 1,
+        'field_text' => array(
+          LANGUAGE_NONE => array(
+            array(
+              'value' => 2,
+            ),
+          ),
+        ),
+      ),
+      'unpublished' => (object) array(
+        'type' => 'article',
+        'status' => 0,
+        'title' => 'Node unpublished (<&>)',
+        'uid' => 1,
+        'field_text' => array(
+          LANGUAGE_NONE => array(
+            array(
+              'value' => 3,
+            ),
+          ),
+        ),
+      ),
+    );
+
+    $node_labels = array();
+    foreach ($nodes as $key => $node) {
+      node_save($node);
+      $node_labels[$key] = check_plain($node->title);
+    }
+
+    // Test as a non-admin.
+    $normal_user = $this->drupalCreateUser(array('access content'));
+    $GLOBALS['user'] = $normal_user;
+
+    $handler = entityreference_get_selection_handler($field);
+
+    // Not only assert the result, but make sure the keys are sorted as
+    // expected.
+    $result = $handler->getReferencableEntities();
+    $expected_result = array(
+      $nodes['published2']->nid => $node_labels['published2'],
+      $nodes['published1']->nid => $node_labels['published1'],
+    );
+    $this->assertIdentical($result['article'], $expected_result, 'Query sorted by field returned expected values for non-admin.');
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/tests/entityreference.taxonomy.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Test for Entity Reference taxonomy integration.
+ */
+class EntityReferenceTaxonomyTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity Reference Taxonomy',
+      'description' => 'Tests nodes with reference to terms as indexed.',
+      'group' => 'Entity Reference',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('entityreference', 'taxonomy');
+
+    // Create an entity reference field.
+    $field = array(
+      'entity_types' => array('node'),
+      'settings' => array(
+        'handler' => 'base',
+        'target_type' => 'taxonomy_term',
+        'handler_settings' => array(
+          'target_bundles' => array(),
+        ),
+      ),
+      'field_name' => 'field_entityreference_term',
+      'type' => 'entityreference',
+    );
+    $field = field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_entityreference_term',
+      'bundle' => 'article',
+      'entity_type' => 'node',
+    );
+
+    // Enable the taxonomy-index behavior.
+    $instance['settings']['behaviors']['taxonomy-index']['status'] = TRUE;
+    field_create_instance($instance);
+
+    // Create a term reference field.
+    $field = array(
+      'translatable' => FALSE,
+      'entity_types' => array('node'),
+      'settings' => array(
+        'allowed_values' => array(
+          array(
+            'vocabulary' => 'terms',
+            'parent' => 0,
+          ),
+        ),
+      ),
+      'field_name' => 'field_taxonomy_term',
+      'type' => 'taxonomy_term_reference',
+    );
+    $field = field_create_field($field);
+    $instance = array(
+      'field_name' => 'field_taxonomy_term',
+      'bundle' => 'article',
+      'entity_type' => 'node',
+    );
+    field_create_instance($instance);
+
+    // Create a terms vocobulary.
+    $vocabulary = new stdClass();
+    $vocabulary->name = 'Terms';
+    $vocabulary->machine_name = 'terms';
+    taxonomy_vocabulary_save($vocabulary);
+
+    // Create term.
+    for ($i = 1; $i <= 2; $i++) {
+      $term = new stdClass();
+      $term->name = "term $i";
+      $term->vid = 1;
+      taxonomy_term_save($term);
+    }
+  }
+
+  /**
+   * Test referencing a term using entity reference field.
+   */
+  public function testNodeIndex() {
+    // Asert node insert with reference to term.
+    $settings = array();
+    $settings['type'] = 'article';
+    $settings['field_entityreference_term'][LANGUAGE_NONE][0]['target_id'] = 1;
+    $node = $this->drupalCreateNode($settings);
+
+    $this->assertEqual(taxonomy_select_nodes(1), array($node->nid));
+
+    // Asert node update with reference to term.
+    node_save($node);
+    $this->assertEqual(taxonomy_select_nodes(1), array($node->nid));
+
+    // Assert node update with reference to term and taxonomy reference to
+    // another term.
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $wrapper->field_taxonomy_term->set(2);
+    $wrapper->save();
+
+    $this->assertEqual(taxonomy_select_nodes(1), array($node->nid));
+    $this->assertEqual(taxonomy_select_nodes(2), array($node->nid));
+
+    // Assert node update with reference to term and taxonomy reference to
+    // same term.
+    $wrapper->field_taxonomy_term->set(1);
+    $wrapper->save();
+    $this->assertEqual(taxonomy_select_nodes(1), array($node->nid));
+
+    $wrapper->delete();
+    $this->assertFalse(taxonomy_select_nodes(1));
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/views/entityreference.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * @file
+ * Views integration for Entity Reference.
+ */
+
+/**
+ * Implements hook_field_views_data().
+ */
+function entityreference_field_views_data($field) {
+  $data = field_views_field_default_views_data($field);
+  $entity_info = entity_get_info($field['settings']['target_type']);
+  foreach ($data as $table_name => $table_data) {
+    if (isset($entity_info['base table'])) {
+      $entity = $entity_info['label'];
+      if ($entity == t('Node')) {
+        $entity = t('Content');
+      }
+
+      $field_name = $field['field_name'] . '_target_id';
+      $parameters = array('@entity' => $entity, '!field_name' => $field['field_name']);
+      $data[$table_name][$field_name]['relationship'] = array(
+        'handler' => 'views_handler_relationship',
+        'base' => $entity_info['base table'],
+        'base field' => $entity_info['entity keys']['id'],
+        'label' => t('@entity entity referenced from !field_name', $parameters),
+        'group' => t('Entity Reference'),
+        'title' => t('Referenced Entity'),
+        'help' => t('A bridge to the @entity entity that is referenced via !field_name', $parameters),
+      );
+    }
+  }
+
+  // Invoke the behaviors to allow them to change the properties.
+  foreach (entityreference_get_behavior_handlers($field) as $handler) {
+    $handler->views_data_alter($data, $field);
+  }
+
+  return $data;
+}
+
+/**
+ * Options callback for Views handler views_handler_filter_in_operator.
+ */
+function entityreference_views_handler_options_list($field_name) {
+  $field = field_info_field($field_name);
+  return entityreference_options_list($field);
+}
+
+/**
+ * Implements hook_field_views_data_views_data_alter().
+ *
+ * Views integration to provide reverse relationships on entityreference fields.
+ */
+function entityreference_field_views_data_views_data_alter(&$data, $field) {
+  foreach ($field['bundles'] as $entity_type => $bundles) {
+    $target_entity_info = entity_get_info($field['settings']['target_type']);
+    if (isset($target_entity_info['base table'])) {
+      $entity_info = entity_get_info($entity_type);
+      $entity = $entity_info['label'];
+      if ($entity == t('Node')) {
+        $entity = t('Content');
+      }
+      $target_entity = $target_entity_info['label'];
+      if ($target_entity == t('Node')) {
+        $target_entity = t('Content');
+      }
+
+      $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
+      $replacements = array('@entity' => $entity, '@target_entity' => $target_entity, '!field_name' => $field['field_name']);
+      $data[$target_entity_info['base table']][$pseudo_field_name]['relationship'] = array(
+        'handler' => 'views_handler_relationship_entity_reverse',
+        'field_name' => $field['field_name'],
+        'field table' => _field_sql_storage_tablename($field),
+        'field field' => $field['field_name'] . '_target_id',
+        'base' => $entity_info['base table'],
+        'base field' => $entity_info['entity keys']['id'],
+        'label' => t('@entity referencing @target_entity from !field_name', $replacements),
+        'group' => t('Entity Reference'),
+        'title' => t('Referencing entity'),
+        'help' => t('A bridge to the @entity entity that is referencing @target_entity via !field_name', $replacements),
+      );
+    }
+  }
+}
+
+/**
+ * Implements hook_views_plugins().
+ */
+function entityreference_views_plugins() {
+  $plugins = array(
+    'display' => array(
+      'entityreference' => array(
+        'title' => t('Entity Reference'),
+        'admin' => t('Entity Reference Source'),
+        'help' => 'Selects referenceable entities for an entity reference field',
+        'handler' => 'entityreference_plugin_display',
+        'uses hook menu' => FALSE,
+        'use ajax' => FALSE,
+        'use pager' => FALSE,
+        'accept attachments' => FALSE,
+        // Custom property, used with views_get_applicable_views() to retrieve
+        // all views with a 'Entity Reference' display.
+        'entityreference display' => TRUE,
+      ),
+    ),
+    'style' => array(
+      'entityreference_style' => array(
+        'title' => t('Entity Reference list'),
+        'help' => 'Returns results as a PHP array of labels and rendered rows.',
+        'handler' => 'entityreference_plugin_style',
+        'theme' => 'views_view_unformatted',
+        'uses row plugin' => TRUE,
+        'uses fields' => TRUE,
+        'uses options' => TRUE,
+        'type' => 'entityreference',
+        'even empty' => TRUE,
+      ),
+    ),
+    'row' => array(
+      'entityreference_fields' => array(
+        'title' => t('Inline fields'),
+        'help' => t('Displays the fields with an optional template.'),
+        'handler' => 'entityreference_plugin_row_fields',
+        'theme' => 'views_view_fields',
+        'theme path' => drupal_get_path('module', 'views') . '/theme',
+        'theme file' => 'theme.inc',
+        'uses fields' => TRUE,
+        'uses options' => TRUE,
+        'type' => 'entityreference',
+      ),
+    ),
+  );
+  return $plugins;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/views/entityreference_plugin_display.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * @file
+ * Handler for entityreference_plugin_display.
+ */
+class entityreference_plugin_display extends views_plugin_display {
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    // Force the style plugin to 'entityreference_style' and the row plugin to
+    // 'fields'.
+    $options['style_plugin']['default'] = 'entityreference_style';
+    $options['defaults']['default']['style_plugin'] = FALSE;
+    $options['defaults']['default']['style_options'] = FALSE;
+    $options['row_plugin']['default'] = 'entityreference_fields';
+    $options['defaults']['default']['row_plugin'] = FALSE;
+    $options['defaults']['default']['row_options'] = FALSE;
+
+    // Set the display title to an empty string (not used in this display type).
+    $options['title']['default'] = '';
+    $options['defaults']['default']['title'] = FALSE;
+
+    return $options;
+  }
+
+  function get_style_type() {
+    return 'entityreference';
+  }
+
+  function execute() {
+    return $this->view->render($this->display->id);
+  }
+
+  function render() {
+    if (!empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty'])) {
+      return $this->view->style_plugin->render($this->view->result);
+    }
+    return '';
+  }
+
+  function uses_exposed() {
+    return FALSE;
+  }
+
+  function query() {
+    $options = $this->get_option('entityreference_options');
+
+    // Play nice with Views UI 'preview' : if the view is not executed through
+    // EntityReference_SelectionHandler_Views::getReferencableEntities(),
+    // don't alter the query.
+    if (empty($options)) {
+      return;
+    }
+
+    // Make sure the id field is included in the results, and save its alias
+    // so that references_plugin_style can retrieve it.
+    $this->id_field_alias = $id_field = $this->view->query->add_field($this->view->base_table, $this->view->base_field);
+    if (strpos($id_field, '.') === FALSE) {
+      $id_field = $this->view->base_table . '.' . $this->id_field_alias;
+    }
+
+    // Restrict the autocomplete options based on what's been typed already.
+    if (isset($options['match'])) {
+      $style_options = $this->get_option('style_options');
+      $value = db_like($options['match']) . '%';
+      if ($options['match_operator'] != 'STARTS_WITH') {
+        $value = '%' . $value;
+      }
+
+      // Multiple search fields are OR'd together
+      $conditions = db_or();
+
+      // Build the condition using the selected search fields
+      foreach ($style_options['search_fields'] as $field_alias) {
+        if (!empty($field_alias)) {
+          // Get the table and field names for the checked field
+          $field = $this->view->query->fields[$this->view->field[$field_alias]->field_alias];
+          // Add an OR condition for the field
+          $conditions->condition($field['table'] . '.' . $field['field'], $value, 'LIKE');
+        }
+      }
+
+      $this->view->query->add_where(NULL, $conditions);
+    }
+
+    // Add an IN condition for validation.
+    if (!empty($options['ids'])) {
+      $this->view->query->add_where(NULL, $id_field, $options['ids']);
+    }
+
+    $this->view->set_items_per_page($options['limit']);
+  }
+
+  /**
+   * Extend the default validation.
+   */
+  function validate() {
+    $errors = parent::validate();
+    // Verify that search fields are set up.
+    $style_options = $this->get_option('style_options');
+    if (!isset($style_options['search_fields'])) {
+      $errors[] = t('Display "@display" needs a selected search fields to work properly. See the settings for the Entity Reference list format.', array('@display' => $this->display->display_title));
+    }
+    else {
+      // Verify that the search fields used actually exist.
+      //$fields = array_keys($this->view->get_items('field'));
+      $fields = array_keys($this->handlers['field']);
+      foreach ($style_options['search_fields'] as $field_alias => $enabled) {
+        if ($enabled && !in_array($field_alias, $fields)) {
+          $errors[] = t('Display "@display" uses field %field as search field, but the field is no longer present. See the settings for the Entity Reference list format.', array('@display' => $this->display->display_title, '%field' => $field_alias));
+        }
+      }
+    }
+    return $errors;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/views/entityreference_plugin_row_fields.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Handler for entityreference_plugin_row_fields.
+ */
+class entityreference_plugin_row_fields extends views_plugin_row_fields {
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['separator'] = array('default' => '-');
+
+    return $options;
+  }
+
+  /**
+   * Provide a form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Expand the description of the 'Inline field' checkboxes.
+    $form['inline']['#description'] .= '<br />' . t("<strong>Note:</strong> In 'Entity Reference' displays, all fields will be displayed inline unless an explicit selection of inline fields is made here." );
+  }
+
+  function pre_render($row) {
+    // Force all fields to be inline by default.
+    if (empty($this->options['inline'])) {
+      $fields = $this->view->get_items('field', $this->display->id);
+      $this->options['inline'] = drupal_map_assoc(array_keys($fields));
+    }
+
+    return parent::pre_render($row);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference/views/entityreference_plugin_style.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Handler for entityreference_plugin_style.
+ */
+class entityreference_plugin_style extends views_plugin_style {
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['search_fields'] = array('default' => NULL);
+
+    return $options;
+  }
+
+  // Create the options form.
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $options = array();
+
+    if (isset($form['grouping'])) {
+      $options = $form['grouping'][0]['field']['#options'];
+      unset($options['']);
+      $form['search_fields'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Search fields'),
+        '#options' => $options,
+        '#required' => TRUE,
+        '#default_value' => $this->options['search_fields'],
+        '#description' => t('Select the field(s) that will be searched when using the autocomplete widget.'),
+        '#weight' => -3,
+      );
+    }
+  }
+
+  function render() {
+    $options = $this->display->handler->get_option('entityreference_options');
+
+    // Play nice with Views UI 'preview' : if the view is not executed through
+    // EntityReference_SelectionHandler_Views::getReferencableEntities(), just
+    // display the HTML.
+    if (empty($options)) {
+      return parent::render();
+    }
+
+    // Group the rows according to the grouping field, if specified.
+    $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
+
+    // Grab the alias of the 'id' field added by entityreference_plugin_display.
+    $id_field_alias = $this->display->handler->id_field_alias;
+
+    // @todo We don't display grouping info for now. Could be useful for select
+    // widget, though.
+    $results = array();
+    $this->view->row_index = 0;
+    foreach ($sets as $records) {
+      foreach ($records as $values) {
+        // Sanitize html, remove line breaks and extra whitespace.
+        $results[$values->{$id_field_alias}] = filter_xss_admin(preg_replace('/\s\s+/', ' ', str_replace("\n", '', $this->row_plugin->render($values))));
+        $this->view->row_index++;
+      }
+    }
+    unset($this->view->row_index);
+    return $results;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,42 @@
+Description
+===========
+Allows the contents of an "Entity Reference" field to be pre-populated by
+taking a parameter from the URL path.
+
+Install
+=======
+1. Download and enable the module.
+2. Visit admin/structure/types/manage/[ENTITY-TYPE]/fields/[FIELD-NAME]
+3. Enable "Entity reference prepopulate" under the instance settings.
+
+
+Configuration
+=============
+Enable Entity reference prepopulate:
+  Check this to enable Entity reference prepopulate on this field.
+Action
+  Using the select box choose the action to take if the entity reference
+  field is pre-populated.
+Fallback behaviour
+  Select what to do if the URL path does NOT contain a parameter to
+  pre-populate the field.
+Skip access permission
+  This is a fallback overide, the fallback behaviour will not be followed
+  for users with the specified permission.
+
+Usage
+=====
+In order to pre-populate an entity reference field you have to supply the
+paramater in the URL.
+
+The structure is
+node/add/article?[field_ref]=[id]
+
+Where [field_ref] is the name of the entity reference field and [id] is
+the id of the entity being referenced.
+
+Examples:
+node/add/article?field_foo=1
+node/add/page?field_bar=1,2,3
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/entityreference_prepopulate.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Entity reference prepopulate
+description = Prepopulate entity reference values from URL.
+core = 7.x
+package = Fields
+dependencies[] = entityreference
+
+files[] = entityreference_prepopulate.test
+
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-1.3"
+core = "7.x"
+project = "entityreference_prepopulate"
+datestamp = "1366630855"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/entityreference_prepopulate.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,429 @@
+<?php
+
+/**
+ * @file
+ * Prepopulate entity reference values from URL.
+ */
+
+/**
+ * Implements hook_ctools_plugin_directory().
+ */
+function entityreference_prepopulate_ctools_plugin_directory($module, $plugin) {
+  if ($module == 'entityreference' || $module == 'ctools') {
+    return 'plugins/' . $plugin;
+  }
+}
+
+/**
+ * Implements hook_field_create_instance().
+ *
+ * Add "default value function" setting to the field instance.
+ * We have to do it from this hook, as we don't have another chance of setting
+ * this option via the hook_field_info().
+ */
+function entityreference_prepopulate_field_create_instance($instance) {
+  if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
+    return;
+  }
+
+  $instance['default_value_function'] = 'entityreference_prepopulate_field_default_value';
+  field_update_instance($instance);
+}
+
+/**
+ * Implements hook_field_update_instance().
+ */
+function entityreference_prepopulate_field_update_instance($instance, $prior_instance) {
+  if (empty($instance['settings']['behaviors']['prepopulate'])) {
+    return;
+  }
+  if (isset($prior_instance['settings']['behaviors']['prepopulate']['status']) && $instance['settings']['behaviors']['prepopulate']['status'] == $prior_instance['settings']['behaviors']['prepopulate']['status']) {
+    // Nothing changed.
+    return;
+  }
+
+  $instance['default_value_function'] = !empty($instance['settings']['behaviors']['prepopulate']['status']) ? 'entityreference_prepopulate_field_default_value' : '';
+  field_update_instance($instance);
+}
+
+
+/**
+ * Implements hook_field_attach_form().
+ */
+function entityreference_prepopulate_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
+  list($id,,$bundle) = entity_extract_ids($entity_type, $entity);
+
+  if (!empty($form_state['triggering_element']['#ajax'])) {
+    // We are inside AJAX, so values can't be taken from URL at the
+    // moment.
+    return;
+  }
+
+  // Check if there is a field that needs to be prepopulated attached to the
+  // given entity.
+  $found = FALSE;
+  foreach (field_info_instances($entity_type, $bundle) as $instance) {
+    if (!empty($instance['settings']['behaviors']['prepopulate']['status'])) {
+      $found = TRUE;
+      break;
+    }
+  }
+
+  if (!$found) {
+    return;
+  }
+
+  foreach (element_children($form_state['field']) as $field_name) {
+    foreach ($form_state['field'][$field_name] as $lang => $value) {
+      $instance = $value['instance'];
+      if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
+        continue;
+      }
+      $settings = $instance['settings']['behaviors']['prepopulate'];
+
+      if ((!empty($settings['skip_perm']) && user_access($settings['skip_perm'])) || ($id && empty($settings['action_on_edit']))) {
+        // User has access to skip the action, or the entity is already
+        // saved, but "Apply action on edit", is disabled.
+        continue;
+      }
+
+      $field = $value['field'];
+
+      // Store prepopulated values in the form state to make them persistent,
+      // in case the form is rebuilt by AJAX requests.
+      $field_name = $field['field_name'];
+
+      if ($ids = entityreference_prepopulate_get_values($field, $instance)) {
+        $form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field_name] = $ids;
+      }
+
+      if ($ids || ($id && !empty($settings['action_on_edit']))) {
+        // New entity with prepopualte values, or an existing entity,
+        // we might need to disable/ hide the group-audience field.
+        if ($settings['action'] == 'disable') {
+          $form[$field_name][$lang]['#disabled'] = TRUE;
+        }
+        elseif ($settings['action'] == 'hide') {
+          // We don't hide the field via hook_field_access(), as the
+          // default value won't be set.
+          $form[$field_name]['#access'] = FALSE;
+        }
+      }
+      elseif (in_array($settings['fallback'], array('form_error', 'redirect'))) {
+        $message = t('Field @label must be populated via URL.', array('@label' => $instance['label']));
+        if ($settings['fallback'] == 'form_error') {
+          form_error($form, $message);
+        }
+        elseif ($settings['fallback'] == 'redirect') {
+          drupal_set_message($message, 'notice');
+          drupal_goto();
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_access().
+ */
+function entityreference_prepopulate_field_access($op, $field, $entity_type, $entity, $account) {
+  if ($op != 'edit' || $field['type'] != 'entityreference') {
+    return;
+  }
+
+  if (empty($entity)) {
+    // $entity might be NULL, so return early.
+    // @see field_access().
+    return;
+  }
+
+  list($id,,$bundle) = entity_extract_ids($entity_type, $entity);
+  if ($id) {
+    // Entity is already saved.
+    return;
+  }
+
+  $instance = field_info_instance($entity_type, $field['field_name'], $bundle);
+  if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
+    return;
+  }
+
+  $settings = $instance['settings']['behaviors']['prepopulate'];
+  if (!empty($settings['skip_perm']) && user_access($settings['skip_perm'])) {
+    return;
+  }
+  $ids = entityreference_prepopulate_get_values($field, $instance);
+
+  if (!$ids && $settings['fallback'] == 'hide') {
+    return FALSE;
+  }
+}
+
+/**
+ * Field default value callback.
+ *
+ * Set the default from the URL context. This works even if the widget is
+ * not shown, e.g. due to restricted field access.
+ *
+ * @todo Check field cardinality.
+ */
+function entityreference_prepopulate_field_default_value($entity_type, $entity, $field, $instance, $langcode) {
+  $items = array();
+  if ($ids = entityreference_prepopulate_get_values($field, $instance)) {
+    $items = array();
+    foreach ($ids as $id) {
+      $items[] = array('target_id' => $id);
+    }
+  }
+  return $items;
+}
+
+/**
+ * Wrapper function to get context (e.g. from URL or OG-context).
+ *
+ * @param $entity_type
+ *   The entity type the entity.
+ * @param $entity
+ *   The entity object that is being checked.
+ * @param $field
+ *   The field info array.
+ * @param $instance
+ *   The instance info array.
+ * @param $validate
+ *   Determine if access validation should be performed. Defaults to TRUE.
+ *
+ * @return
+ *   Array of IDs a user may view.
+ */
+function entityreference_prepopulate_get_values($field, $instance, $validate = TRUE) {
+  if (!$instance['settings']['behaviors']['prepopulate']['status']) {
+    // Do nothing when prepopulate is disabled for this field.
+    return;
+  }
+
+  $field_name = $field['field_name'];
+
+  $cache = &drupal_static(__FUNCTION__, array());
+  $identifier = array(
+    $instance['entity_type'],
+    $instance['bundle'],
+    $field_name,
+    $validate,
+  );
+
+  if (module_exists('og') && og_is_group_audience_field($field_name)) {
+    if (empty($instance['field_mode'])) {
+      // Group audience field, but no field-mode provided.
+      // So we iterate over the "default" and possibly "admin" field-modes,
+      // and return those values together.
+      $ids = array();
+      $field_modes = !user_access('administer group') ? array('default') : array('default', 'admin');
+      foreach ($field_modes as $field_mode) {
+        $instance['field_mode'] = $field_mode;
+        if ($og_ids = entityreference_prepopulate_get_values($field, $instance)) {
+          $ids = array_merge($ids, $og_ids);
+        }
+      }
+
+      // Return the values.
+      return $ids;
+    }
+
+    $identifier[] = $instance['field_mode'];
+  }
+
+  $identifier = implode(':', $identifier);
+
+  if (isset($cache[$identifier])) {
+    return $cache[$identifier];
+  }
+
+  $cache[$identifier] = $ids = array();
+
+  // Check if we have cached values.
+  if (!$ids) {
+    $ids = entityreference_prepopulate_get_values_from_cache($field, $instance);
+  }
+
+  // Check if we have OG-context integration.
+  if (!$ids) {
+    $ids = entityreference_prepopulate_get_values_from_og_context($field, $instance);
+  }
+
+  // Check if there are values in the URL.
+  if (!$ids) {
+    $ids = entityreference_prepopulate_get_values_from_url($field, $instance);
+  }
+
+  if (!$ids || !$validate) {
+    // No IDs found, or no validation is needed.
+    $cache[$identifier] = $ids;
+    return $ids;
+  }
+
+  $handler = entityreference_get_selection_handler($field, $instance);
+  if (!$ids = $handler->validateReferencableEntities($ids)) {
+    $cache[$identifier] = FALSE;
+    return;
+  }
+
+  // Check access to the provided entities.
+  $target_type = $field['settings']['target_type'];
+  entity_load($target_type, $ids);
+  foreach ($ids as $delta => $id) {
+    $entity = entity_load_single($target_type, $id);
+    if (!$entity || !entity_access('view', $target_type, $entity)) {
+      unset($ids[$delta]);
+    }
+  }
+
+  $cache[$identifier] = $ids;
+  return $ids;
+}
+
+/**
+ * Get the values from the cached form.
+ *
+ * @param $field
+ *   The field info array.
+ * @param $instance
+ *   The instance info array.
+ *
+ * @see
+ *   entityreference_prepopulate_get_values()
+ */
+function entityreference_prepopulate_get_values_from_cache($field, $instance) {
+  // Try to get the form out of cache.
+  if (!$form_build_id = isset($_GET['form_build_id']) ? $_GET['form_build_id'] : isset($_POST['form_build_id']) ? $_POST['form_build_id'] : NULL) {
+    return;
+  }
+
+  $field_name = $field['field_name'];
+
+  $form_state = array();
+  form_get_cache($form_build_id, $form_state);
+
+  // If successful, get the value from the form_state.
+  return isset($form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field_name]) ? $form_state['entityreference_prepopulate'][$instance['entity_type']][$instance['bundle']][$field_name] : FALSE;
+}
+
+/**
+ * Get values for prepopulating fields via URL.
+ *
+ * @param $field
+ *   The field info array.
+ * @param $instance
+ *   The instance info array.
+ *
+ * @see
+ *   entityreference_prepopulate_get_values()
+ */
+function entityreference_prepopulate_get_values_from_url($field, $instance) {
+  $field_name = $field['field_name'];
+  if (!empty($_GET[$field_name]) && is_string($_GET[$field_name])) {
+    return explode(',', $_GET[$field_name]);
+  }
+}
+
+
+/**
+ * Get values for prepopulating fields OG-context.
+ *
+ * @param $field
+ *   The field info array.
+ * @param $instance
+ *   The instance info array.
+ *
+ * @see
+ *   entityreference_prepopulate_get_values()
+ */
+function entityreference_prepopulate_get_values_from_og_context($field, $instance) {
+  $field_name = $field['field_name'];
+
+  if (!module_exists('og_context') || !og_is_group_audience_field($field_name) || !$og_context = og_context()) {
+    return;
+  }
+
+  if ($og_context['group_type'] != $field['settings']['target_type']) {
+    // Context is of invalid group-type.
+    return;
+  }
+
+  return array($og_context['gid']);
+}
+
+
+/**
+ * Return a form element with crafted links to create nodes for a group.
+ *
+ * @param $entity_type
+ *   The entity type of the referenced entity.
+ * @param $entity_id
+ *   The entity ID of the referenced entity.
+ * @param $destination
+ *   Optional; The destination after a node is created. Defaults to the
+ *   destination passed in the URL if exists, otherwise back to the current
+ *   page.
+ * @param $types
+ *   Optional; An array of type names. Restrict the created links to the given
+ *   types.
+ */
+function entityreference_prepopulate_create_node_links($entity_type, $entity_id, $field_name, $destination = NULL, $types = NULL) {
+  $wrapper = entity_metadata_wrapper($entity_type, $entity_id);
+  $field = field_info_field($field_name);
+
+  $entity = entity_load_single($entity_type, $entity_id);
+  list(,, $bundle) = entity_extract_ids($entity_type, $entity);
+
+  $types = isset($types) ? $types : array_keys(node_type_get_types());
+  $names = array();
+  foreach ($types as $type_name) {
+    if ($field['settings']['target_type'] != $entity_type) {
+      // The entity type isn't referenced by the field.
+      continue;
+    }
+
+    if (!empty($field['settings']['handler_settings']['target_bundles']) && !in_array($bundle, $field['settings']['handler_settings']['target_bundles'])) {
+      // The entity bundle isn't referenced by the field.
+      continue;
+    }
+
+    $instance = field_info_instance('node', $field_name, $type_name);
+    if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
+      // The field doesn't exist on the node type, or doesn't have prepopulate
+      // enabled.
+      continue;
+    }
+
+    if (!node_access('create', $type_name)) {
+      continue;
+    }
+
+    $names[$type_name] = node_type_get_name($type_name);
+  }
+
+  if (empty($names)) {
+    return;
+  }
+
+  // Sort names.
+  asort($names);
+
+  // Build links.
+  $options = array(
+    'query' => array($field_name => $entity_id) + drupal_get_destination(),
+  );
+
+  $items = array();
+  foreach ($names as $type => $name) {
+    $items[] = array('data' => l($name, 'node/add/' . str_replace('_', '-', $type), $options));
+  }
+
+  $element = array();
+  $element['entityreference_prepopulate'] = array(
+    '#theme' => 'item_list',
+    '#items' => $items,
+  );
+
+  return $element;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/entityreference_prepopulate.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,67 @@
+<?php
+
+class EntityReferenceOgContextTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'OG-context integration',
+      'description' => 'Test the OG-context integration, which allows prepopulating by the group context.',
+      'group' => 'Entity reference prepopulate',
+      'dependencies' => array('og'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('og_context', 'entityreference_prepopulate_test');
+
+    $this->user1 = $this->drupalCreateUser();
+    $this->user2 = $this->drupalCreateUser(array('bypass node access', 'administer group'));
+
+    $type = $this->drupalCreateContentType();
+    $this->group_type = $type->type;
+    og_create_field(OG_GROUP_FIELD, 'node', $this->group_type);
+
+    $type = $this->drupalCreateContentType();
+    $this->group_content_type = $type->type;
+
+    $og_field = og_fields_info(OG_AUDIENCE_FIELD);
+    // Enable the prepopulate behavior.
+    $og_field['instance']['settings']['behaviors']['prepopulate'] = array(
+      'status' => TRUE,
+      'action' => 'none',
+      'fallback' => 'none',
+      'skip_perm' => FALSE,
+      'og_context' => TRUE,
+    );
+    og_create_field(OG_AUDIENCE_FIELD, 'node', $this->group_content_type, $og_field);
+  }
+
+  /**
+   * Test the OG-context integration.
+   */
+  function testPrepopulate() {
+    $settings = array(
+      'type' => $this->group_type,
+      'uid' => $this->user1->uid,
+    );
+    $settings[OG_GROUP_FIELD][LANGUAGE_NONE][0]['value'] = 1;
+    $group1 = $this->drupalCreateNode($settings);
+
+    og_group('node', $group1, array('entity_type' => 'user', 'entity' => $this->user2));
+
+    $this->drupalLogin($this->user2);
+    $this->drupalGet('node/add/' . str_replace('_', '-', $this->group_content_type));
+    $this->assertNoOptionSelected('edit-og-group-ref-und-0-default', 1, 'Group-audience fields is not selected.');
+
+    // Set the OG-context();
+    // See entityreference_prepopulate_init().
+    $options = array(
+      'query' => array(
+        'gid' => $group1->nid,
+      ),
+    );
+
+    $this->drupalGet('node/add/' . str_replace('_', '-', $this->group_content_type), $options);
+    $this->assertOptionSelected('edit-og-group-ref-und-0-default', 1, 'Group-audience fields is selected.');
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/plugins/behavior/EntityReferencePrepopulateInstanceBehavior.class.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,78 @@
+<?php
+
+class EntityReferencePrepopulateInstanceBehavior extends EntityReference_BehaviorHandler_Abstract {
+
+  /**
+   * Generate a settings form for this handler.
+   */
+  public function settingsForm($field, $instance) {
+    $field_name = $field['field_name'];
+
+    $form['action'] = array(
+      '#type' => 'select',
+      '#title' => t('Action'),
+      '#options' => array(
+        'none' => t('Do nothing'),
+        'hide' => t('Hide field'),
+        'disable' => t('Disable field'),
+      ),
+      '#description' => t('Action to take when prepopulating field with values via URL.'),
+    );
+    $form['action_on_edit'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Apply action on edit'),
+      '#description' => t('Apply action when editing an existing entity.'),
+      '#states' => array(
+        'invisible' => array(
+          ':input[name="instance[settings][behaviors][prepopulate][action]"]' => array('value' => 'none'),
+        ),
+      ),
+    );
+    $form['fallback'] = array(
+      '#type' => 'select',
+      '#title' => t('Fallback behaviour'),
+      '#description' => t('Determine what should happen if no values are provided via URL.'),
+      '#options' => array(
+        'none' => t('Do nothing'),
+        'hide' => t('Hide field'),
+        'form_error' => t('Set form error'),
+        'redirect' => t('Redirect'),
+      ),
+    );
+
+    // Get list of permissions.
+    $perms = array();
+    $perms[0] = t('- None -');
+    foreach (module_list(FALSE, FALSE, TRUE) as $module) {
+      // By keeping them keyed by module we can use optgroups with the
+      // 'select' type.
+      if ($permissions = module_invoke($module, 'permission')) {
+        foreach ($permissions as $id => $permission) {
+          $perms[$module][$id] = strip_tags($permission['title']);
+        }
+      }
+    }
+
+    $form['skip_perm'] = array(
+      '#type' => 'select',
+      '#title' => t('Skip access permission'),
+      '#description' => t('Set a permission that will not be affected by the fallback behavior.'),
+      '#options' => $perms,
+    );
+
+    $description = t('Determine if values that should be prepopulated should "listen" to the OG-context.');
+
+    if ($disabled = !module_exists('og_context') || !og_is_group_audience_field($field_name)) {
+      $description .= '<br / >' . t('Organic groups integration: Enable OG-context and set "Entity selection mode" to "Organic groups" to enable this selection.');
+    }
+
+    $form['og_context'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('OG context'),
+      '#description' => $description,
+      '#disabled' => $disabled,
+    );
+
+    return $form;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/plugins/behavior/prepopulate.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,8 @@
+<?php
+
+$plugin = array(
+  'title' => t('Entity reference prepopulate'),
+  'description' => t('Prepopulate entity reference values from URL.'),
+  'class' => 'EntityReferencePrepopulateInstanceBehavior',
+  'behavior type' => 'instance',
+);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/plugins/content_types/node_prepopulate.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * Plugin definition.
+ */
+$plugin = array(
+  'title' => t('Content prepopulate links'),
+  'description' => t('Crafted links to create content (nodes) for an entity reference field.'),
+  'required context' => new ctools_context_required(t('Node'), 'node'),
+  'category' => t('Entity reference'),
+  'defaults' => array(
+    'types' => array(),
+    'field_name' => '',
+  ),
+);
+
+/**
+ * Render callback.
+ */
+function entityreference_prepopulate_node_prepopulate_content_type_render($subtype, $conf, $args, $context) {
+  if (empty($context->data)) {
+    return;
+  }
+
+  $node = $context->data;
+  $links = entityreference_prepopulate_create_node_links('node', $node->nid, $conf['field_name'], NULL, !empty($conf['types']) ? $conf['types'] : NULL);
+  if (!$links) {
+    return;
+  }
+
+  $module = 'entityreference_prepopulate';
+  $block = new stdClass();
+  $block->module = $module;
+  $block->title = t('Content create links');
+  $block->content = $links;
+  return $block;
+}
+
+/**
+ * Edit form.
+ */
+function entityreference_prepopulate_node_prepopulate_content_type_edit_form($form, &$form_state) {
+  $conf = $form_state['conf'];
+
+  $options = array();
+  $bundles = array();
+  // Use CTools to get the best matching field name.
+  ctools_include('fields');
+  foreach (field_info_instances('node') as $node_type => $instances) {
+    foreach ($instances as $field_name => $instance) {
+      if (empty($instance['settings']['behaviors']['prepopulate']['status'])) {
+        continue;
+      }
+
+      $field = field_info_field($field_name);
+
+      if ($field['settings']['target_type'] != 'node') {
+        // Field doesn't reference a node.
+        continue;
+      }
+
+      $bundles[] = $instance['bundle'];
+      if (empty($options[$field_name])) {
+        $options[$field_name] = ctools_field_label($field_name) . ' (' . $field_name . ')';
+      }
+    }
+  }
+
+  $form['field_name'] = array(
+    '#title' => t('Field name'),
+    '#type' => 'select',
+    '#options' => $options,
+    '#default_value' => $conf['field_name'],
+    '#description' => $options ? t('The entity reference field to prepopulate.') : t('There are no entity reference fields, with prepopulate enabled'),
+    '#required' => TRUE,
+  );
+
+  $options = array();
+  foreach (node_type_get_types() as $type) {
+    if (in_array($type->type, $bundles)) {
+      $options[$type->type] = check_plain($type->name);
+    }
+  }
+  $form['types'] = array(
+    '#title' => t('Restrict to content types'),
+    '#type' => 'checkboxes',
+    '#options' => $options,
+    '#default_value' => $conf['types'],
+    '#description' => t('If left empty, all possible content types are shown.'),
+  );
+  return $form;
+}
+
+/**
+ * Edit form submit callback.
+ */
+function entityreference_prepopulate_node_prepopulate_content_type_edit_form_submit($form, &$form_state) {
+  $form_state['conf']['field_name'] = $form_state['values']['field_name'];
+  $form_state['conf']['types'] = array_filter($form_state['values']['types']);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/tests/entityreference_prepopulate_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Entity reference prepopulate test module
+description = Functionality to assist Entity reference prepopulate testing.
+core = 7.x
+dependencies[] = entityreference_prepopulate
+dependencies[] = og_context
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2013-04-22
+version = "7.x-1.3"
+core = "7.x"
+project = "entityreference_prepopulate"
+datestamp = "1366630855"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/entityreference_prepopulate/tests/entityreference_prepopulate_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+<?php
+
+/**
+ * @file
+ * Test module for Entity reference prepopulate.
+ */
+
+/**
+ * Implements hook_init().
+ */
+function entityreference_prepopulate_test_init() {
+  if (empty($_GET['gid'])) {
+    return;
+  }
+
+  $node = node_load($_GET['gid']);
+  og_context('node', $node);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/API.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,189 @@
+
+Features 1.x API for Drupal 7.x
+-------------------------------
+This file contains documentation for two audiences: site builders interested in
+creating and managing features and module developers interested in integrating
+with the features module.
+
+
+Terminology
+-----------
+- A **feature module** is a Drupal module that contains the `feature` key in its
+`.info` file. This array describes the components that should be managed by
+Features within the module.
+
+- A **component** is a configuration object that can be exported. Examples: a
+view, content type or CCK field instance.
+
+- A **machine name** is a string identifier for a specific type of component and
+should be unique within a single Drupal site. It should not be a numerically
+generated serial id.
+
+- An **exportable** component is one that can be used solely from a default hook
+in code and without an instance in the database. For example, a view that lives
+in code does not need an entry in the database in order to be used.
+
+- A **faux-exportable** component is one that must exist in the database in
+order to be used. Any exports of this component are used to create or
+synchronize entries in the database that share the same machine name.
+
+
+### Component states
+
+Features provides some infrastructure to determine the state of components on
+the site. To determine the state of a component Features keeps track of three
+things using an md5 hash of
+
+- current code for the component. This is the configuration as actually
+represented in code by a given feature.
+
+- the most recent prior code state that differs from the current code state. For
+example, if an `svn update` changes the configuration of a view, this stores the
+code state *prior* to the update.
+
+- The "normal" component state. This is the configuration represented by the
+component as stored in the database or the default component (with any changes
+introduced by `drupal_alter()`) if no database override exists.
+
+Using these three values, Features determines a component to be in one of the
+following five states:
+
+- **Default** (`FEATURES_DEFAULT`) The object has no database entry or the
+database entry matches the state of the component in code. This should be the
+default state of components after installing a feature. Updating the component
+can be done by altering the code definition directly.
+
+- **Overridden** (`FEATURES_OVERRIDDEN`) The code remains constant but the
+database object does not match the state of the component in code. Changes must
+be reverted before the component can be updated from code.
+
+- **Needs review** (`FEATURES_NEEDS_REVIEW`) The previous code state, database
+state, and current code state all differ. This occurs most commonly when a user
+changes one of her components and then pulls updates to her codebase. Since
+there is no way to tell whether the code state or the database state is more
+recent/valid, user input is necessary to resolve this state.
+
+- **Rebuildable** (`FEATURES_REBUILDABLE`) This state only applies to
+**faux-exportables** and indicates that the database component must and can be
+safely updated from the code definition. The database entry does not match the
+current code state but does match the previous code state. Features assumes that
+in this scenario the user has made no substantive changes and the component can
+be updated automatically.
+
+- **Rebuilding** (`FEATURES_REBUILDING`) This state is rarely seen and only
+applies to **faux-exportables.** This state is shown when a
+`FEATURES_REBUILDABLE` component is *currently* being synced to the database.
+Usually this operation is very fast and short lived. However, if the operation
+is interrupted (e.g. the server goes down) this state will be seen until the
+rebuild locking semaphore is cleared.
+
+
+How a feature is generated
+--------------------------
+At a high level Features writes the code in a feature module using the following
+steps:
+
+1. An `.info` file describing the components that should be included in a
+Feature is generated. It is either read from an existing feature or generated
+through the Features UI.
+
+2. Features converts the info file into an `$export` array which contains a list
+of elements to be exported. Each component type is given a chance to add to the
+export list as well as request that *other* components be given a second chance
+to add to the `$export` array.
+
+3. If any additional components have been queued up in the `$pipe` we repeat
+step 2 for each of the queued component types.
+
+4. Once a full `$export` array is populated each component renders items from
+the `$export` array to PHP code as a exportable defaults hook.
+
+5. Finally, Features writes the code into files and delivers it as a
+downloadable package (UI) or writes it directly to a module directory (drush).
+
+This workflow makes a variety of things possible:
+
+### Add components to a feature
+
+Add the components to the `features` array in the feature's `.info` file and run
+`drush features-update`. The same operation can be performed using the
+*Recreate* page in the Features UI.
+
+### Remove components from a feature
+
+Remove the corresponding component lines from the feature's `.info` file and run
+`drush features-update`. The same operation can be performed using the
+*Recreate* page in the Features UI.
+
+### Rename a component
+
+Rename a component by changing its name in the feature's `.info` file and the
+key and name property of the exported object in the appropriate `.inc` file in
+the feature. Note that any references in other configuration objects to the
+previous name should also be updated.
+
+
+Integrating your module with the Features API
+---------------------------------------------
+This section is for developers interested in adding Features-based management
+for the configuration objects in their modules. From the perspective of
+Features, there are a few different ways that modules store their configuration:
+
+- In the `variable` table using `variable_set()`. If a module is using variables
+for storing configuration, these variable settings can be exported with Features
+by using the [Strongarm][1] module.
+
+  **Features integration:** Install the Strongarm module.
+
+- Using a custom table with a serial ID for identifying configuration objects.
+If this is the case, you will need to change your schema to use a string
+identifier / machine name for each object.
+
+  **Features integration:** Fix your schema first, then see below.
+
+- Using a custom table with a machine name identifier and custom exportables
+handling (e.g. you have your own defaults hook handling and export generation).
+If this is the case, you will need to implement many of the features hooks
+yourself.
+
+  **Features integration:** `hook_features_api()`, `hook_features_export()`,
+`hook_features_export_render()`, `hook_features_export_options()`,
+`hook_features_revert()`.
+
+- Using a custom table with CTools Export API integration. If this is the case,
+Features will automatically have integration with your module. You can implement
+any of the Features hooks in order to override the default CTools exportables
+integration behavior.
+
+  **Features integration:** Automatically provided. You may implement any of the
+Features hooks where you need further customization for your configuration
+object.
+
+If it isn't clear by now, we highly recommend using the [CTools][2] Export API
+for adding exportables to your module. Stella has written a [fantastic HOWTO][3]
+on using the CTools Export API that can get you started.
+
+
+An overview of Features hooks
+-----------------------------
+Extensive documentation of the hooks provided by Features is available in
+`features.api.php`. This section provides a short overview of each hook and its
+role.
+
+- `hook_features_api()` defines one or more component types that are available
+to Features for export and a variety of settings for each type.
+- `hook_features_export()` processes a list of components, detecting any
+dependencies or further components
+- `hook_features_export_options()` provides an array of components that can be
+exported for a given type.
+- `hook_features_export_render()` renders a set of components to code as a
+defaults hook.
+- `hook_features_revert()` reverts components of a feature back to their default
+state.
+- `hook_features_rebuild()` updates faux-exportable components back to their
+default state. Only applies to faux-exportables.
+
+
+[1]: http://drupal.org/project/strongarm
+[2]: http://drupal.org/project/ctools
+[3]: http://civicactions.com/blog/2009/jul/24/using_chaos_tools_module_create_exportables
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/CHANGELOG.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,221 @@
+features DRUPAL-7--1-0
+----------------------
+
+#1647894 by tim.plunkett: Fixed Features with page manager components are perpetually overridden.
+#1635662 by donquixote: Fixed Undefined index: feature in features_get_info().
+Add missing taxonomy test file
+
+features DRUPAL-7--1-0-RC3
+--------------------------
+
+#1429262 by joelcollinsdc, neochief: Added Allow component level reverting (without needing to go to interactive mode) in drush fr.
+#1272586 by alexweber | stevector: Added Increment or directly set version number directly with drush features-update.
+#1532422 by nadavoid: Fixed If the custom sort order of 'format_handlers()' is not maintained, some things can break.
+#1564864 by jeffschuler: Fixed Mixup in hook_features_export_render() example.
+#1567506 by Dave Reid: Fixed Unable to properly export or provide a locked field in a feature.
+#1597792 by jessehs: Make sure all comments in created features end period.
+#1599188 by jessehs: Move inline comment for empty feature .module file to @file doc block.
+#1587200 by ericduran: Fixed Test module should be hidden.
+#1574716 by bojanz: Fixed Avoid unnecessary cache rebuilds when creating and updating fields.
+#1530386 by exratione, bojanz, kotnik: Avoid unnecessary cache rebuilds and improve installation performance.
+#1489480 by Xen | dema502: Fixed drush:features-export Ambiguous component.
+#1159390 by hefox | brad.bulger: Fixed incorrect revert hook name in features.api.php?.
+#1493274 by hefox, neochief: Fixed Feature installed before Strongarm blocks all other variable imports.
+#1537838 by hefox, JvE | Gisle: Fixed Upgrading to 7.x-1.0-rc2 (from rc1) breaks taxonomy creation.
+#1447656 by bcmiller0, smk-ka: Added drush features-revert-all performance improvement.
+
+features DRUPAL-7--1-0-RC2
+--------------------------
+
+#1529202 by mpotter, mstrelan: Fixed Unable to revert overrides because clear-block is now clearfix.
+#1505044 by neochief: Fixed features_var_export() adds additional prefix to multiline strings contained in objects.
+#1510710 by neochief: Fixed Incorrect key in features_include_defaults() with reset parameters.
+#1402262 by hefox: Fixed features.api.php mentions 'features_source()' key, but the actual key in use is 'feature_source()'.
+#939254 by hefox, fago: Added Return the () to hook_features_pipe_component_alter().
+#894572 by pearcec, eporama, Grayside, andrewlevine: Added Features with only module dependencies not recognized as features.
+#1231118 by tim.plunkett, jhedstrom, nielsonm, arnested: Fixed Generate code according to coding standards.
+#1493274 by neochief, hefox: Fixed Feature installed before Strongarm blocks all other variable imports.
+#1287594 by tim.plunkett: Don't wrap .info file values in double quotes.
+#1437388 by hefox: Fixed check if file exists before including it in features_include().
+#1496322 by hefox, dajjen: Added Make package autocomplete search string case insensitive .
+#1279938 by derhasi, helmo: Added Features support for languages.
+#1305048 by mongolito404: Fixed Undefined index error in user_permission_features_export_render().
+#1063204 by careernerd, davidwhthomas, hefox | mrfree: Fixed Adding a new permission causes integrity constraint violation.
+#1432264 by ezra-g, tim.plunkett | samhassell: Fixed Changes to hook_views_api() cause Views plugins to be undefined.
+Revert "Issue #1432264 by ezra-g, tim.plunkett | samhassell: Fixed Changes to hook_views_api() cause Views plugins to be undefined."
+
+features DRUPAL-7--1-0-RC1
+--------------------------
+
+#1331278 by Xen, tim.plunkett, joelcollinsdc, mpotter: Drush features-add and features-export are confusingly simi
+#1475780 by rggoode: Added Prevent starting features machine name starting with numeric.
+#1402826 by mpotter: Added Make 'Checking...' a link.
+#1478808 by mpotter: Added Why is Description field required?.
+#1279938 by derhasi, helmo: Added Features support for languages.
+#1009900 by DamienMcKenna: Check if a variable is empty before comparing it to a known value.
+#1426452 by mpotter, rypit: Added Conflicts with disabled modules should be colored differently.
+#984472 by hefox, goron, Sarenc, mpotter: Added hook_node_info_alter(), and alter_type(), alter_hook() to features
+#1478808 by mpotter: Added Why is Description field required?.
+#1479068 by mpotter: Added Allow exportable code written to different files.
+#1058778 by dajjen | nymo: Added ability to edit package of feature when creating/editing features via the UI.
+#1429408 by joelcollinsdc: Fixed Diff page does not show component titles.
+#1264826 by Volx, hefox | mortendk: Fixed revert views calls views delete() & throws a fatal error .
+#1432264 by ezra-g, tim.plunkett | samhassell: Fixed Changes to hook_views_api() cause Views plugins to be undefin
+#1479068 by mpotter: Added Allow exportable code written to different files.
+#1437370 by hefox: Fixed . is being mapped to ord(',') instead of ord('.') in features_dom_encode_options()/featur
+Added a README section about security concerns
+Updated some docs, specifically the maintainers
+#1231118 by jhedstrom: Generate code according to coding standards when using include_once.
+#1305194 by hefox,Xen,mpotter: Provide support for exporting of altering of components
+#1305194 by smk-ka,jief: Taxonomy reference field export recursion
+#1390848: Fixing a slight bug from the previous patch that lead to wrong components being shown as being able to b
+#1390848 by hefox: Centralize the call to hook_features_api()
+Updated the features_test Feature
+#1399440 by hefox: Fixed Feature tests failure on image against drupal 7.10.
+
+features DRUPAL-7--1-0-BETA6
+----------------------------
+
+#1382156 by tim.plunkett | davidn: Fixed PHP Fatal error: Call to undefined function ctools_features_declare_funct
+
+features DRUPAL-7--1-0-BETA5
+----------------------------
+
+#1363284 by tim.plunkett, mpotter: Fixed Drush --force option is declared wrong.
+#1079440 by mpotter, mrf, tobby, acrollet, donquixote: Fixed Module name check prevents panels custom content pane
+#1152908 by greg.1.anderson, msonnabaum, smk-ka, rbayliss: Fixed Remove calls to drush_backend_invoke()
+#813760 by galooph, tim.plunkett, Volx, raphaelhuefner | greg.harvey: Fixed CTools Page manager pages do not rever
+#904558 by hefox, voxpelli, Raines37 | loze: Fixed Multiple features and strongarm conflicts.
+#1170846 by Ravi.J: Fixed Disabling a feature does not disable dependent modules.
+#1313744 by TravisCarden: Fixed Sort 'Edit components' SELECT alphabetically.
+Made the Features Test not hidden, b/c if it is hidden it wont enable/install the content type
+#1300780 by Dave Reid: Added Provide an actual hook_features_pipe_alter() for general altering.
+#1178884 by YaderV | altfuns: Fixed Wrong  word (with) in a description text.
+#893360 by Xen, Raines37, Grayside, franz: Added Drush update/recreate (add components).
+#913890 by Grayside, joshuajabbour, tim.plunkett | webchick: Added Generate .info file properties in order consist
+#1288028 by DamienMcKenna: Fixed D7 branch refers to D6 CCK hook.
+#1187232 by Ravi.J, rickvug: Fixed Hidden and disabled features should not be displayed in UI and should not be co
+
+features DRUPAL-7--1-0-BETA4
+----------------------------
+
+Fixing naming conflict b/w hook_enable and hook_disable
+#1187858 by smk-ka, febbraro: Fixed Node permissions fail to import.
+#1191558 by clemens.tolboom, Raines37: Allow for drush --destination while exporting a feature.
+#1188066 by smk-ka, febbraro: Fixed Excessive rebuilding if installing more than one feature at a time.
+#1260040 by tim.plunkett | hefox: Fixed features.css does not follow coding standards.
+#1195432: Fixing admin screen regression
+#1195432 by smk-ka: Use dependency information when importing
+#1186874 by dixon_: Better support for switching field storage types
+#1175684 by sagannotcarl, rocket.nova: Add legend/help to features-diff
+#1210604 by catch: drush features-revert-all does not respect --force argument
+#954062 by irakli, hefox: Incorrect Component Labels in the Components Dropdown
+#1186694 by tunic, fearlsgroove: Features orders exportes recursivally; fields allowed_values array alphabetized,
+#935152 by adamdicarlo, hadsie, hefox: Menu Items missing from Menu Links due to access callback user_is_anonymous
+#1258072 by hefox: Add suggestion for vocabulary when exporting a taxonomy field
+#1279212: add Features Breadcrumb
+Fixed the display of conflicting features. It was borked big time.
+#1219932 bu acrollet, t-dub, Nico Heulsen: Problems when dependencies have version numbers in them
+#1055460 by nedjo, hefox, fabsor, others...: Disabling a feature does not allow user to delete content type
+#994602 by franz: Misleading example on hook_features_export_alter() documentation
+#1264462 by Dave Reid, skwashd: template_preprocess_features_admin_components() calls D6-style theme() arguments
+#1131062: scripts/stylesheets manually added to info file have the path broken
+#946068 by rvilar, hefox: The machine name isn't updating correctly
+#1079440 by mrf, DamienMcKenna, dereine: Allow export of Custom Content Panes
+#1231118 by arnested, tim.plunkett: Coder fixes
+
+features DRUPAL-7--1-0-BETA3
+----------------------------
+
+#1177582 by paulsheldrake: Missing ctools plugin include
+#1191670: Undefined FEATURES_COMPONENT_NOT_FOUND in features.drush.inc
+#1157048 by dixon_: Features appear overridden
+#1124422 by anantagati: Wrong links in README
+#932104 by aaronbauman, hefox, etc.: Improve help for feature export drush command
+#1094940 by webflo: Features unit test are broken
+#1134202: Overridden views not reverting
+#1097560 by nedjo: Features incompatible with latest version of views
+
+features DRUPAL-7--1-0-BETA2
+----------------------------
+
+#1111714 by paranojik: _features_restore() does not properly revert components.
+#1070912 by bdragon: features_get_info() hands back original objects, can get corrupted.
+#1073988 by mikewink: File formats should be labeled text formats for consistency.
+removing unnecessary and typo-including check on plugin_api_hook_name
+removed duplicate ctools_plugin_api_get_hook function since new ctools is now released and it's unnecessary
+#1097560 by floretan, quartsize, merlinofchaos: Features incompatible with the latest version of views.
+Fixing unit test for permissions that broke as a result of #1063204
+Fixed the sanitize as it was incorrectly misidentifying a one item associative array as non-associative.
+Merge branch '7.x-1.x' of git.drupal.org:project/features into 7.x-1.x
+#1063204 by mrfree, careernerd, hadsie, irakli: Adding a new user role causes integrity constraing violation.
+Fixed E_STRICT warnings
+Merge branch '7.x-1.x' of git.drupal.org:project/features into 7.x-1.x
+#973836 by fmitchell, Grayside: Add @file to the generated files
+#1078972 by bdragon: Quoting problems on key side.
+Removing translation directories
+Stripping CVS keywords
+
+features DRUPAL-7--1-0-BETA1
+----------------------------
+
+#993314 by das-peter: Notice 'undefined index' in features_export_build_form_populate.
+adding warning @TODO to note an edge case that is not covered by existing code when checking if .module includes feature
+#1053336 by tema: Translatables are not exported for fields.
+#970788 by mori, das_peter, steinmb: Notice: Undefined index: api in _ctools_features_get_info() // error from featu
+#1062526 by fago, dasjo: components appear always overriden if the default hook makes use of hook-group.
+#954536 by klausi: Unsetting ids on vocabulary object breaks Entity Cache.
+#1014066 by brenk28: Improper use of t().
+#994122 by hadsie: Feature conflicts report displays conflicting features as Array instead of proper feature name.
+#953236 by isolesen, grobot : Make the Manage Features page more descriptive when there are no features.
+cleaning up previous somewhat extraneous commit and making first attempt towards fixing: #986118. Full fix of that one s
+#944584 by  Rok Žlender, pcambra: Features diff in drush is broken.
+#1056422 by EclipseGc: Attribute Classes are Arrays in D7.
+Follow up to previous commit, actually ordering array correctly.
+Fix tab rendering on admin/build/features.
+Updated the filter test
+Utilize filter format machine names which core now provides.
+
+features DRUPAL-7--1-0-ALPHA3
+-----------------------------
+
+Update filter component to make use of machine names if available.
+PHP declaration.
+Update features_test field export to match changes in core.
+Several test fixes.
+Use features_get_default() rather than module_invoke().
+Remove old schema check.
+#925628 by thill_: Fix example version strings.
+#925332 by joshuajabbour: Cleaner export render for ctools components.
+
+features DRUPAL-7--1-0-ALPHA2
+-----------------------------
+
+Update features.api.php.
+#919500 by fago: Enable generic feature implementations. Introduces 'base' key in hook_features_api().
+#912132 by das-peter, fago: Implement hook_hook_info() entry for 'features_api'.
+Properly support 'hidden' key in D7.
+Fix function signature of features_export_prepare().
+Fix for menu links export options.
+Exclude bundles info from field config.
+Exclude 'module' key from image style export.
+Prevent features from going haywire when attempting to detect conflict with components it doesn't know about.
+Sorting field definitions before exporting.
+Removing non-class files from files[] in fino.
+Revert addition of files array to features.
+#912018 by das-peter: Fix for duplicate files[] entries.
+Remove unneeded context features hooks.
+Fix features_get_orphans().
+#908390: Generate files[] array for features.
+
+features DRUPAL-7--1-0-ALPHA1
+-----------------------------
+
+D7: Update image styles component.
+D7: Update hook_permission().
+D7: Remove _features_get_roles().
+D7: user_role and user_permission component upgrades.
+D7: Update list of component includes.
+D7: Filter format API updates.
+D7: Fix for diff integration.
+D7 fixes for menu_custom and menu_links components.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,235 @@
+
+Current state of Features for Drupal 7
+--------------------------------------
+Work on Features for D7 is currently aimed at getting to a point where Features
+can be used on a new install of Drupal 7 with features that were created on D7.
+Once this has been achieved, we will begin working on supporting D6 features as
+well as possibly supporting upgrades & migrations between legacy components and
+new equivalents (e.g. CCK to fields, imagecache to core image styles).
+
+### Working components
+
+- ctools
+- dependencies
+- field
+- filter
+- image
+- menu_custom
+- menu_links
+- node
+- taxonomy
+- user_permission
+- user_role
+- views
+
+### Has changes to export format between D6 and D7
+
+(@TODO legacy export compatibility)
+
+- filter
+- taxonomy
+
+### Requires upgrade/migration path
+
+- imagecache > image
+- content > field
+
+Note on the "Generate Feature" capability
+-----------------------------------------
+Features 7.x-2.x includes the ability to "Generate a feature" which saves it
+to the server disk. This can be a time-saving task in development. It requires
+the webserver to be able to write to the very code running the site and is
+not recommended for any environment other than a firewalled-off, local
+development environment (e.g. a person working alone on their laptop).
+
+Features 1.x for Drupal 7.x
+---------------------------
+The features module enables the capture and management of features in Drupal. A
+feature is a collection of Drupal entities which taken together satisfy a
+certain use-case.
+
+Features provides a UI and API for taking different site building components
+from modules with exportables and bundling them together in a single feature
+module. A feature module is like any other Drupal module except that it declares
+its components (e.g. views, contexts, CCK fields, etc.) in its `.info` file so
+that it can be checked, updated, or reverted programmatically.
+
+Examples of features might be:
+
+- A blog
+- A pressroom
+- An image gallery
+- An e-commerce t-shirt store
+
+
+Installation
+------------
+Features can be installed like any other Drupal module -- place it in the
+modules directory for your site and enable it on the `admin/build/modules` page.
+To take full advantage of some of the workflow benefits provided by Features,
+you should install [Drush][1].
+
+If you plan on creating or working with very large features (greater than 1000
+items), you may need to increase PHP's max_input_vars configuration directive.
+For example, adding the following line to your .htaccess file will increase the
+max_input_vars directive to 3000:
+
+php_value max_input_vars 3000
+
+If you are using Suhosin, increasing suhosin.get.max_vars,
+suhosin.post.max_vars, and suhosin.request.max_vars may also be necessary.
+
+
+Basic usage
+-----------
+Features is geared toward usage by developers and site builders. It
+is not intended to be used by the general audience of your Drupal site.
+Features provides tools for accomplishing two important tasks:
+
+### Task 1: Export features
+
+You can build features in Drupal by using site building tools that are supported
+(see a short list under the *Compatibility* section).
+
+Once you've built and configured functionality on a site, you can export it into
+a feature module by using the feature create page at
+`admin/structure/features/create`.
+
+
+### Task 2: Manage features
+
+The features module also provides a way to manage features through a more
+targeted interface than `admin/modules`. The interface at
+`admin/structure/features` shows you only feature modules, and will also inform you
+if any of their components have been overridden. If this is the case, you can
+also re-create features to bring the module code up to date with any changes
+that have occurred in the database.
+
+
+Including custom code and adding to your feature
+------------------------------------------------
+Once you've exported your feature you will see that you have several files:
+
+    myfeature.info
+    myfeature.module
+    myfeature.[*].inc
+
+You can add custom code (e.g. custom hook implementations, other functionality,
+etc.) to your feature in `myfeature.module` as you would with any other module.
+Do not change or add to any of the features `.inc` files unless you know what
+you are doing. These files are written to by features on updates so any custom
+changes may be overwritten.
+
+
+Using Features to manage development
+------------------------------------
+Because Features provides a centralized way to manage exportable components and
+write them to code it can be used during development in conjunction with a
+version control like SVN or git as a way to manage changes between development,
+staging and production sites. An example workflow for a developer using Features
+is to:
+
+1. Make configuration changes to a feature on her local development site.
+2. Update her local feature codebase using `drush features-update`.
+3. Commit those changes using `svn commit`.
+4. Roll out her changes to the development site codebase by running `svn update`
+  on the server. Other collaborating developers can also get her changes with
+  `svn update`.
+5. Reverting any configuration on the staging site to match the updated codebase
+by running `drush features-revert`.
+6. Rinse, repeat.
+
+Features also provides integration with the [Diff][3] module if enabled to show
+differences between configuration in the database and that in code. For site
+builders interested in using Features for development, enabling the diff module
+and reading `API.txt` for more details on the inner workings of Features is
+highly recommended.
+
+
+Drush usage
+-----------
+(requires Drush v4.5 or higher)
+
+Features provides several useful drush commands:
+
+- `drush features`
+
+  List all the available features on your site and their status.
+
+- `drush features-export [feature name] [component list]`
+
+  Write a new feature in code containing the components listed.
+  If called with no arguments, display a list of available components.
+  If called with one argument, take the argument as a component name and
+  attempt to create a feature with the same name.
+
+  The option '--destination=foo' may be used to specify the path (from Drupal
+  root) where the feature should be created. The default destination is
+  'sites/all/modules'.
+
+- `drush features-update [feature name]`
+
+  Update the code of an existing feature to include any overrides/changes in
+  your database (e.g. a new view).
+
+- `drush features-revert [feature name]`
+
+  Revert the components of a feature in your site's database to the state
+  described in your feature module's defaults.
+
+- `drush features-diff [feature name]`
+
+  Show a diff between a feature's database components and those in code.
+  Requires the Diff module.
+
+Additional commands and options can be found using `drush help`.
+
+
+Compatibility
+-------------
+Features provides integration for the following exportables:
+
+- CTools export API implementers (Context, Spaces, Boxes, Strongarm, Page
+  Manager)
+- ImageCache
+- Views
+- [Other contributed modules][2]
+
+Features also provides faux-exportable functionality for the following Drupal
+core and contrib components:
+
+- Fields
+- Content types
+- Input filters
+- User roles/permissions
+- Custom menus and menu links *
+- Taxonomy vocabularies
+
+* Currently in development.
+
+
+Security Concerns
+-----------------
+If you are using Features to export Roles and also use those Roles in other
+exportable code (like Views filters) you can wind up with an unintended
+security hole.  When you import your Feature, if the Roles do not get created
+with the exact same Role IDs then your Views filters (or other component) will
+be referencing a different Role than you intended.
+
+
+For developers
+--------------
+Please read `API.txt` for more information about the concepts and integration
+points in the Features module.
+
+
+Maintainers
+-----------
+- febbraro (Frank Febbraro)
+- hefox (Fox)
+- mpotter (Mike Potter)
+- timplunkett (Tim Plunkett)
+
+
+[1]: http://drupal.org/project/drush
+[2]: (http://drupal.org/taxonomy/term/11478)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1483 @@
+<?php
+
+/**
+ * @file
+ * Forms for Features admin screens
+ */
+
+
+/**
+ * Settings form for features
+ */
+function features_settings_form($form, $form_state) {
+  $form = array();
+
+  $components = features_get_components();
+  uasort($components, 'features_compare_component_name');
+  $form['show_components'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Show components on create/edit feature form.'),
+    '#description' => t('Components with no options will not be shown no matter the setting below. Disabled components cannot be used with admin form.')
+  );
+  foreach ($components as $compontent => $info) {
+    if (empty($info['feature_source']) && empty($info['features_source'])) {
+      continue;
+    }
+    $form['show_components']['features_admin_show_component_' . $compontent] = array(
+      '#title' => t('@name (@machine)', array('@name' => $info['name'], '@machine' => $compontent)),
+      '#type' => 'checkbox',
+      '#default_value' => variable_get('features_admin_show_component_' . $compontent, TRUE),
+    );
+    if ($compontent == 'menu_links' && ($menus = menu_get_menus())) {
+      $form['show_components']['features_admin_menu_links'] = array(
+        '#title' => t('Advanced Menu Link Settings'),
+        '#type' => 'fieldset',
+        '#collapsed' => TRUE,
+        '#collapsible' => TRUE,
+        '#states' => array(
+          'invisible' => array(
+            'input[name="features_admin_show_component_menu_links"]' => array('checked' => FALSE),
+          ),
+        ),
+      );
+      $form['show_components']['features_admin_menu_links']['features_admin_menu_links_menus'] = array(
+        '#title' => t('Allowed menus for menu links'),
+        '#type' => 'checkboxes',
+        '#options' =>  array_map('check_plain', $menus),
+        '#default_value' => variable_get('features_admin_menu_links_menus', array_keys(menu_get_menus())),
+      );
+    }
+  }
+
+  $form['features_rebuild_on_flush'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Rebuild features on cache clear'),
+    '#default_value' => variable_get('features_rebuild_on_flush', TRUE),
+    '#description' => t('If you have a large site with many features, you may experience lag on full cache clear. If disabled, features will rebuild only when viewing the features list or saving the modules list.'),
+  );
+
+  return system_settings_form($form);
+}
+
+/**
+ * Form constructor for features export form.
+ *
+ * Acts as a router based on the form_state.
+ *
+ * @param object|null $feature
+ *   The feature object, if available. NULL by default.
+ *
+ * @see features_export_build_form_submit()
+ * @ingroup forms
+ */
+function features_export_form($form, $form_state, $feature = NULL) {
+  module_load_include('inc', 'features', 'features.export');
+  features_include();
+
+  $feature_name = !empty($feature->name) ? $feature->name : '';
+  $form = array(
+    '#attributes' => array('class' => array('features-export-form')),
+    '#feature' => isset($feature) ? $feature : NULL,
+  );
+  $form['info'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('General Information'),
+    '#tree' => FALSE,
+    '#weight' => 2,
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+    '#prefix' => "<div id='features-export-info'>",
+    '#suffix' => '</div>',
+  );
+  $form['info']['name'] = array(
+    '#title' => t('Name'),
+    '#description' => t('Example: Image gallery') . ' (' . t('Do not begin name with numbers.') . ')',
+    '#type' => 'textfield',
+    '#default_value' => !empty($feature->info['name']) ? $feature->info['name'] : '',
+    '#attributes' => array('class' => array('feature-name')),
+  );
+  $form['info']['module_name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Machine-readable name'),
+    '#description' => t('Example: image_gallery') . '<br/>' . t('May only contain lowercase letters, numbers and underscores. <strong>Try to avoid conflicts with the names of existing Drupal projects.</strong>'),
+    '#required' => TRUE,
+    '#default_value' => $feature_name,
+    '#attributes' => array('class' => array('feature-module-name')),
+    '#element_validate' => array('features_export_form_validate_field'),
+  );
+  // If recreating this feature, disable machine name field and blank out
+  // js-attachment classes to ensure the machine name cannot be changed.
+  if (isset($feature)) {
+    $form['info']['module_name']['#value'] = $feature_name;
+    $form['info']['module_name']['#disabled'] = TRUE;
+    $form['info']['name']['#attributes'] = array();
+  }
+  $form['info']['description'] = array(
+    '#title' => t('Description'),
+    '#description' => t('Provide a short description of what users should expect when they enable your feature.'),
+    '#type' => 'textfield',
+    '#default_value' => !empty($feature->info['description']) ? $feature->info['description'] : '',
+  );
+  $form['info']['package'] = array(
+    '#title' => t('Package'),
+    '#description' => t('Organize your features in groups.'),
+    '#type' => 'textfield',
+    '#autocomplete_path' => 'features/autocomplete/packages',
+    '#default_value' => !empty($feature->info['package']) ? $feature->info['package'] : 'Features',
+  );
+  $form['info']['version'] = array(
+    '#title' => t('Version'),
+    '#description' => t('Examples: 7.x-1.0, 7.x-1.0-beta1'),
+    '#type' => 'textfield',
+    '#required' => FALSE,
+    '#default_value' => !empty($feature->info['version']) ? $feature->info['version'] : '',
+    '#size' => 30,
+    '#element_validate' => array('features_export_form_validate_field'),
+  );
+  $form['advanced'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Advanced Options'),
+    '#tree' => FALSE,
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#weight' => 10,
+    '#prefix' => "<div id='features-export-advanced'>",
+    '#suffix' => '</div>',
+  );
+  $form['advanced']['project_status_url'] = array(
+    '#title' => t('URL of update XML'),
+    '#description' => t('URL of Feature Server.  For Example: http://mywebsite.com/fserver'),
+    '#type' => 'textfield',
+    '#required' => FALSE,
+    '#default_value' => !empty($feature->info['project status url']) ? $feature->info['project status url'] : '',
+    '#element_validate' => array('features_export_form_validate_field'),
+  );
+  $directory = (!empty($feature->filename)) ? dirname($feature->filename) : 'sites/all/modules/features';
+  if (!empty($feature_name) && substr_compare($directory, $feature_name, strlen($directory)-strlen($feature_name), strlen($feature_name)) === 0) {
+    // if path ends with module_name, strip it
+    $directory = dirname($directory);
+  }
+  if (user_access('generate features')) {
+    $form['advanced']['generate_path'] = array(
+      '#title' => t('Path to Generate feature module'),
+      '#description' => t('File path for feature module.  For Example: sites/all/modules/features or /tmp.  ' .
+        t('Leave blank for <strong>@path</strong>', array('@path' => $directory))),
+      '#type' => 'textfield',
+      '#required' => FALSE,
+      '#default_value' => !empty($feature->info['project path']) ? $feature->info['project path'] : '',
+    );
+    $form['advanced']['generate'] = array(
+      '#type' => 'submit',
+      '#value' => t('Generate feature'),
+      '#submit' => array('features_export_build_form_submit'),
+    );
+  }
+  // build the Component Listing panel on the right
+  _features_export_form_components($form, $form_state);
+
+  $form['advanced']['info-preview'] = array(
+    '#type' => 'button',
+    '#value' => t('Preview .info file'),
+    '#ajax' => array(
+      'callback' => 'features_info_file_preview',
+      'wrapper' => 'features-export-wrapper',
+    ),
+  );
+  //Info dialog
+  $form['advanced']['info-file'] = array(
+    '#prefix' => '<div id="features-info-file" title="Export .info file preview">',
+    'text'    => array(
+      '#type' => 'textarea',
+      '#default_value' => '',
+      '#resizable' => FALSE,
+    ),
+    '#suffix' => '</div>',
+  );
+
+  $form['buttons'] = array(
+    '#theme' => 'features_form_buttons',
+    '#tree' => FALSE,
+    '#weight' => 99,
+    '#prefix' => "<div id='features-export-buttons'>",
+    '#suffix' => '</div>',
+  );
+  $form['buttons']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Download feature'),
+    '#weight' => 10,
+    '#submit' => array('features_export_build_form_submit'),
+  );
+
+  $form['#attached']['library'][] = array('system', 'ui.dialog');
+
+  return $form;
+}
+
+/**
+ * Return the render array elements for the Components selection on the Export form
+ * @param  array $feature    - feature associative array
+ * @param  array $components - array of components in feature
+ */
+function _features_export_form_components(&$form, &$form_state) {
+  global $features_ignore_conflicts;
+  drupal_add_css(drupal_get_path('module', 'features') . '/features.css');
+  drupal_add_js(drupal_get_path('module', 'features') . '/features.js');
+
+  $feature = $form['#feature'];
+
+  // keep the allow_conflict variable around in the session
+  if (isset($form_state['values']['features_allow_conflicts'])) {
+    $_SESSION['features_allow_conflicts'] = $form_state['values']['features_allow_conflicts'];
+    $features_ignore_conflicts = $_SESSION['features_allow_conflicts'];
+  }
+
+  $form['export'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Components'),
+    '#description' => t('Expand each component section and select which items should be included in this feature export.'),
+    '#tree' => FALSE,
+    '#prefix' => "<div id='features-export-wrapper'>",
+    '#suffix' => '</div>',
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+    '#weight' => 1,
+  );
+
+  // filter field used in javascript, so javascript will unhide it
+  $form['export']['features_filter_wrapper'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Filters'),
+    '#tree' => FALSE,
+    '#prefix' => "<div id='features-filter' class='element-invisible'>",
+    '#suffix' => '</div>',
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+    '#weight' => -10,
+  );
+  $form['export']['features_filter_wrapper']['features_filter'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Search'),
+    '#hidden' => TRUE,
+    '#default_value' => '',
+    '#suffix' => "<span class='features-filter-clear'>". t('Clear') ."</span>",
+  );
+  $form['export']['features_filter_wrapper']['checkall'] = array(
+    '#type' => 'checkbox',
+    '#default_value' => FALSE,
+    '#hidden' => TRUE,
+    '#title' => t('Select all'),
+    '#attributes' => array(
+      'class' => array('features-checkall'),
+    )
+  );
+
+  $form['advanced']['features_autodetect_wrapper'] = array(
+    '#type' => 'fieldset',
+    '#tree' => FALSE,
+    '#prefix' => "<div id='features-autodetect'>",
+    '#suffix' => '</div>',
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+  );
+  $form['advanced']['features_autodetect_wrapper']['autodetect'] = array(
+    '#title' => t('Add auto-detected dependencies'),
+    '#type' => 'checkbox',
+    '#default_value' => !empty($feature->info['no autodetect']) ? FALSE : TRUE,
+  );
+
+  // this refresh button will rebuild the form.
+  // this button is hidden by javascript since it is only needed when
+  // javascript is not available
+  $form['advanced']['features_autodetect_wrapper']['features_refresh'] = array(
+    '#type' => 'submit',
+    '#value' => t('Refresh'),
+    '#name' => 'features-refresh',
+    '#attributes' => array(
+      'title' => t("Refresh the list of auto-detected items."),
+      'class' => array('features-refresh-button'),
+    ),
+    '#submit' => array('features_export_form_rebuild'),
+    '#prefix' => "<div class='features-refresh-wrapper'>",
+    '#suffix' => "</div>",
+    '#ajax' => array(
+      'callback' => 'features_export_form_ajax',
+      'wrapper' => 'features-export-wrapper',
+    ),
+  );
+
+  // generate the export array for the current feature and user selections
+  $export = _features_export_build($feature, $form_state);
+
+  $form['advanced']['features_allow_conflicts'] = array(
+    '#title' => t('Allow conflicts to be added'),
+    '#type' => 'checkbox',
+    '#default_value' => $features_ignore_conflicts,
+    '#ajax' => array(
+      'callback' => 'features_export_form_ajax',
+      'wrapper' => 'features-export-wrapper',
+    ),
+  );
+
+  if (isset($form_state['values']['op']) && ($form_state['values']['op'] == $form_state['values']['info-preview'])) {
+    // handle clicking Preview button
+    module_load_include('inc', 'features', 'features.export');
+
+    $feature_export = _features_export_generate($export, $form_state, $feature);
+    $feature_export = features_export_prepare($feature_export, $feature->name, TRUE);
+    $info = features_export_info($feature_export);
+
+    drupal_add_js(array('features' => array('info' => $info)), 'setting');
+  }
+
+  // determine any components that are deprecated
+  $deprecated = features_get_deprecated($export['components']);
+
+  $sections = array('included', 'detected', 'added');
+  foreach ($export['components'] as $component => $component_info) {
+    if (!variable_get('features_admin_show_component_' . $component, TRUE)) {
+      continue;
+    }
+    $label = (isset($component_info['name']) ?
+      $component_info['name'] . " <span>(" . check_plain($component) . ")</span>" : check_plain($component));
+
+    $count = 0;
+    foreach ($sections as $section) {
+      $count += count($component_info['options'][$section]);
+    }
+    $extra_class = ($count == 0) ? 'features-export-empty' : '';
+    $component_name = str_replace('_', '-', check_plain($component));
+
+    if ($count + count($component_info['options']['sources']) > 0) {
+
+      if (!empty($deprecated[$component])) {
+        // only show deprecated component if it has some exports
+        if (!empty($component_info['options']['included'])) {
+          $form['export'][$component] = array(
+            '#markup' => '',
+            '#tree' => TRUE,
+            );
+
+          $form['export'][$component]['deprecated'] = array(
+            '#type' => 'fieldset',
+            '#title' => $label . "<span class='features-conflict'> (" . t('DEPRECATED') . ")</span>",
+            '#tree' => TRUE,
+            '#collapsible' => TRUE,
+            '#collapsed' => TRUE,
+            '#attributes' => array('class' => array('features-export-component')),
+          );
+          $list = ' ';
+          foreach ($component_info['options']['included'] as $key) {
+            $list .= "<span class='form-type-checkbox features-conflict'>$key</span>";
+          }
+          $form['export'][$component]['deprecated']['selected'] = array(
+            '#prefix' => "<div class='component-detected'>",
+            '#markup' => $list,
+            '#suffix' => "</div>",
+          );
+        }
+      }
+      else {
+        $form['export'][$component] = array(
+          '#markup' => '',
+          '#tree' => TRUE,
+          );
+
+        $form['export'][$component]['sources'] = array(
+          '#type' => 'fieldset',
+          '#title' => $label,
+          '#tree' => TRUE,
+          '#collapsible' => TRUE,
+          '#collapsed' => TRUE,
+          '#attributes' => array('class' => array('features-export-component')),
+          '#prefix' => "<div class='features-export-parent component-$component'>",
+        );
+        $form['export'][$component]['sources']['selected'] = array(
+          '#type' => 'checkboxes',
+          '#id' => "edit-sources-$component_name",
+          '#options' => features_dom_encode_options($component_info['options']['sources']),
+          '#default_value' => features_dom_encode_options($component_info['selected']['sources'], FALSE),
+          '#attributes' => array(
+            'class' => array('component-select'),
+          ),
+        );
+
+        foreach ($sections as $section) {
+          $form['export'][$component][$section] = array(
+            '#type' => 'checkboxes',
+            '#options' => !empty($component_info['options'][$section]) ?
+              features_dom_encode_options($component_info['options'][$section]) : array(),
+            '#default_value' => !empty($component_info['selected'][$section]) ?
+              features_dom_encode_options($component_info['selected'][$section], FALSE) : array(),
+            '#attributes' => array('class' => array('component-' . $section)),
+          );
+        }
+        $form['export'][$component][$sections[0]]['#prefix'] =
+          "<div class='component-list features-export-list $extra_class'>";
+        $form['export'][$component][$sections[count($sections)-1]]['#suffix'] = '</div></div>';
+      }
+    }
+  }
+  $form['export']['features_legend'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Legend'),
+    '#tree' => FALSE,
+    '#prefix' => "<div id='features-legend'>",
+    '#suffix' => '</div>',
+    '#collapsible' => FALSE,
+    '#collapsed' => FALSE,
+  );
+  $form['export']['features_legend']['legend'] = array(
+    '#markup' =>
+      "<span class='component-included'>Normal</span> " .
+      "<span class='component-added'>Changed</span> " .
+      "<span class='component-detected'>Auto detected</span> " .
+      "<span class='features-conflict'>Conflict</span> ",
+  );
+}
+
+/**
+ * Return the full feature export array based upon user selections in form_state
+ * @param  array $feature    Feature array to be exported
+ * @param  array $form_state Optional form_state information for user selections
+ *   can be updated to reflect new selection status
+ * @return array             New export array to be exported
+ *   array['components'][$component_name] = $component_info
+ *     $component_info['options'][$section] is list of available options
+ *     $component_info['selected'][$section] is option state TRUE/FALSE
+ *   $section = array('sources', included', 'detected', 'added')
+ *     sources - options that are available to be added to the feature
+ *     included - options that have been previously exported to the feature
+ *     detected - options that have been auto-detected
+ *     added - newly added options to the feature
+ *
+ * NOTE: This routine gets a bit complex to handle all of the different possible
+ * user checkbox selections and de-selections.
+ * Cases to test:
+ *   1a) uncheck Included item -> mark as Added but unchecked
+ *   1b) re-check unchecked Added item -> return it to Included check item
+ *   2a) check Sources item -> mark as Added and checked
+ *   2b) uncheck Added item -> return it to Sources as unchecked
+ *   3a) uncheck Included item that still exists as auto-detect -> mark as Detected but unchecked
+ *   3b) re-check Detected item -> return it to Included and checked
+ *   4a) check Sources item should also add any auto-detect items as Detected and checked
+ *   4b) uncheck Sources item with auto-detect and auto-detect items should return to Sources and unchecked
+ *   5a) uncheck a Detected item -> refreshing page should keep it as unchecked Detected
+ *   6)  when nothing changes, refresh should not change any state
+ *   7)  should never see an unchecked Included item
+ */
+function _features_export_build($feature, &$form_state) {
+  global $features_ignore_conflicts;
+  // set a global to effect features_get_component_map when building feature
+  // hate to use a global, but it's just for an admin screen so probably ok
+  if (isset($_SESSION['features_allow_conflicts'])) {
+    $features_ignore_conflicts = $_SESSION['features_allow_conflicts'];
+  }
+
+  $feature_name = isset($feature->name) ? $feature->name : NULL;
+  $conflicts = _features_get_used($feature_name);
+  $reset = FALSE;
+  if (isset($form_state['triggering_element']['#name']) && ($form_state['triggering_element']['#name'] == 'features_allow_conflicts')) {
+    // when clicking the Allow Conflicts button, reset the feature back to it's original state
+    $reset = TRUE;
+  }
+
+  module_load_include('inc', 'features', 'features.export');
+  features_include();
+
+  $components = features_get_components();
+  uasort($components, 'features_compare_component_name');
+
+  // Assemble the combined component list
+  $stub = array();
+  $sections = array('sources', 'included', 'detected', 'added');
+
+  // create a new feature "stub" to populate
+
+  $stub_count = array();
+  foreach ($components as $component => $component_info) {
+    if ($reset) {
+      unset($form_state['values'][$component]);
+    }
+    if (!variable_get('features_admin_show_component_' . $component, TRUE)) {
+      unset($components[$component]);
+      continue;
+    }
+    // User-selected components take precedence.
+    $stub[$component] = array();
+    $stub_count[$component] = 0;
+    // add selected items from Sources checkboxes
+    if (!empty($form_state['values'][$component]['sources']['selected'])) {
+      $stub[$component] = array_merge($stub[$component], features_dom_decode_options(array_filter($form_state['values'][$component]['sources']['selected'])));
+      $stub_count[$component]++;
+    }
+    // add selected items from already Included and newly Added checkboxes
+    foreach (array('included', 'added') as $section) {
+      if (!empty($form_state['values'][$component][$section])) {
+        $stub[$component] = array_merge($stub[$component], features_dom_decode_options(array_filter($form_state['values'][$component][$section])));
+        $stub_count[$component]++;
+      }
+    }
+    // count any detected items
+    if (!empty($form_state['values'][$component]['detected'])) {
+      $stub_count[$component]++;
+      }
+    // Only fallback to an existing feature's values if there are no export options for the component.
+    if ($component == 'dependencies') {
+      if (($stub_count[$component] == 0) && !empty($feature->info['dependencies'])) {
+        $stub[$component] = drupal_map_assoc($feature->info['dependencies']);
+      }
+    }
+    elseif (($stub_count[$component] == 0) && !empty($feature->info['features'][$component])) {
+      $stub[$component] = drupal_map_assoc($feature->info['features'][$component]);
+    }
+  }
+  // Generate new populated feature
+  $export = features_populate(array('features' => $stub, 'dependencies' => $stub['dependencies']), $feature_name);
+
+  // Components that are already exported to feature
+  $exported_features_info = !empty($feature->info['features']) ? $feature->info['features'] : array();
+  $exported_features_info['dependencies'] = !empty($feature->info['dependencies']) ? $feature->info['dependencies'] : array();
+  // Components that should be exported
+  $new_features_info = !empty($export['features']) ? $export['features'] : array();
+  $new_features_info['dependencies'] = !empty($export['dependencies']) ? $export['dependencies'] : array();
+  $excluded = !empty($feature->info['features_exclude']) ? $feature->info['features_exclude'] : array();
+
+  // now fill the $export with categorized sections of component options
+  // based upon user selections and de-selections
+
+  foreach ($components as $component => $component_info) {
+    $component_export = $component_info;
+    foreach ($sections as $section) {
+      $component_export['options'][$section] = array();
+      $component_export['selected'][$section] = array();
+    }
+    $options = features_invoke($component, 'features_export_options');
+    if (!empty($options)) {
+      $exported_components = !empty($exported_features_info[$component]) ? $exported_features_info[$component] : array();
+      $new_components = !empty($new_features_info[$component]) ? $new_features_info[$component] : array();
+
+      // Find all default components that are not provided by this feature and
+      // strip them out of the possible options.
+      if ($map = features_get_default_map($component)) {
+        foreach ($map as $k => $v) {
+          if (isset($options[$k]) && (!isset($feature->name) || $v !== $feature->name)) {
+            unset($options[$k]);
+          }
+        }
+      }
+      foreach ($options as $key => $value) {
+        // use the $clean_key when accessing $form_state
+        $clean_key = features_dom_encode($key);
+        // if checkbox in Sources is checked, move it to Added section
+        if (!empty($form_state['values'][$component]['sources']['selected'][$clean_key])) {
+          unset($form_state['input'][$component]['sources']['selected'][$clean_key]);
+          $form_state['values'][$component]['sources']['selected'][$clean_key] = FALSE;
+          $form_state['values'][$component]['added'][$clean_key] = 1;
+          $form_state['input'][$component]['added'][$clean_key] = $clean_key;
+          $component_export['options']['added'][$key] = check_plain($value);
+          $component_export['selected']['added'][$key] = $key;
+        }
+        elseif (in_array($key, $new_components)) {
+          // option is in the New exported array
+          if (in_array($key, $exported_components)) {
+            // option was already previously exported
+            // so it's part of the Included checkboxes
+            $section = 'included';
+            $default_value = $key;
+            if ($reset) {
+              // leave it included
+            }
+            // if Included item was un-selected (removed from export $stub)
+            // but was re-detected in the $new_components
+            // means it was an auto-detect that was previously part of the export
+            // and is now de-selected in UI
+            elseif (!empty($form_state['values']) &&
+                (isset($form_state['values'][$component]['included'][$clean_key]) ||
+                 empty($form_state['values'][$component]['detected'][$clean_key])) &&
+                empty($stub[$component][$key])) {
+              $section = 'detected';
+              $default_value = FALSE;
+            }
+            // unless it's unchecked in the form, then move it to Newly disabled item
+            elseif (!empty($form_state['values']) &&
+                empty($form_state['values'][$component]['added'][$clean_key]) &&
+                empty($form_state['values'][$component]['detected'][$clean_key]) &&
+                empty($form_state['values'][$component]['included'][$clean_key])) {
+              $section = 'added';
+              $default_value = FALSE;
+            }
+          }
+          else {
+            // option was in New exported array, but NOT in already exported
+            // so it's a user-selected or an auto-detect item
+            $section = 'detected';
+            // check for item explicity excluded
+            if (isset($excluded[$component][$key]) && !isset($form_state['values'][$component]['detected'][$clean_key])) {
+              $default_value = FALSE;
+            }
+            else {
+              $default_value = $key;
+            }
+            // if it's already checked in Added or Sources, leave it in Added as checked
+            if (!empty($form_state['values']) &&
+              (!empty($form_state['values'][$component]['added'][$clean_key]) ||
+               !empty($form_state['values'][$component]['sources']['selected'][$clean_key]))) {
+              $section = 'added';
+              $default_value = $key;
+            }
+            // if it's already been unchecked, leave it unchecked
+            elseif (!empty($form_state['values']) &&
+              empty($form_state['values'][$component]['sources']['selected'][$clean_key]) &&
+              empty($form_state['values'][$component]['detected'][$clean_key]) &&
+              !isset($form_state['values'][$component]['added'][$clean_key])) {
+              $section = 'detected';
+              $default_value = FALSE;
+            }
+          }
+          $component_export['options'][$section][$key] = check_plain($value);
+          $component_export['selected'][$section][$key] = $default_value;
+          // save which dependencies are specifically excluded from auto-detection
+          if (($section == 'detected') && ($default_value === FALSE)) {
+            $excluded[$component][$key] = $key;
+            // remove excluded item from export
+            if ($component == 'dependencies') {
+              unset($export['dependencies'][$key]);
+            }
+            else {
+              unset($export['features'][$component][$key]);
+            }
+          }
+          else {
+            unset($excluded[$component][$key]);
+          }
+          // remove the 'input' and set the 'values' so Drupal stops looking at 'input'
+          if (isset($form_state['values'])) {
+            if (!$default_value) {
+              unset($form_state['input'][$component][$section][$clean_key]);
+              $form_state['values'][$component][$section][$clean_key] = FALSE;
+            }
+            else {
+              $form_state['input'][$component][$section][$clean_key] = $clean_key;
+              $form_state['values'][$component][$section][$clean_key] = 1;
+            }
+          }
+        }
+        else {
+          // option was not part of the new export
+          $added = FALSE;
+          foreach (array('included', 'added') as $section) {
+            // restore any user-selected checkboxes
+            if (!empty($form_state['values'][$component][$section][$clean_key])) {
+              $component_export['options'][$section][$key] = check_plain($value);
+              $component_export['selected'][$section][$key] = $key;
+              $added = TRUE;
+            }
+          }
+          if (!$added) {
+            // if not Included or Added, then put it back in the unchecked Sources checkboxes
+            $component_export['options']['sources'][$key] = check_plain($value);
+            $component_export['selected']['sources'][$key] = FALSE;
+          }
+        }
+      }
+    }
+    $export['components'][$component] = $component_export;
+  }
+  $export['features_exclude'] = $excluded;
+
+  // make excluded list and conflicts available for javascript to pass to our ajax callback
+  drupal_add_js(array('features' => array(
+    'excluded' => $excluded,
+    'conflicts' => $conflicts,
+    )), 'setting');
+
+  return $export;
+}
+
+/**
+ * AJAX callback for features_export_form.
+ */
+function features_export_form_ajax($form, &$form_state) {
+  return $form['export'];
+}
+
+/**
+ * Tells the ajax form submission to rebuild form state.
+ */
+function features_export_form_rebuild($form, &$form_state) {
+  $form_state['rebuild'] = TRUE;
+}
+
+function features_export_components_json($feature_name) {
+  module_load_include('inc', 'features', 'features.export');
+  $export = array();
+  if (!empty($_POST['items'])) {
+    $excluded = (!empty($_POST['excluded'])) ? $_POST['excluded'] : array();
+    $stub = array();
+    foreach ($_POST['items'] as $key) {
+      preg_match('/^([^\[]+)(\[.+\])?\[(.+)\]\[(.+)\]$/', $key, $matches);
+      if (!empty($matches[1]) && !empty($matches[4])) {
+        $component = $matches[1];
+        $item = features_dom_decode($matches[4]);
+        if (empty($stub[$component])) {
+          $stub[$component] = array($item);
+        }
+        else {
+          $stub[$component] = array_merge($stub[$component], array($item));
+        }
+      }
+    }
+
+    $stub['dependencies'] = isset($stub['dependencies']) ? $stub['dependencies'] : array();
+    $export = features_populate(array('features' => $stub, 'dependencies' => $stub['dependencies']), $feature_name);
+    $export['features']['dependencies'] = $export['dependencies'];
+
+    // uncheck any detected item that is in the excluded list
+    foreach ($export['features'] as $component => $value) {
+      foreach ($value as $key => $item) {
+        $clean_key = features_dom_encode($key);
+        if ($key != $clean_key) {
+          // need to move key to a cleankey for javascript
+          $export['features'][$component][$clean_key] = $export['features'][$component][$key];
+          unset($export['features'][$component][$key]);
+        }
+        if (isset($excluded[$component][$key])) {
+          $export['features'][$component][$clean_key] = FALSE;
+        }
+      }
+    }
+  }
+  print drupal_json_encode($export['features']);
+}
+
+/**
+ * AJAX callback to get .info file preview.
+ */
+function features_info_file_preview($form, &$form_state){
+  return $form['export'];
+}
+
+/**
+ * Render API callback: Validates a project field.
+ *
+ * This function is assigned as an #element_validate callback in
+ * features_export_form().
+ */
+function features_export_form_validate_field($element, &$form_state) {
+  switch ($element['#name']) {
+    case 'module_name':
+      if (!preg_match('!^[a-z0-9_]+$!', $element['#value'])) {
+        form_error($element, t('The machine-readable name must contain only lowercase letters, numbers, and underscores.'));
+      }
+      // If user is filling out the feature name for the first time and uses
+      // the name of an existing module throw an error.
+      else if (empty($element['#default_value']) && features_get_info('module', $element['#value'])) {
+        form_error($element, t('A module by the name @name already exists on your site. Please choose a different name.', array('@name' => $element['#value'])));
+      }
+      break;
+    case 'project_status_url':
+      if (!empty($element['#value']) && !valid_url($element['#value'])) {
+        form_error($element, t('The URL %url is invalid. Please enter a fully-qualified URL, such as http://www.example.com/feed.xml.', array('%url' => $element['#value'])));
+      }
+      break;
+    case 'version':
+      preg_match('/^(?P<core>\d+\.x)-(?P<major>\d+)\.(?P<patch>\d+)-?(?P<extra>\w+)?$/', $element['#value'], $matches);
+      if (!empty($element['#value']) && !isset($matches['core'], $matches['major'])) {
+        form_error($element, t('Please enter a valid version with core and major version number. Example: @example', array('@example' => '7.x-1.0')));
+      };
+      break;
+  }
+}
+
+/**
+ * Return the $export array to be rendered for the feature export
+ */
+function _features_export_generate($export, $form_state, $feature = NULL) {
+  unset($export['components']); // remove the UI data that we are not saving to disk
+
+  $module_name = $form_state['values']['module_name'];
+  // Directly copy the following attributes from form_state
+  $attr = array('name', 'description', 'package', 'project path');
+  foreach ($attr as $key) {
+    $export[$key] = isset($form_state['values'][$key]) ? $form_state['values'][$key] : NULL;
+  }
+  // Directly copy the following attributes from the original feature
+  $attr = array('scripts' , 'stylesheets');
+  foreach ($attr as $key) {
+    $export[$key] = isset($feature->info[$key]) ? $feature->info[$key] : NULL;
+  }
+  // If either update status-related keys are provided, add a project key
+  // corresponding to the module name.
+  if (!empty($form_state['values']['version']) || !empty($form_state['values']['project_status_url'])) {
+    $export['project'] = $form_state['values']['module_name'];
+  }
+  if (!empty($form_state['values']['version'])) {
+    $export['version'] = $form_state['values']['version'];
+  }
+  if (!empty($form_state['values']['project_status_url'])) {
+    $export['project status url'] = $form_state['values']['project_status_url'];
+  }
+  $export['no autodetect'] = empty($form_state['values']['autodetect']) ? 1 : NULL;
+  $export['project path'] = !empty($form_state['values']['generate_path']) ? $form_state['values']['generate_path'] : NULL;
+  return $export;
+}
+
+/**
+ * Form submission handler for features_export_form().
+ */
+function features_export_build_form_submit($form, &$form_state) {
+  $feature = $form['#feature'];
+  $export = _features_export_build($feature, $form_state);
+  $export = _features_export_generate($export, $form_state, $feature);
+  $generate = ($form_state['values']['op'] == $form_state['values']['generate']);
+  $module_name = $form_state['values']['module_name'];
+
+  if ($generate && !user_access('generate features')) {
+    drupal_set_message(t("No permission for generating features."));
+    return;
+  }
+
+  // Generate download
+  if ($files = features_export_render($export, $module_name, TRUE)) {
+    $filename = (!empty($export['version']) ? "{$module_name}-{$export['version']}" : $module_name) . '.tar';
+
+    if ($generate) {
+      $success = TRUE;
+      $destination = 'sites/all/modules/features';
+      $directory = (!empty($export['project path'])) ? $export['project path'] . '/' . $module_name :
+        (isset($feature->filename) ? dirname($feature->filename) : $destination . '/' . $module_name);
+      if (!is_dir($directory)) {
+        if (mkdir($directory, 0777, true) === FALSE) {
+          $success = FALSE;
+        }
+      }
+    }
+    else {
+      // Clear out output buffer to remove any garbage from tar output.
+      if (ob_get_level()) {
+        ob_end_clean();
+      }
+
+      drupal_add_http_header('Content-type', 'application/x-tar');
+      drupal_add_http_header('Content-Disposition', 'attachment; filename="'. $filename .'"');
+      drupal_send_headers();
+    }
+
+    $tar = array();
+    $filenames = array();
+    foreach ($files as $extension => $file_contents) {
+      if (!in_array($extension, array('module', 'info'))) {
+        $extension .= '.inc';
+      }
+      $filenames[] = "{$module_name}.$extension";
+      if ($generate) {
+        if (file_put_contents("{$directory}/{$module_name}.$extension", $file_contents) === FALSE) {
+          $success = FALSE;
+        }
+      }
+      else {
+        print features_tar_create("{$module_name}/{$module_name}.$extension", $file_contents);
+      }
+    }
+    if (features_get_modules($module_name, TRUE)) {
+      // prevent deprecated component files from being included in download
+      $deprecated = features_get_deprecated();
+      foreach ($deprecated as $component) {
+        $info = features_get_components($component);
+        $filename = isset($info['default_file']) && $info['default_file'] == FEATURES_DEFAULTS_CUSTOM ? $info['default_filename'] : "features.{$component}";
+        $filename .= '.inc';
+        $filenames[] = "{$module_name}.$filename";
+      }
+      $module_path = drupal_get_path('module', $module_name);
+      // file_scan_directory() can throw warnings when using PHP 5.3, messing
+      // up the output of our file stream. Suppress errors in this one case in
+      // order to produce valid output.
+      foreach (@file_scan_directory($module_path, '/.*/') as $file) {
+        $filename = substr($file->uri, strlen($module_path) + 1);
+        if (!in_array($filename, $filenames)) {
+          // Add this file.
+          $contents = file_get_contents($file->uri);
+          if ($generate) {
+            if (file_put_contents("{$directory}/{$filename}", $contents) === FALSE) {
+              $success = FALSE;
+            }
+          }
+          else {
+            print features_tar_create("{$module_name}/{$filename}", $contents);
+          }
+          unset($contents);
+        }
+      }
+    }
+    if ($generate) {
+      if ($success) {
+        drupal_set_message(t("Module @name written to @directory",
+          array('@name' => $export['name'], '@directory' => $directory)));
+        }
+      else {
+        drupal_set_message(
+          t("Could not write module to @path. ", array('@path' => $directory)) .
+          t("Ensure your file permissions allow the web server to write to that directory."), "error");
+      }
+    }
+    else {
+      print pack("a1024","");
+      exit;
+    }
+  }
+}
+
+/**
+ * array_filter() callback for excluding hidden modules.
+ */
+function features_filter_hidden($module) {
+  return empty($module->info['hidden']);
+}
+
+/**
+ * Form constructor for the features configuration form.
+ */
+function features_admin_form($form, $form_state) {
+  // Load export functions to use in comparison.
+  module_load_include('inc', 'features', 'features.export');
+
+  // Clear & rebuild key caches
+  features_get_info(NULL, NULL, TRUE);
+  features_rebuild();
+
+  $modules = array_filter(features_get_modules(), 'features_filter_hidden');
+  $features = array_filter(features_get_features(), 'features_filter_hidden');
+  $conflicts = features_get_conflicts();
+
+  foreach ($modules as $key => $module) {
+    if ($module->status && !empty($module->info['dependencies'])) {
+      foreach ($module->info['dependencies'] as $dependent) {
+        if (isset($features[$dependent])) {
+          $features[$dependent]->dependents[$key] = $module->info['name'];
+        }
+      }
+    }
+  }
+
+  if ( empty($features) ) {
+    $form['no_features'] = array(
+      '#markup' => t('No Features were found. Please use the !create_link link to create
+      a new Feature module, or upload an existing Feature to your modules directory.',
+      array('!create_link' => l(t('Create Feature'), 'admin/structure/features/create'))),
+    );
+    return $form ;
+  }
+
+  $form = array('#features' => $features);
+
+  // Generate features form. Features are sorted by dependencies, resort alpha
+  ksort($features);
+  foreach ($features as $name => $module) {
+    $package_title = !empty($module->info['package']) ? $module->info['package'] : t('Other');
+    $package = strtolower(preg_replace('/[^a-zA-Z0-9-]+/', '-', $package_title));
+
+    // Set up package elements
+    if (!isset($form[$package])) {
+      $form[$package] = array(
+        '#tree' => FALSE,
+        '#title' => check_plain($package_title),
+        '#theme' => 'features_form_package',
+        '#type' => 'fieldset',
+        '#group' => 'packages',
+      );
+      $form[$package]['links'] =
+      $form[$package]['version'] =
+      $form[$package]['weight'] =
+      $form[$package]['status'] =
+      $form[$package]['action'] = array('#tree' => TRUE);
+    }
+
+    $disabled = FALSE;
+    $description = isset($module->info['description']) ? check_plain($module->info['description']) : '';
+
+    // Detect unmet dependencies
+    if (!empty($module->info['dependencies'])) {
+      $unmet_dependencies = array();
+      $dependencies = _features_export_maximize_dependencies($module->info['dependencies']);
+      foreach ($dependencies as $dependency) {
+        if (empty($modules[$dependency])) {
+          $unmet_dependencies[] = theme('features_module_status', array('status' => FEATURES_MODULE_MISSING, 'module' => $dependency));
+        }
+      }
+      if (!empty($unmet_dependencies)) {
+        $description .= "<div class='dependencies'>" . t('Unmet dependencies: !dependencies', array('!dependencies' => implode(', ', $unmet_dependencies))) . "</div>";
+        $disabled = TRUE;
+      }
+    }
+
+    if (!empty($module->dependents)) {
+      $disabled = TRUE;
+      $description .= "<div class='requirements'>". t('Required by: !dependents', array('!dependents' => implode(', ', $module->dependents))) ."</div>";
+    }
+
+    // Detect potential conflicts
+    if (!empty($conflicts[$name])) {
+      $module_conflicts = array();
+      foreach ($conflicts[$name] as $conflict => $components) {
+        $component_strings = array();
+        foreach ($components as $component => $component_conflicts) {
+          $component_strings[] = t('@component [@items]', array('@component' => $component, '@items' => implode(', ', $component_conflicts)));
+        }
+        $component_strings = implode(', ', $component_strings);
+        // If conflicting module is disabled, indicate so in feature listing
+        $status = !module_exists($conflict) ? FEATURES_MODULE_DISABLED : FEATURES_MODULE_CONFLICT;
+        $module_conflicts[] = theme('features_module_status', array('status' => $status, 'module' => $conflict)) . t(' in ') . $component_strings;
+        // Only disable modules with conflicts if they are not already enabled.
+        // If they are already enabled, somehow the user got themselves into a
+        // bad situation and they need to be able to disable a conflicted module.
+        if (module_exists($conflict) && !module_exists($name)) {
+          $disabled = TRUE;
+        }
+      }
+      $description .= "<div class='conflicts'>". t('Conflicts with: !conflicts', array('!conflicts' => implode(', ', $module_conflicts))) ."</div>";
+    }
+
+    $href = "admin/structure/features/{$name}";
+    $module_name = (user_access('administer features')) ? l($module->info['name'], $href) : $module->info['name'];
+    $form[$package]['status'][$name] = array(
+      '#type' => 'checkbox',
+      '#title' => $module_name,
+      '#description' => $description,
+      '#default_value' => $module->status,
+      '#disabled' => $disabled,
+    );
+
+    if (!empty($module->info['project status url'])) {
+      $uri = l(truncate_utf8($module->info['project status url'], 35, TRUE, TRUE), $module->info['project status url']);
+    }
+    else if (isset($module->info['project'], $module->info['version'], $module->info['datestamp'])) {
+      $uri = l('http://drupal.org', 'http://drupal.org/project/' . $module->info['project']);
+    }
+    else {
+      $uri = t('Unavailable');
+    }
+    $version = !empty($module->info['version']) ? $module->info['version'] : '';
+    $version = !empty($version) ? "<div class='description'>$version</div>" : '';
+    $form[$package]['sign'][$name] = array('#markup' => "{$uri} {$version}");
+
+    if (user_access('administer features')) {
+      // Add status link
+      if ($module->status) {
+        $state = theme('features_storage_link', array('storage' => FEATURES_CHECKING, 'path' => $href));
+        $state .= l(t('Check'), "admin/structure/features/{$name}/status", array('attributes' => array('class' => array('admin-check'))));
+        $state .= theme('features_storage_link', array('storage' => FEATURES_REBUILDING, 'path' => $href));
+        $state .= theme('features_storage_link', array('storage' => FEATURES_NEEDS_REVIEW, 'path' =>  $href));
+        $state .= theme('features_storage_link', array('storage' => FEATURES_OVERRIDDEN, 'path' =>  $href));
+        $state .= theme('features_storage_link', array('storage' => FEATURES_DEFAULT, 'path' =>  $href));
+      }
+      elseif (!empty($conflicts[$name])) {
+        $state = theme('features_storage_link', array('storage' => FEATURES_CONFLICT, 'path' => $href));
+      }
+      else {
+        $state = theme('features_storage_link', array('storage' => FEATURES_DISABLED, 'path' => $href));
+      }
+      $form[$package]['state'][$name] = array(
+        '#markup' => !empty($state) ? $state : '',
+      );
+
+      // Add in recreate link
+      $form[$package]['actions'][$name] = array(
+        '#markup' => l(t('Recreate'), "admin/structure/features/{$name}/recreate", array('attributes' => array('class' => array('admin-update')))),
+      );
+    }
+  }
+  ksort($form);
+
+  // As of 7.0 beta 2 it matters where the "vertical_tabs" element lives on the
+  // the array. We add it late, but at the beginning of the array because that
+  // keeps us away from trouble.
+  $form = array('packages' => array('#type' => 'vertical_tabs')) + $form;
+
+  $form['buttons'] = array(
+    '#theme' => 'features_form_buttons',
+  );
+  $form['buttons']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save settings'),
+    '#submit' => array('features_form_submit'),
+    '#validate' => array('features_form_validate'),
+  );
+  return $form;
+}
+
+/**
+ * Display the components of a feature.
+ */
+function features_admin_components($form, $form_state, $feature) {
+  // Breadcrumb navigation
+  $breadcrumb[] = l(t('Home'), NULL);
+  $breadcrumb[] = l(t('Administration'), 'admin');
+  $breadcrumb[] = l(t('Structure'), 'admin/structure');
+  $breadcrumb[] = l(t('Features'), 'admin/structure/features');
+  drupal_set_breadcrumb($breadcrumb);
+
+  module_load_include('inc', 'features', 'features.export');
+  $form = array();
+
+  // Store feature info for theme layer.
+  $form['module'] = array('#type' => 'value', '#value' => $feature->name);
+  $form['#info'] = $feature->info;
+  $form['#dependencies'] = array();
+  if (!empty($feature->info['dependencies'])) {
+    foreach ($feature->info['dependencies'] as $dependency) {
+      $parsed_dependency = drupal_parse_dependency($dependency);
+      $dependency = $parsed_dependency['name'];
+      $status = features_get_module_status($dependency);
+      $form['#dependencies'][$dependency] = $status;
+    }
+  }
+
+  $conflicts = features_get_conflicts();
+  if (!module_exists($form['module']['#value']) && isset($form['module']['#value']) && !empty($conflicts[$form['module']['#value']])) {
+    $module_conflicts = $conflicts[$form['module']['#value']];
+    $conflicts = array();
+    foreach ($module_conflicts as $conflict) {
+      $conflicts = array_merge_recursive($conflict, $conflicts);
+    }
+  }
+  else {
+    $conflicts = array();
+  }
+  $form['#conflicts'] = $conflicts;
+
+  $review = $revert = FALSE;
+
+  // Iterate over components and retrieve status for display
+  $states = features_get_component_states(array($feature->name), FALSE);
+  $form['revert']['#tree'] = TRUE;
+  foreach ($feature->info['features'] as $component => $items) {
+    if (user_access('administer features') && array_key_exists($component, $states[$feature->name]) && in_array($states[$feature->name][$component], array(FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW))) {
+      switch ($states[$feature->name][$component]) {
+        case FEATURES_OVERRIDDEN:
+          $revert = TRUE;
+          break;
+        case FEATURES_NEEDS_REVIEW:
+          $review = TRUE;
+          break;
+      }
+      $form['revert'][$component] = array(
+        '#type' => 'checkbox',
+        '#default_value' => FALSE,
+      );
+    }
+    if (module_exists('diff')) {
+      $diffpath = "admin/structure/features/{$feature->name}/diff/{$component}";
+      $item = menu_get_item($diffpath);
+      $path = ($item && $item['access']) ? $diffpath : NULL;
+    }
+    else {
+      $path = NULL;
+    }
+
+    $storage = FEATURES_DEFAULT;
+    if (array_key_exists($component, $states[$feature->name])) {
+      $storage = $states[$feature->name][$component];
+    }
+    else if (array_key_exists($component, $conflicts)) {
+      $storage = FEATURES_CONFLICT;
+    }
+    $form['components'][$component] = array(
+      '#markup' => theme('features_storage_link', array('storage' => $storage, 'path' =>  $path)),
+    );
+  }
+
+  if ($review || $revert) {
+    $form['buttons'] = array('#theme' => 'features_form_buttons', '#tree' => TRUE);
+    if ($revert || $review) {
+      $form['buttons']['revert'] = array(
+        '#type' => 'submit',
+        '#value' => t('Revert components'),
+        '#submit' => array('features_admin_components_revert'),
+      );
+    }
+    if ($review) {
+      $form['buttons']['review'] = array(
+        '#type' => 'submit',
+        '#value' => t('Mark as reviewed'),
+        '#submit' => array('features_admin_components_review'),
+      );
+    }
+  }
+  return $form;
+}
+
+/**
+ * Submit handler for revert form.
+ */
+function features_admin_components_revert(&$form, &$form_state) {
+  module_load_include('inc', 'features', 'features.export');
+  features_include();
+  $module = $form_state['values']['module'];
+  $revert = array($module => array());
+  foreach (array_filter($form_state['values']['revert']) as $component => $status) {
+    $revert[$module][] = $component;
+    drupal_set_message(t('Reverted all <strong>@component</strong> components for <strong>@module</strong>.', array('@component' => $component, '@module' => $module)));
+  }
+  if (empty($revert[$module])) {
+    drupal_set_message(t('Please select which components to revert.'), 'warning');
+  }
+  features_revert($revert);
+  $form_state['redirect'] = 'admin/structure/features/' . $module;
+}
+
+/**
+ * Submit handler for revert form.
+ */
+function features_admin_components_review(&$form, &$form_state) {
+  module_load_include('inc', 'features', 'features.export');
+  features_include();
+  $module = $form_state['values']['module'];
+  $revert = array();
+  foreach (array_filter($form_state['values']['revert']) as $component => $status) {
+    features_set_signature($module, $component);
+    drupal_set_message(t('All <strong>@component</strong> components for <strong>@module</strong> reviewed.', array('@component' => $component, '@module' => $module)));
+  }
+  $form_state['redirect'] = 'admin/structure/features/' . $module;
+}
+
+/**
+ * Validate handler for the 'manage features' form.
+ */
+function features_form_validate(&$form, &$form_state) {
+  include_once './includes/install.inc';
+  $conflicts = features_get_conflicts();
+  foreach ($form_state['values']['status'] as $module => $status) {
+    if ($status) {
+      if (!empty($conflicts[$module])) {
+        foreach (array_keys($conflicts[$module]) as $conflict) {
+          if (!empty($form_state['values']['status'][$conflict])) {
+            form_set_error('status', t('The feature @module cannot be enabled because it conflicts with @conflict.', array('@module' => $module, '@conflict' => $conflict)));
+          }
+        }
+      }
+      if (!drupal_check_module($module)) {
+        form_set_error('status', t('The feature @module cannot be enabled because it has unmet requirements.', array('@module' => $module)));
+      }
+    }
+  }
+}
+
+/**
+ * Submit handler for the 'manage features' form
+ */
+function features_form_submit(&$form, &$form_state) {
+  // Clear drupal caches after enabling a feature. We do this in a separate
+  // page callback rather than as part of the submit handler as some modules
+  // have includes/other directives of importance in hooks that have already
+  // been called in this page load.
+  $form_state['redirect'] = 'admin/structure/features/cleanup/clear';
+
+  $features = $form['#features'];
+  if (!empty($features)) {
+    $status = $form_state['values']['status'];
+    $install = array_keys(array_filter($status));
+    $disable = array_diff(array_keys($status), $install);
+
+    // Disable first. If there are any features that are disabled that are
+    // dependencies of features that have been queued for install, they will
+    // be re-enabled.
+    module_disable($disable);
+    features_install_modules($install);
+  }
+}
+
+/**
+ * Form for clearing cache after enabling a feature.
+ */
+function features_cleanup_form($form, $form_state, $cache_clear = FALSE) {
+  // Clear caches if we're getting a post-submit redirect that requests it.
+  if ($cache_clear) {
+    drupal_flush_all_caches();
+
+    // The following functions need to be run because drupal_flush_all_caches()
+    // runs rebuilds in the wrong order. The node type cache is rebuilt *after*
+    // the menu is rebuilt, meaning that the menu tree is stale in certain
+    // circumstances after drupal_flush_all_caches(). We rebuild again.
+    menu_rebuild();
+  }
+
+    drupal_goto('admin/structure/features');
+}
+
+/**
+ * Page callback to display the differences between what's in code and
+ * what is in the db.
+ *
+ * @param $feature
+ *   A loaded feature object to display differences for.
+ * @param $component
+ *   (optional) Specific component to display differences for. If excluded, all
+ *   components are used.
+ *
+ * @return
+ *   Themed display of what is different.
+ */
+function features_feature_diff($feature, $component = NULL) {
+  drupal_add_css(drupal_get_path('module', 'features') . '/features.css');
+  module_load_include('inc', 'features', 'features.export');
+  drupal_set_title($feature->info['name']);
+
+  $overrides = features_detect_overrides($feature);
+
+  $output = '';
+  if (!empty($overrides)) {
+    // Filter overrides down to specified component.
+    if (isset($component) && isset($overrides[$component])) {
+      $overrides = array($component => $overrides[$component]);
+    }
+
+    module_load_include('inc', 'diff', 'diff.engine');
+    $formatter = new DrupalDiffFormatter();
+
+    $rows = array();
+    foreach ($overrides as $component => $items) {
+      $rows[] = array(array('data' => $component, 'colspan' => 4, 'header' => TRUE));
+      $diff = new Diff(explode("\n", $items['default']), explode("\n", $items['normal']));
+      $rows = array_merge($rows, $formatter->format($diff));
+    }
+    $header = array(
+      array('data' => t('Default'), 'colspan' => 2),
+      array('data' => t('Overrides'), 'colspan' => 2),
+    );
+    $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('diff', 'features-diff'))));
+  }
+  else {
+    $output = "<div class='features-empty'>" . t('No changes have been made to this feature.') . "</div>";
+  }
+  $output = array('page' => array('#markup' => "<div class='features-comparison'>{$output}</div>"));
+  return $output;
+}
+
+/**
+ * Compare the component names. Used to sort alphabetically.
+ */
+function features_compare_component_name($a, $b) {
+  return strcasecmp($a['name'], $b['name']);
+}
+
+/**
+ * Javascript callback that returns the status of a feature.
+ */
+function features_feature_status($feature) {
+  module_load_include('inc', 'features', 'features.export');
+  return drupal_json_output(array('storage' => features_get_storage($feature->name)));
+}
+
+/**
+ * Make a Drupal options array safe for usage with jQuery DOM selectors.
+ * Encodes known bad characters into __[ordinal]__ so that they may be
+ * safely referenced by JS behaviors.
+ */
+function features_dom_encode_options($options = array(), $keys_only = TRUE) {
+  $replacements = features_dom_encode_map();
+  $encoded = array();
+  foreach ($options as $key => $value) {
+    $encoded[strtr($key, $replacements)] = $keys_only ? $value : strtr($value, $replacements);
+  }
+  return $encoded;
+}
+
+function features_dom_encode($key) {
+  $replacements = features_dom_encode_map();
+  return strtr($key, $replacements);
+}
+
+function features_dom_decode($key) {
+  $replacements = array_flip(features_dom_encode_map());
+  return strtr($key, $replacements);
+}
+
+/**
+ * Decode an array of option values that have been encoded by
+ * features_dom_encode_options().
+ */
+function features_dom_decode_options($options, $keys_only = FALSE) {
+  $replacements = array_flip(features_dom_encode_map());
+  $encoded = array();
+  foreach ($options as $key => $value) {
+    $encoded[strtr($key, $replacements)] = $keys_only ? $value : strtr($value, $replacements);
+  }
+  return $encoded;
+}
+
+/**
+ * Returns encoding map for decode and encode options.
+ */
+function features_dom_encode_map() {
+  return array(
+    ':' => '__' . ord(':') . '__',
+    '/' => '__' . ord('/') . '__',
+    ',' => '__' . ord(',') . '__',
+    '.' => '__' . ord('.') . '__',
+    '<' => '__' . ord('<') . '__',
+    '>' => '__' . ord('>') . '__',
+    '%' => '__' . ord('%') . '__',
+    ')' => '__' . ord(')') . '__',
+    '(' => '__' . ord('(') . '__',
+  );
+}
+
+/**
+ * Page callback: Autocomplete field for features package.
+ *
+ * @param $search_string
+ *   The char or string that user have written in autocomplete field,
+ *   this is the string this function uses for filter.
+ *
+ * @see features_menu()
+ */
+function features_autocomplete_packages($search_string) {
+  $matched_packages = array();
+  //fetch all modules that are features and copy the package name into a new array.
+  foreach (features_get_features(NULL, TRUE) as $value) {
+    if (preg_match('/' . $search_string . '/i', $value->info['package'])) {
+      $matched_packages[$value->info['package']] = $value->info['package'];
+    }
+  }
+  //removes duplicated package, we wont a list of all unique packages.
+  $matched_packages = array_unique($matched_packages);
+  drupal_json_output($matched_packages);
+}
+
+/**
+ * Return a list of all used components/items not matching a given feature module
+ * similar to features_get_conflicts but returns all component items "in use"
+ */
+function _features_get_used($module_name = NULL) {
+
+  global $features_ignore_conflicts;
+  // make sure we turn off the ignore_conflicts global to get full list of used components
+  // hate to use global, but since this is just for an admin screen it's not a real problem
+  $old_value = $features_ignore_conflicts;
+  $features_ignore_conflicts = FALSE;
+
+  $conflicts = array();
+  $component_info = features_get_components();
+  $map = features_get_component_map();
+
+  foreach ($map as $type => $components) {
+    // Only check conflicts for components we know about.
+    if (isset($component_info[$type])) {
+      foreach ($components as $component => $modules) {
+        foreach ($modules as $module) {
+          // only for enabled modules
+          if (module_exists($module) && (empty($module_name) || ($module_name != $module))) {
+            if (!isset($conflicts[$module])) {
+              $conflicts[$module] = array();
+            }
+            $conflicts[$module][$type][] = $component;
+          }
+        }
+      }
+    }
+  }
+
+  // restore previous value of global
+  $features_ignore_conflicts = $old_value;
+  return $conflicts;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,476 @@
+<?php
+
+/**
+ * Main info hook that features uses to determine what components are provided
+ * by the implementing module.
+ *
+ * @return array
+ *   An array of components, keyed by the component name. Each component can
+ *   define several keys:
+ *
+ *   'file': Optional path to a file to include which contains the rest
+ *   of the features API hooks for this module.
+ *
+ *   'default_hook': The defaults hook for your component that is called
+ *   when the cache of default components is generated. Examples include
+ *   hook_views_default_views() or hook_context_default_contexts().
+ *
+ *   'default_file': The file-writing behavior to use when exporting this
+ *   component. May be one of 3 constant values:
+ *
+ *   FEATURES_DEFAULTS_INCLUDED_COMMON: write hooks/components to
+ *   `.features.inc` with other components. This is the default behavior
+ *   if this key is not defined.
+ *
+ *   FEATURES_DEFAULTS_INCLUDED: write hooks/components to a component-
+ *   specific include named automatically by features.
+ *
+ *   FEATURES_DEFAULTS_CUSTOM: write hooks/components to a component-
+ *   specific include with a custom name provided. If your module provides
+ *   large amounts of code that should not be parsed often (only on specific
+ *   cache clears/rebuilds, for example) you should use the 2nd or 3rd
+ *   options to split your component into its own include.
+ *
+ *   'default_filename': The filename to use when 'default_file' is set to
+ *   FEATURES_DEFAULTS_CUSTOM.
+ *
+ *   'feature_source': Boolean value for whether this component should be
+ *   offered as an option on the initial feature creation form.
+ *
+ *   'base': Optional. An alternative base key to use when calling features
+ *   hooks for this component. Can be used for features component types that
+ *   are declared "dynamically" or are part of a family of components.
+ *
+ *   'alter_type': What type of alter hook this hook uses. 'normal' is called
+ *   after the main hook is called. 'inline' is embeded within the default hook
+ *   and may not be implemented by some default hooks.
+ *   'none' is no alter hook exists. Defaults to 'normal'
+ *
+ *   'alter_hook': What the name of the alter hook for this component is.
+ *    Do not include the '_alter' part. Defaults to 'default_hook'.
+ */
+function hook_features_api() {
+  return array(
+    'mycomponent' => array(
+      'default_hook' => 'mycomponent_defaults',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'feature_source' => TRUE,
+      'file' => drupal_get_path('module', 'mycomponent') . '/mycomponent.features.inc',
+    ),
+  );
+}
+
+/**
+ * Component hook. The hook should be implemented using the name of the
+ * component, not the module, eg. [component]_features_export() rather than
+ * [module]_features_export().
+ *
+ * Process the export array for a given component. Implementations of this hook
+ * have three key tasks:
+ *
+ * 1. Determine module dependencies for any of the components passed to it
+ *   e.g. the views implementation iterates over each views' handlers and
+ *   plugins to determine which modules need to be added as dependencies.
+ *
+ * 2. Correctly add components to the export array. In general this is usually
+ *   adding all of the items in $data to $export['features']['my_key'], but
+ *   can become more complicated if components are shared between features
+ *   or modules.
+ *
+ * 3. Delegating further detection and export tasks to related or derivative
+ *   components.
+ *
+ * Each export processor can kickoff further export processors by returning a
+ * keyed array (aka the "pipe") where the key is the next export processor hook
+ * to call and the value is an array to be passed to that processor's $data
+ * argument. This allows an export process to start simply at a few objects:
+ *
+ * [context]
+ *
+ * And then branch out, delegating each component to its appropriate hook:
+ *
+ * [context]--------+------------+
+ *     |            |            |
+ *   [node]      [block]      [views]
+ *     |
+ *   [CCK]
+ *     |
+ * [imagecache]
+ *
+ * @param array $data
+ *   An array of machine names for the component in question to be exported.
+ * @param array &$export
+ *   By reference. An array of all components to be exported with a given
+ *   feature. Component objects that should be exported should be added to
+ *   this array.
+ * @param string $module_name
+ *   The name of the feature module to be generated.
+ * @return array
+ *   The pipe array of further processors that should be called.
+ */
+function hook_features_export($data, &$export, $module_name) {
+  // The following is the simplest implementation of a straight object export
+  // with no further export processors called.
+  foreach ($data as $component) {
+    $export['features']['mycomponent'][$component] = $component;
+  }
+  return array();
+}
+
+/**
+ * Component hook. The hook should be implemented using the name of the
+ * component, not the module, eg. [component]_features_export() rather than
+ * [module]_features_export().
+ *
+ * List all objects for a component that may be exported.
+ *
+ * @return array
+ *   A keyed array of items, suitable for use with a FormAPI select or
+ *   checkboxes element.
+ */
+function hook_features_export_options() {
+  $options = array();
+  foreach (mycomponent_load() as $mycomponent) {
+    $options[$mycomponent->name] = $mycomponent->title;
+  }
+  return $options;
+}
+
+/**
+ * Component hook. The hook should be implemented using the name of the
+ * component, not the module, eg. [component]_features_export() rather than
+ * [module]_features_export().
+ *
+ * Render one or more component objects to code.
+ *
+ * @param string $module_name
+ *   The name of the feature module to be exported.
+ * @param array $data
+ *   An array of machine name identifiers for the objects to be rendered.
+ * @param array $export
+ *   The full export array of the current feature being exported. This is only
+ *   passed when hook_features_export_render() is invoked for an actual feature
+ *   update or recreate, not during state checks or other operations.
+ * @return array
+ *   An associative array of rendered PHP code where the key is the name of the
+ *   hook that should wrap the PHP code. The hook should not include the name
+ *   of the module, e.g. the key for `hook_example` should simply be `example`
+ *   The values in the array can also be in the form of an associative array
+ *   with the required key of 'code' and optional key of 'args', if 'args' need
+ *   to be added to the hook.
+ */
+function hook_features_export_render($module_name, $data, $export = NULL) {
+  $code = array();
+  $code[] = '$mycomponents = array();';
+  foreach ($data as $name) {
+    $code[] = "  \$mycomponents['{$name}'] = " . features_var_export(mycomponent_load($name)) .";";
+  }
+  $code[] = "return \$mycomponents;";
+  $code = implode("\n", $code);
+  return array('mycomponent_defaults' => $code);
+}
+
+/**
+ * Component hook. The hook should be implemented using the name of the
+ * component, not the module, eg. [component]_features_export() rather than
+ * [module]_features_export().
+ *
+ * Revert all component objects for a given feature module.
+ *
+ * @param string $module_name
+ *   The name of the feature module whose components should be reverted.
+ * @return boolean
+ *   TRUE or FALSE for whether the components were successfully reverted.
+ *   NOTE: This return value is no longer used in the latest Features so
+ *   modules should no longer count on this value
+ */
+function hook_features_revert($module_name) {
+  $mycomponents = module_invoke($module_name, 'mycomponent_defaults');
+  if (!empty($mycomponents)) {
+    foreach ($mycomponents as $mycomponent) {
+      mycomponent_delete($mycomponent);
+    }
+  }
+}
+
+/**
+ * Component hook. The hook should be implemented using the name of the
+ * component, not the module, eg. [component]_features_export() rather than
+ * [module]_features_export().
+ *
+ * Rebuild all component objects for a given feature module. Should only be
+ * implemented for 'faux-exportable' components.
+ *
+ * This hook is called at points where Features determines that it is safe
+ * (ie. the feature is in state `FEATURES_REBUILDABLE`) for your module to
+ * replace objects in the database with defaults that you collect from your
+ * own defaults hook. See API.txt for how Features determines whether a
+ * rebuild of components is possible.
+ *
+ * @param string $module_name
+ *   The name of the feature module whose components should be rebuilt.
+ */
+function hook_features_rebuild($module_name) {
+  $mycomponents = module_invoke($module_name, 'mycomponent_defaults');
+  if (!empty($mycomponents)) {
+    foreach ($mycomponents as $mycomponent) {
+      mycomponent_save($mycomponent);
+    }
+  }
+}
+
+/**
+ * Alter the final array of Component names to be exported, just prior to
+ * the rendering of defaults. Allows modules a final say in whether or not
+ * certain Components are exported (the Components' actual data, however,
+ * cannot be altered by this hook).
+ *
+ * @param array &$export
+ *   By reference. An array of all component names to be exported with a given
+ *   feature.
+ * @param array $module_name
+ *   The name of the feature module to be generated.
+ */
+function hook_features_export_alter(&$export, $module_name) {
+  // Example: do not allow the page content type to be exported, ever.
+  if (!empty($export['features']['node']['page'])) {
+    unset($export['features']['node']['page']);
+  }
+}
+
+/**
+ * Alter the pipe array for a given component. This hook should be implemented
+ * with the name of the component type in place of `component` in the function
+ * name, e.g. `features_pipe_views_alter()` will alter the pipe for the Views
+ * component.
+ *
+ * @param array &$pipe
+ *   By reference. The pipe array of further processors that should be called.
+ * @param array $data
+ *   An array of machine names for the component in question to be exported.
+ * @param array &$export
+ *   By reference. An array of all components to be exported with a given
+ *   feature.
+ */
+function hook_features_pipe_COMPONENT_alter(&$pipe, $data, $export) {
+  if (in_array($data, 'my-node-type')) {
+    $pipe['dependencies'][] = 'mymodule';
+  }
+}
+
+/**
+ * Alter the pipe array for a given component.
+ *
+ * @param array &$pipe
+ *   By reference. The pipe array of further processors that should be called.
+ * @param array $data
+ *   An array of machine names for the component in question to be exported.
+ * @param array &$export
+ *   By reference. An array of all components to be exported with a given
+ *   feature.
+ *
+ * The component being exported is contained in $export['component'].
+ * The module being exported contained in $export['module_name'].
+ */
+function hook_features_pipe_alter(&$pipe, $data, $export) {
+  if ($export['component'] == 'node' && in_array($data, 'my-node-type')) {
+    $pipe['dependencies'][] = 'mymodule';
+  }
+}
+
+/**
+ * @defgroup features_component_alter_hooks Feature's component alter hooks
+ * @{
+ * Hooks to modify components defined by other features. These come in the form
+ * hook_COMPONENT_alter where COMPONENT is the default_hook declared by any of
+ * components within features.
+ *
+ * CTools also has a variety of hook_FOO_alters.
+ *
+ * Note: While views is a component of features, it declares it's own alter
+ * function which takes a similar form:
+ * hook_views_default_views_alter(&$views)
+ */
+
+/**
+ * Alter the default fields right before they are cached into the database.
+ *
+ * @param &$fields
+ *   By reference. The fields that have been declared by another feature.
+ */
+function hook_field_default_fields_alter(&$fields) {
+}
+
+/**
+ * Alter the default fieldgroup groups right before they are cached into the
+ * database.
+ *
+ * @param &$groups
+ *   By reference. The fieldgroup groups that have been declared by another
+ *   feature.
+ */
+function hook_fieldgroup_default_groups_alter(&$groups) {
+}
+
+/**
+ * Alter the default filter formats right before they are cached into the
+ * database.
+ *
+ * @param &$formats
+ *   By reference. The formats that have been declared by another feature.
+ */
+function hook_filter_default_formats_alter(&$formats) {
+}
+
+/**
+ * Alter the default menus right before they are cached into the database.
+ *
+ * @param &$menus
+ *   By reference. The menus that have been declared by another feature.
+ */
+function hook_menu_default_menu_custom_alter(&$menus) {
+}
+
+/**
+ * Alter the default menu links right before they are cached into the database.
+ *
+ * @param &$links
+ *   By reference. The menu links that have been declared by another feature.
+ */
+function hook_menu_default_menu_links_alter(&$links) {
+}
+
+/**
+ * Alter the default menu items right before they are cached into the database.
+ *
+ * @param &$items
+ *   By reference. The menu items that have been declared by another feature.
+ */
+function hook_menu_default_items_alter(&$items) {
+}
+
+/**
+ * Alter the default vocabularies right before they are cached into the
+ * database.
+ *
+ * @param &$vocabularies
+ *   By reference. The vocabularies that have been declared by another feature.
+ */
+function hook_taxonomy_default_vocabularies_alter(&$vocabularies) {
+}
+
+/**
+ * Alter the default permissions right before they are cached into the
+ * database.
+ *
+ * @param &$permissions
+ *   By reference. The permissions that have been declared by another feature.
+ */
+function hook_user_default_permissions_alter(&$permissions) {
+}
+
+/**
+ * Alter the default roles right before they are cached into the database.
+ *
+ * @param &$roles
+ *   By reference. The roles that have been declared by another feature.
+ */
+function hook_user_default_roles_alter(&$roles) {
+}
+
+/**
+ * @}
+ */
+
+
+/**
+ * @defgroup features_module_hooks Feature module hooks
+ * @{
+ * Hooks invoked on Feature modules when that module is enabled, disabled,
+ * rebuilt, or reverted. These are ONLY invoked on the Features module on
+ * which these actions are taken.
+ */
+
+/**
+ * Feature module hook. Invoked on a Feature module before that module is
+ * reverted.
+ *
+ * @param $component
+ *   String name of the component that is about to be reverted.
+ */
+function hook_pre_features_revert($component) {
+}
+
+/**
+ * Feature module hook. Invoked on a Feature module after that module is
+ * reverted.
+ *
+ * @param $component
+ *   String name of the component that has just been reverted.
+ */
+function hook_post_features_revert($component) {
+}
+
+/**
+ * Feature module hook. Invoked on a Feature module before that module is
+ * rebuilt.
+ *
+ * @param $component
+ *   String name of the component that is about to be rebuilt.
+ */
+function hook_pre_features_rebuild($component) {
+}
+
+/**
+ * Feature module hook. Invoked on a Feature module after that module is
+ * rebuilt.
+ *
+ * @param $component
+ *   String name of the component that has just been rebuilt.
+ */
+function hook_post_features_rebuild($component) {
+}
+
+/**
+ * Feature module hook. Invoked on a Feature module before that module is
+ * disabled.
+ *
+ * @param $component
+ *   String name of the component that is about to be disabled.
+ */
+function hook_pre_features_disable_feature($component) {
+}
+
+/**
+ * Feature module hook. Invoked on a Feature module after that module is
+ * disabled.
+ *
+ * @param $component
+ *   String name of the component that has just been disabled.
+ */
+function hook_post_features_disable_feature($component) {
+}
+
+/**
+ * Feature module hook. Invoked on a Feature module before that module is
+ * enabled.
+ *
+ * @param $component
+ *   String name of the component that is about to be enabled.
+ */
+function hook_pre_features_enable_feature($component) {
+}
+
+/**
+ * Feature module hook. Invoked on a Feature module after that module is
+ * enabled.
+ *
+ * @param $component
+ *   String name of the component that has just been enabled.
+ */
+function hook_post_features_enable_feature($component) {
+}
+
+/**
+ * @}
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,561 @@
+/**
+ * Features packages.
+ */
+div.features-form-links {
+  width:20%;
+  float:left;
+}
+
+div.features-form-content {
+  width:80%;
+  float:right;
+}
+
+/**
+ * Package links.
+ */
+div.features-form-links ul#features-form-links,
+div.features-form-links ul#features-form-links li,
+div.features-form-links ul#features-form-links li a {
+  display:block;
+  float:none;
+  padding:0px;
+  margin:0px;
+}
+
+div.features-form-links ul#features-form-links {
+  margin:0px 0px 10px;
+}
+
+div.features-form-links ul#features-form-links li a {
+  background:#f8f8f8;
+  padding:5px 5px 4px 4px;
+  border-left:1px solid #eee;
+  border-bottom:1px solid #eee;
+  color: #000;
+  cursor:pointer;
+}
+
+div.features-form-links ul#features-form-links li a.features-package-active {
+  padding:4px 5px 4px 4px;
+  background:#fff;
+  border:1px solid #ccc;
+  border-right:0px;
+  color: #000;
+  margin-right:-1px;
+}
+
+/* Packages */
+div.features-form-package {
+  border:1px solid #ccc;
+  background:#fff;
+  color: #000;
+  padding:10px;
+  margin:0px 0px 20px;
+  display:none;
+}
+
+div.features-package-active {
+  display:block;
+}
+
+/**
+ * Features management form (admin/build/features).
+ */
+div.features-empty {
+  margin:15px 0px;
+  font-size:1.5em;
+  text-align:center;
+  color:#999;
+}
+
+form div.buttons {
+  text-align:center;
+}
+
+table.features .admin-loading,
+table.features tr.disabled {
+  color:#999;
+}
+
+table.features a.configure {
+  float:right;
+  font-style:italic;
+}
+table.features div.feature {
+  float:left; width:85%;
+}
+table.features div.feature strong {
+  font-size:13px;
+}
+table.features div.feature div.description {
+  font-size:11px; margin:0px;
+}
+
+table.features-manage td.name {
+  width:80%;
+}
+table.features-manage td.sign {
+  width:20%;
+}
+
+table.features-admin td.name {
+  width:60%;
+}
+table.features-admin td.sign {
+  width:20%;
+}
+table.features-admin td.state {
+  width:10%;
+}
+table.features-admin td.actions {
+  width:10%;
+}
+
+table.features td.sign {
+  font-size:9px;
+  line-height:15px;
+  white-space:nowrap;
+}
+
+table.features td.sign * {
+  margin:0px;
+}
+
+table.features .admin-check,
+table.features .admin-default,
+table.features .admin-overridden,
+table.features .admin-rebuilding,
+table.features .admin-needs-review {
+  display:none;
+}
+
+/**
+ * Feature export form (admin/build/features/export).
+ */
+form.features-export-form table td {
+  width:50%;
+}
+form.features-export-form table td {
+  vertical-align:top;
+}
+form.features-export-form table div.description {
+  white-space:normal;
+}
+
+table.features-export div.form-item {
+  white-space:normal;
+}
+table.features-export select {
+  width:90%;
+}
+table.features-export td {
+  vertical-align:top;
+}
+
+form.features-export-form div.features-select {
+  display:none;
+}
+
+/*
+form.features-export-form div.form-checkboxes {
+  overflow-x:hidden;
+  overflow-y:auto;
+  height:20em;
+  }
+   */
+
+form.features-export-form div#edit-components-wrapper,
+form.features-export-form div.features-select {
+  padding-right:20px;
+}
+
+/**
+ * Feature component display (admin/build/features/%feature).
+ */
+div.features-components div.column {
+  float:left;
+  width:50%;
+}
+
+div.features-components div.column div.info {
+  padding-right:20px;
+}
+div.features-components div.column div.components {
+  padding-left:20px;
+}
+
+h3.features-download,
+div.features-comparison h3,
+div.features-components h3 {
+  font-size:2em;
+  font-weight:bold;
+  letter-spacing:-1px;
+  margin:15px 0px;
+}
+
+h3.features-download {
+  text-align:center;
+}
+
+div.features-components div.description {
+  font-size:11px;
+  margin:15px 0px;
+}
+
+div.features-components table td {
+  font-size:11px;
+}
+div.features-components table td.component {
+  padding-left:20px;
+}
+
+/**
+ * Features component lists.
+ */
+span.features-component-key {
+  font-size:11px;
+}
+
+a.admin-update,
+a.features-storage,
+span.features-storage,
+span.features-component-list span {
+  white-space:nowrap;
+  margin-right:5px;
+  padding:2px 5px;
+  background:#eee;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+}
+
+div.features-key span.admin-conflict,
+span.features-component-list span.features-conflict {
+  background-color: #c30 !important;
+  color: #fff;
+}
+
+#features-export-wrapper .features-conflict,
+#features-export-wrapper .features-conflict label.option{
+  color: #c30 !important;
+  font-weight: bold !important;
+}
+
+div.conflicts span.admin-disabled {
+  color: #955;
+}
+
+a.admin-update {
+  background:transparent;
+}
+
+/* These pseudo selectors are necessary for themes like Garland. */
+a.admin-overridden:link,
+a.admin-overridden:visited,
+span.admin-overridden {
+  color:#fff;
+  background:#666;
+}
+
+a.admin-needs-review:link,
+a.admin-needs-review:visited,
+span.admin-needs-review {
+  color:#963;
+  background:#fe6;
+}
+
+a.admin-rebuilding:link,
+a.admin-rebuilding:visited,
+span.admin-rebuilding {
+  color:#fff;
+  background:#699;
+}
+
+a.admin-conflict:link,
+a.admin-conflict:visited,
+span.admin-conflict {
+  color:#c30;
+}
+
+table.features-diff td.diff-addedline,
+span.features-component-list .features-detected {
+  color:#68a;
+  background:#def;
+}
+
+table.features-diff td.diff-deletedline,
+span.features-component-list .features-dependency {
+  color:#999;
+  background:#f8f8f8;
+}
+
+/**
+ * Features diff.
+ */
+table.features-diff {
+  font-size:11px;
+}
+
+table.features-diff td {
+  padding:0px 5px;
+}
+
+table.features-diff td.diff-deletedline,
+table.features-diff td.diff-addedline,
+table.features-diff td.diff-context {
+  width:50%;
+  font-family:'Andale Mono',monospace;
+}
+
+/**
+ * New UI component export list
+ */
+#features-export-wrapper div.features-export-parent {
+  clear: both;
+}
+#features-export-form .fieldset-content.fieldset-wrapper {
+  padding-top: 5px;
+}
+html.js #features-export-form fieldset.collapsed {
+  min-height: 2em;
+  margin-bottom: 0;
+  top: 0;
+  padding: 0 0 0 0;
+}
+fieldset.features-export-component  {
+  background: #F3F8FB;
+  margin: 0.5em 0;
+  font-weight: normal;
+  font-size: 12px;
+  top: 0;
+}
+fieldset.features-export-component.collapsed  {
+  background: #F3F8FB;
+}
+fieldset.features-export-component legend {
+  top: 0;
+}
+fieldset.features-export-component.collapsed .fieldset-wrapper {
+  margin: 0;
+  padding: 0 13px 6px 15px;
+}
+fieldset.features-export-component .fieldset-legend {
+  white-space: nowrap;
+}
+fieldset.features-export-component .fieldset-title span {
+  font-size: 11px;
+  text-transform: none;
+  font-weight: normal;
+}
+#features-export-wrapper .fieldset-wrapper  {
+  font-size: 12px;
+}
+div.features-export-list  {
+  font-weight: normal;
+  font-size: 12px;
+  border: 1px solid #CCC;
+  border-top-width: 0;
+  overflow: hidden;
+}
+#features-export-form .fieldset-description {
+  margin: 5px 0;
+  line-height: 1.231em;
+  font-size: 0.923em;
+  color: #666;
+}
+div.features-export-empty {
+  display: none;
+}
+fieldset.features-export-component .fieldset-wrapper .form-checkboxes {
+  max-height: 20em;
+  overflow: auto;
+  min-width: 100px;
+}
+
+#features-export-wrapper .component-select .form-type-checkbox {
+  overflow: hidden;
+  padding: 0 0 0 2px;
+}
+
+#features-export-wrapper .component-added .form-type-checkbox,
+#features-export-wrapper .component-detected .form-type-checkbox,
+#features-export-wrapper .component-included .form-type-checkbox {
+  float: left;
+  white-space: normal;
+  margin: 2px 5px;
+  padding: 0 5px;
+  background: transparent;
+}
+
+#features-export-wrapper .component-added .form-type-checkbox {
+  font-weight: bold;
+  background: #EEE;
+  -moz-border-radius: 5px;
+  -webkit-border-radius: 5px;
+}
+#features-export-wrapper div.component-added label.option {
+  font-weight: bold;
+}
+#features-export-wrapper .component-detected .form-type-checkbox {
+  font-style: italic;
+  color:#68a;
+  background:#def;
+  -moz-border-radius: 5px;
+  -webkit-border-radius: 5px;
+}
+
+#features-export-info {
+  width: 49%;
+  float: left;
+  position: relative;
+}
+#features-export-wrapper {
+  width: 49%;
+  float: right;
+  clear: both;
+  position: relative;
+}
+#features-export-advanced {
+  width: 49%;
+  float: left;
+  clear: left;
+  margin-top: 0.5em;
+  position: relative;
+}
+#features-export-buttons {
+  width: 49%;
+  float: left;
+  margin-top: 0.5em;
+  position: relative;
+  text-align: center;
+}
+#features-export-buttons input {
+  margin: 0 3px;
+}
+
+#features-export-wrapper .component-added label a,
+#features-export-wrapper .component-detected label a,
+#features-export-wrapper .component-included label a {
+  display: inline;
+  float: none;
+}
+#features-export-wrapper label.component-added {
+  font-weight: bold;
+}
+#features-export-form input[size="60"].form-text {
+  width: 100%;
+}
+input.form-submit.features-refresh-button {
+  font-size: 0.7em;
+  -moz-border-radius: 5px;
+  -webkit-border-radius: 5px;
+  border-radius: 5px;
+  background-color: transparent;
+  margin-left: 1em;
+}
+.features-refresh-wrapper .ajax-progress {
+  font-size: 10px;
+  width: 10em;
+}
+#features-export-advanced .ajax-progress {
+  font-size: 10px;
+  width: 10em;
+}
+#features-export-wrapper div.fieldset-description,
+#features-export-wrapper div.description {
+  clear: both;
+}
+#features-filter input[size="60"].form-text {
+  width: 200px;
+}
+#features-filter .fieldset-content,
+#features-filter .fieldset-wrapper,
+#features-filter fieldset {
+  border: 0;
+  padding: 0;
+  margin: 0;
+}
+#features-filter fieldset legend {
+  display: none;
+}
+#features-filter label,
+#features-filter input {
+  display: inline;
+  width: auto;
+}
+#features-filter .form-item {
+  float: left;
+  margin: 5px 0;
+  padding: 0;
+}
+#features-filter .form-item.form-type-checkbox {
+  margin: 5px 0;
+}
+#features-filter span {
+  float: left;
+  white-space: normal;
+  margin: 5px 5px;
+  padding: 0 5px;
+  background: transparent;
+  background: #EEE;
+  -moz-border-radius: 5px;
+  -webkit-border-radius: 5px;
+  cursor: pointer;
+}
+#features-filter span:hover {
+  background:#def;
+}
+#features-autodetect .form-item {
+  float: left;
+  margin: 0 0;
+  padding: 0;
+}
+#features-autodetect .fieldset-content,
+#features-autodetect .fieldset-wrapper,
+#features-autodetect fieldset {
+  border: 0;
+  padding: 0;
+  margin: 1em 0 0 0;
+  top: 0;
+}
+#features-autodetect fieldset legend {
+  display: none;
+}
+#features-export-advanced .form-item.form-item-generate-path {
+  margin-bottom: 0;
+}
+#features-info-file .form-textarea-wrapper,
+#features-info-file textarea {
+  height: 100%;
+}
+
+#features-info-file .form-type-textarea {
+  height: 100%;
+  margin: 0;
+}
+#edit-info-preview {
+  margin: 1em 0;
+}
+#features-legend .fieldset-wrapper span {
+  font-style: normal;
+  color: black;
+  display: inline-block;
+  background: transparent;
+  border: 1px solid #DDD;
+  -moz-border-radius: 5px;
+  -webkit-border-radius: 5px;
+  white-space: nowrap;
+  padding: 0 8px;
+  margin: 0 10px 0 0;
+}
+#features-legend .fieldset-wrapper .component-detected {
+  font-style: italic;
+  color:#68a;
+  background:#def;
+  border-width: 0;
+}
+#features-legend .fieldset-wrapper .component-added {
+  font-weight: bold;
+  background: #EEE;
+  border-width: 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.drush.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,870 @@
+<?php
+
+/**
+ * @file
+ * Features module drush integration.
+ */
+
+/**
+ * Implements hook_drush_command().
+ *
+ * @return
+ *   An associative array describing your command(s).
+ *
+ * @see drush_parse_command()
+ */
+function features_drush_command() {
+  $items = array();
+
+  $items['features-list'] = array(
+    'description' => "List all the available features for your site.",
+    'options' => array(
+      'status' => "Feature status, can be 'enabled', 'disabled'  or 'all'",
+    ),
+    'drupal dependencies' => array('features'),
+    'aliases' => array('fl', 'features'),
+  );
+  $items['features-export'] = array(
+    'description' => "Export a feature from your site into a module.",
+    'arguments' => array(
+      'feature' => 'Feature name to export.',
+      'components' => 'Patterns of components to include, see features-components for the format of patterns.'
+    ),
+    'options' => array(
+      'destination' => "Destination path (from Drupal root) of the exported feature. Defaults to 'sites/all/modules/features'",
+      'version-set' => "Specify a version number for the feature.",
+      'version-increment' => "Increment the feature's version number.",
+    ),
+    'drupal dependencies' => array('features'),
+    'aliases' => array('fe'),
+  );
+  $items['features-add'] = array(
+    'description' => "Add a component to a feature module. (DEPRECATED: use features-export)",
+    'arguments' => array(
+      'feature' => 'Feature name to add to.',
+      'components' => 'List of components to add.',
+    ),
+    'options' => array(
+      'version-set' => "Specify a version number for the feature.",
+      'version-increment' => "Increment the feature's version number.",
+    ),
+    'drupal dependencies' => array('features'),
+    'aliases' => array('fa'),
+  );
+  $items['features-components'] = array(
+    'description' => 'List features components.',
+    'arguments' => array(
+      'patterns' => 'The features components type to list. Omit this argument to list all components.',
+    ),
+    'options' => array(
+      'exported' => array(
+        'description' => 'Show only components that have been exported.',
+      ),
+      'not-exported' => array(
+        'description' => 'Show only components that have not been exported.',
+      ),
+    ),
+    'aliases' => array('fc'),
+  );
+  $items['features-update'] = array(
+    'description' => "Update a feature module on your site.",
+    'arguments' => array(
+      'feature' => 'A space delimited list of features.',
+    ),
+    'options' => array(
+      'version-set' => "Specify a version number for the feature.",
+      'version-increment' => "Increment the feature's version number.",
+    ),
+    'drupal dependencies' => array('features'),
+    'aliases' => array('fu'),
+  );
+  $items['features-update-all'] = array(
+    'description' => "Update all feature modules on your site.",
+    'arguments' => array(
+      'feature_exclude' => 'A space-delimited list of features to exclude from being updated.',
+    ),
+    'drupal dependencies' => array('features'),
+    'aliases' => array('fu-all', 'fua'),
+  );
+  $items['features-revert'] = array(
+    'description' => "Revert a feature module on your site.",
+    'arguments' => array(
+      'feature' => 'A space delimited list of features or feature.component pairs.',
+    ),
+    'options' => array(
+      'force' => "Force revert even if Features assumes components' state are default.",
+    ),
+    'examples' => array(
+      'drush fr foo.node foo.taxonomy bar' => 'Revert node and taxonomy components of feature "foo", but only if they are overriden. Revert all overriden components of feature "bar".',
+      'drush fr foo.node foo.taxonomy bar --force' => 'Revert node and taxonomy components of feature "foo". Revert all components of feature "bar".',
+    ),
+    'drupal dependencies' => array('features'),
+    'aliases' => array('fr'),
+  );
+  $items['features-revert-all'] = array(
+    'description' => "Revert all enabled feature module on your site.",
+    'arguments' => array(
+      'feature_exclude' => 'A space-delimited list of features to exclude from being reverted.',
+    ),
+    'options' => array(
+      'force' => "Force revert even if Features assumes components' state are default.",
+    ),
+    'drupal dependencies' => array('features'),
+    'aliases' => array('fr-all', 'fra'),
+  );
+  $items['features-diff'] = array(
+    'description' => "Show the difference between the default and overridden state of a feature.",
+    'arguments' => array(
+      'feature' => 'The feature in question.',
+    ),
+    'options' => array(
+      'lines' => 'Generate diffs with <n> lines of context instead of the usual two.',
+    ),
+    'drupal dependencies' => array('features', 'diff'),
+    'aliases' => array('fd'),
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_drush_help().
+ */
+function features_drush_help($section) {
+  switch ($section) {
+    case 'drush:features':
+      return dt("List all the available features for your site.");
+    case 'drush:features-export':
+      return dt("Export a feature from your site into a module. If called with no arguments, display a list of available components. If called with a single argument, attempt to create a feature including the given component with the same name. The option '--destination=foo' may be used to specify the path (from Drupal root) where the feature should be created. The default destination is 'sites/all/modules/features'. The option '--version-set=foo' may be used to specify a version number for the feature or the option '--version-increment' may also to increment the feature's version number.");
+    case 'drush:features-components':
+      return dt("List feature components matching patterns. The listing may be limited to exported/not-exported components.
+
+A component pattern consists of a source, a colon and a component. Both source and component may be a full name (as in \"dependencies\"), a shorthand (for instance \"dep\") or a pattern (like \"%denci%\").
+
+Shorthands are unique shortenings of a name. They will only match if exactly one option contains the shorthand. So in a standard installation, \"dep\" will work for dependencies, but \"user\" wont, as it matches both user_permission and user_role.
+
+Patterns uses * or % for matching multiple sources/components. Unlike shorthands, patterns must match the whole name, so \"field:%article%\" should be used to select all fields containing \"article\" (which could both be those on the node type article, as well as those fields named article). * and % are equivalent, but the latter doesn't have to be escaped in UNIX shells.
+
+Lastly, a pattern without a colon is interpreted as having \":%\" appended, for easy listing of all components of a source.
+");
+    case 'drush:features-update':
+      return dt("Update a feature module on your site. The option '--version-set=foo' may be used to specify a version number for the feature or the option '--version-increment' may also to increment the feature's version number.");
+    case 'drush:features-update-all':
+      return dt("Update all feature modules on your site.");
+    case 'drush:features-revert':
+      return dt("Revert a feature module on your site.");
+    case 'drush:features-revert-all':
+      return dt("Revert all enabled feature module on your site.");
+    case 'drush:features-diff':
+      return dt("Show a diff of a feature module.");
+    case 'drush:features-add':
+      return dt("Add a component to a feature module. The option '--version-set=foo' may be used to specify a version number for the feature or the option '--version-increment' may also to increment the feature's version number.");
+  }
+}
+
+/**
+ * Get a list of all feature modules.
+ */
+function drush_features_list() {
+  $status = drush_get_option('status') ? drush_get_option('status') : 'all';
+  if (!in_array($status, array('enabled', 'disabled', 'all'))) {
+    return drush_set_error('', dt('!status is not valid', array('!status' => $status)));
+  }
+
+  module_load_include('inc', 'features', 'features.export');
+  $rows = array(array(dt('Name'), dt('Feature'), dt('Status'), dt('Version'), dt('State')));
+
+  // Sort the Features list before compiling the output.
+  $features = features_get_features(NULL, TRUE);
+  ksort($features);
+
+  foreach ($features as $k => $m) {
+    switch (features_get_storage($m->name)) {
+      case FEATURES_DEFAULT:
+      case FEATURES_REBUILDABLE:
+        $storage = '';
+        break;
+      case FEATURES_OVERRIDDEN:
+        $storage = dt('Overridden');
+        break;
+      case FEATURES_NEEDS_REVIEW:
+        $storage = dt('Needs review');
+        break;
+    }
+    if (
+      ($m->status == 0 && ($status == 'all' || $status == 'disabled')) ||
+      ($m->status == 1 && ($status == 'all' || $status == 'enabled'))
+    ) {
+      $rows[] = array(
+        $m->info['name'],
+        $m->name,
+        $m->status ? dt('Enabled') : dt('Disabled'),
+        $m->info['version'],
+        $storage
+      );
+    }
+  }
+  drush_print_table($rows, TRUE);
+}
+
+/**
+ * List components, with pattern matching.
+ */
+function drush_features_components() {
+  $args = func_get_args();
+  $components = _drush_features_component_list();
+  // If no args supplied, prompt with a list.
+  if (empty($args)) {
+    $types = array_keys($components);
+    array_unshift($types, 'all');
+    $choice = drush_choice($types, 'Enter a number to choose which component type to list.');
+    if ($choice === FALSE) {
+      return;
+    }
+
+    $args = ($choice == 0) ? array('*') : array($types[$choice]);
+  }
+  $options = array(
+    'provided by' => TRUE,
+  );
+  if (drush_get_option(array('exported', 'e'), NULL)) {
+    $options['not exported'] = FALSE;
+  }
+  elseif (drush_get_option(array('not-exported', 'o'), NULL)) {
+    $options['exported'] = FALSE;
+  }
+
+  $filtered_components = _drush_features_component_filter($components, $args, $options);
+  if ($filtered_components){
+    _drush_features_component_print($filtered_components);
+  }
+}
+
+/**
+ * Returns a listing of all known components, indexed by source.
+ */
+function _drush_features_component_list() {
+  $components = array();
+  foreach (features_get_feature_components() as $source => $info) {
+    if ($options = features_invoke($source, 'features_export_options')) {
+      foreach ($options as $name => $title) {
+        $components[$source][$name] = $title;
+      }
+    }
+  }
+  return $components;
+}
+
+/**
+ * Filters components by patterns.
+ */
+function _drush_features_component_filter($all_components, $patterns = array(), $options = array()) {
+  $options += array(
+    'exported' => TRUE,
+    'not exported' => TRUE,
+    'provided by' => FALSE,
+  );
+  $pool = array();
+  // Maps exported components to feature modules.
+  $components_map = features_get_component_map();
+  // First filter on exported state.
+  foreach ($all_components as $source => $components) {
+    foreach ($components as $name => $title) {
+      $exported = sizeof($components_map[$source][$name]) > 0;
+      if ($exported) {
+        if ($options['exported']) {
+          $pool[$source][$name] = $title;
+        }
+      }
+      else {
+        if ($options['not exported']) {
+          $pool[$source][$name] = $title;
+        }
+      }
+    }
+  }
+
+  $state_string = '';
+
+  if (!$options['exported']) {
+    $state_string = 'unexported';
+  }
+  elseif (!$options['not exported']) {
+    $state_string = 'exported';
+  }
+
+  $selected = array();
+  foreach ($patterns as $pattern) {
+    // Rewrite * to %. Let users use both as wildcard.
+    $pattern = strtr($pattern, array('*' => '%'));
+    $sources = array();
+    list($source_pattern, $component_pattern) = explode(':', $pattern, 2);
+    // If source is empty, use a pattern.
+    if ($source_pattern == '') {
+      $source_pattern = '%';
+    }
+    if ($component_pattern == '') {
+      $component_pattern = '%';
+    }
+
+    $preg_source_pattern = strtr(preg_quote($source_pattern, '/'), array('%' => '.*'));
+    $preg_component_pattern = strtr(preg_quote($component_pattern, '/'), array('%' => '.*'));
+    /*
+     * If it isn't a pattern, but a simple string, we don't anchor the
+     * pattern, this allows for abbreviating. Else, we do, as this seems more
+     * natural for patterns.
+     */
+    if (strpos($source_pattern, '%') !== FALSE) {
+      $preg_source_pattern = '^' . $preg_source_pattern . '$';
+    }
+    if (strpos($component_pattern, '%') !== FALSE) {
+      $preg_component_pattern = '^' . $preg_component_pattern . '$';
+    }
+    $matches = array();
+
+    // Find the sources.
+    $all_sources = array_keys($pool);
+    $matches = preg_grep('/' . $preg_source_pattern . '/', $all_sources);
+    if (sizeof($matches) > 0) {
+      // If we have multiple matches and the source string wasn't a
+      // pattern, check if one of the matches is equal to the pattern, and
+      // use that, or error out.
+      if (sizeof($matches) > 1 and $preg_source_pattern[0] != '^') {
+        if (in_array($source_pattern, $matches)) {
+          $matches = array($source_pattern);
+        }
+        else {
+          return drush_set_error('', dt('Ambiguous source "!source", matches !matches', array('!source' => $source_pattern, '!matches' => join(', ', $matches))));
+        }
+      }
+      // Loose the indexes preg_grep preserved.
+      $sources = array_values($matches);
+    }
+    else {
+      return drush_set_error('', dt('No !state sources match "!source"', array('!state' => $state_string, '!source' => $source_pattern)));
+    }
+
+
+    // Now find the components.
+    foreach ($sources as $source) {
+      // Find the components.
+      $all_components = array_keys($pool[$source]);
+      // See if there's any matches.
+      $matches = preg_grep('/' . $preg_component_pattern . '/', $all_components);
+      if (sizeof($matches) > 0) {
+        // If we have multiple matches and the components string wasn't a
+        // pattern, check if one of the matches is equal to the pattern, and
+        // use that, or error out.
+        if (sizeof($matches) > 1 and $preg_component_pattern[0] != '^') {
+          if (in_array($component_pattern, $matches)) {
+            $matches = array($component_pattern);
+          }
+          else {
+            return drush_set_error('', dt('Ambiguous component "!component", matches !matches', array('!component' => $component_pattern, '!matches' => join(', ', $matches))));
+          }
+        }
+        if (!is_array($selected[$source])) {
+          $selected[$source] = array();
+        }
+        $selected[$source] += array_intersect_key($pool[$source], array_flip($matches));
+      }
+      else {
+        // No matches. If the source was a pattern, just carry on, else
+        // error out. Allows for patterns like :*field*
+        if ($preg_source_pattern[0] != '^') {
+          return drush_set_error('', dt('No !state !source components match "!component"', array('!state' => $state_string, '!component' => $component_pattern, '!source' => $source)));
+        }
+      }
+    }
+  }
+
+  // Lastly, provide feature module information on the selected components, if
+  // requested.
+  $provided_by = array();
+  if ($options['provided by'] && $options['exported'] ) {
+    foreach ($selected as $source => $components) {
+      foreach ($components as $name => $title) {
+        $exported = sizeof($components_map[$source][$name]) > 0;
+        if ($exported) {
+          $provided_by[$source . ':' . $name] = join(', ', $components_map[$source][$name]);
+        }
+      }
+    }
+  }
+
+  return array(
+    'components' => $selected,
+    'sources' => $provided_by,
+  );
+}
+
+/**
+ * Prints a list of filtered components.
+ */
+function _drush_features_component_print($filtered_components) {
+  $rows = array(array(dt('Available sources')));
+  foreach ($filtered_components['components'] as $source => $components) {
+    foreach ($components as $name => $value) {
+      $row = array($source .':'. $name);
+      if (isset($filtered_components['sources'][$source .':'. $name])) {
+        $row[] = dt('Provided by') . ': ' . $filtered_components['sources'][$source .':'. $name];
+      }
+      $rows[] = $row;
+    }
+  }
+
+  drush_print_table($rows, TRUE);
+}
+
+/**
+ * Add a component to a features module, or create a new module with
+ * the selected components.
+ */
+function drush_features_export() {
+  if ($args = func_get_args()) {
+    $module = array_shift($args);
+    if (empty($args)) {
+      return drush_set_error('', 'No components supplied.');
+    }
+    $components = _drush_features_component_list();
+    $options = array(
+      'exported' => FALSE,
+    );
+
+    $filtered_components = _drush_features_component_filter($components, $args, $options);
+    $items = $filtered_components['components'];
+
+    if (empty($items)) {
+      return drush_set_error('', 'No components to add.');
+    }
+
+    $items = array_map('array_keys', $items);
+
+    if (($feature = features_load_feature($module, TRUE)) && module_exists($module)) {
+      module_load_include('inc', 'features', 'features.export');
+      _features_populate($items, $feature->info, $feature->name);
+      _drush_features_export($feature->info, $feature->name, dirname($feature->filename));
+    }
+    elseif ($feature) {
+      _features_drush_set_error($module, 'FEATURES_FEATURE_NOT_ENABLED');
+    }
+    else {
+      // Same logic as in _drush_features_export. Should be refactored.
+      $destination = drush_get_option(array('destination'), 'sites/all/modules/features');
+      $directory = isset($directory) ? $directory : $destination . '/' . $module;
+      drush_print(dt('Will create a new module in !dir', array('!dir' => $directory)));
+      if (!drush_confirm(dt('Do you really want to continue?'))) {
+        drush_die('Aborting.');
+      }
+      $export = _drush_features_generate_export($items, $module);
+      _features_populate($items, $export[info], $export[name]);
+      _drush_features_export($export['info'], $module, $directory);
+    }
+  }
+  else {
+    return drush_set_error('', 'No feature name given.');
+  }
+}
+
+/**
+ * Add a component to a features module
+ * the selected components.
+ *
+ * This is DEPRECATED, but keeping it around for a bit longer for user migration
+ */
+function drush_features_add() {
+  drush_print(dt('features-add is DEPRECATED.'));
+  drush_print(dt('Calling features-export instead.'));
+  drush_features_export();
+}
+
+
+/**
+ * Update an existing feature module.
+ */
+function drush_features_update() {
+  if ($args = func_get_args()) {
+    foreach ($args as $module) {
+      if (($feature = features_load_feature($module, TRUE)) && module_exists($module)) {
+        _drush_features_export($feature->info, $feature->name, dirname($feature->filename));
+      }
+      else if ($feature) {
+        _features_drush_set_error($module, 'FEATURES_FEATURE_NOT_ENABLED');
+      }
+      else {
+        _features_drush_set_error($module);
+      }
+    }
+  }
+  else {
+    // By default just show contexts that are available.
+    $rows = array(array(dt('Available features')));
+    foreach (features_get_features(NULL, TRUE) as $name => $info) {
+      $rows[] = array($name);
+    }
+    drush_print_table($rows, TRUE);
+  }
+}
+
+/**
+ * Update all enabled features. Optionally pass in a list of features to
+ * exclude from being updated.
+ */
+function drush_features_update_all() {
+  $features_to_update = array();
+  $features_to_exclude = func_get_args();
+  foreach (features_get_features() as $module) {
+    if ($module->status && !in_array($module->name, $features_to_exclude)) {
+      $features_to_update[] = $module->name;
+    }
+  }
+  drush_print(dt('The following modules will be updated: !modules', array('!modules' => implode(', ', $features_to_update))));
+  if (drush_confirm(dt('Do you really want to continue?'))) {
+    foreach ($features_to_update as $module_name) {
+      drush_invoke_process(drush_sitealias_get_record('@self'), 'features-update', array($module_name));
+    }
+  }
+  else {
+    drush_die('Aborting.');
+  }
+}
+
+/**
+ * Write a module to the site dir.
+ *
+ * @param $info
+ *   The feature info associative array.
+ * @param $module_name
+ *  Optional. The name for the exported module.
+ */
+function _drush_features_export($info, $module_name = NULL, $directory = NULL) {
+  $root = drush_get_option(array('r', 'root'), drush_locate_root());
+  if ($root) {
+    $destination = drush_get_option(array('destination'), 'sites/all/modules/features');
+    $directory = isset($directory) ? $directory : $destination . '/' . $module_name;
+    if (is_dir($directory)) {
+      drush_print(dt('Module appears to already exist in !dir', array('!dir' => $directory)));
+      if (!drush_confirm(dt('Do you really want to continue?'))) {
+        drush_die('Aborting.');
+      }
+    }
+    else {
+      drush_op('mkdir', $directory);
+    }
+    if (is_dir($directory)) {
+      drupal_flush_all_caches();
+      $export = _drush_features_generate_export($info, $module_name);
+      $files = features_export_render($export, $module_name, TRUE);
+      foreach ($files as $extension => $file_contents) {
+        if (!in_array($extension, array('module', 'info'))) {
+          $extension .= '.inc';
+        }
+        drush_op('file_put_contents', "{$directory}/{$module_name}.$extension", $file_contents);
+      }
+      drush_log(dt("Created module: !module in !directory", array('!module' => $module_name, '!directory' => $directory)), 'ok');
+    }
+    else {
+      drush_die(dt('Couldn\'t create directory !directory', array('!directory' => $directory)));
+    }
+  }
+  else {
+    drush_die(dt('Couldn\'t locate site root'));
+  }
+}
+
+/**
+ * Helper function for _drush_feature_export.
+ *
+ * @param $info
+ *   The feature info associative array.
+ * @param $module_name
+ *  Optional. The name for the exported module.
+ */
+function _drush_features_generate_export(&$info, &$module_name) {
+  module_load_include('inc', 'features', 'features.export');
+  $export = features_populate($info, $module_name);
+  if (!features_load_feature($module_name)) {
+    $export['name'] = $module_name;
+  }
+  // Set the feature version if the --version-set or --version-increment option is passed.
+  if ($version = drush_get_option(array('version-set'))) {
+    preg_match('/^(?P<core>\d+\.x)-(?P<major>\d+)\.(?P<patch>\d+)-?(?P<extra>\w+)?$/', $version, $matches);
+    if (!isset($matches['core'], $matches['major'])) {
+      drush_die(dt('Please enter a valid version with core and major version number. Example: !example', array('!example' => '7.x-1.0')));
+    }
+    $export['version'] = $version;
+  }
+  else if ($version = drush_get_option(array('version-increment'))) {
+    // Determine current version and increment it.
+    $export_load = features_export_prepare($export, $module_name);
+    $version = $export_load['version'];
+    $version_explode = explode('.', $version);
+    $version_minor = array_pop($version_explode);
+    // Increment minor version number if numeric or not a dev release.
+    if (is_numeric($version_minor) || strpos($version_minor, 'dev') !== (strlen($version_minor) - 3)) {
+      // Check for prefixed versions (alpha, beta, rc).
+      if (ctype_digit($version_minor)) {
+        ++$version_minor;
+      }
+      else {
+        // Split version number parts.
+        $pattern = '/([0-9]-[a-z]+([0-9])+)/';
+        $matches = array();
+        preg_match($pattern, $version_minor, $matches);
+        $number = array_pop($matches);
+        ++$number;
+        $pattern = '/[0-9]+$/';
+        $version_minor = preg_replace($pattern, $number, $version_minor);
+      }
+    }
+    array_push($version_explode, $version_minor);
+    // Rebuild version string.
+    $version = implode('.', $version_explode);
+    $export['version'] = $version;
+  }
+  return $export;
+}
+
+/**
+ * Revert a feature to it's code definition.
+ * Optionally accept a list of components to revert.
+ */
+function drush_features_revert() {
+  if ($args = func_get_args()) {
+    module_load_include('inc', 'features', 'features.export');
+    features_include();
+
+    // Determine if revert should be forced.
+    $force = drush_get_option('force');
+
+    // Parse list of arguments.
+    $modules = array();
+    foreach ($args as $arg) {
+      $arg = explode('.', $arg);
+      $module = array_shift($arg);
+      $component = array_shift($arg);
+
+      if (isset($module)) {
+        if (empty($component)) {
+          // If we received just a feature name, this means that we need all of it's components.
+          $modules[$module] = TRUE;
+        }
+        elseif ($modules[$module] !== TRUE) {
+          if (!isset($modules[$module])) {
+            $modules[$module] = array();
+          }
+          $modules[$module][] = $component;
+        }
+      }
+    }
+
+    // Process modules.
+    foreach ($modules as $module => $components_needed) {
+      if (($feature = features_load_feature($module, TRUE)) && module_exists($module)) {
+
+        $components = array();
+        // Forcefully revert all components of a feature.
+        if ($force) {
+          foreach (array_keys($feature->info['features']) as $component) {
+            if (features_hook($component, 'features_revert')) {
+              $components[] = $component;
+            }
+          }
+        }
+        // Only revert components that are detected to be Overridden/Needs review/rebuildable.
+        else {
+          $states = features_get_component_states(array($feature->name), FALSE);
+          foreach ($states[$feature->name] as $component => $state) {
+            if (in_array($state, array(FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW, FEATURES_REBUILDABLE)) && features_hook($component, 'features_revert')) {
+              $components[] = $component;
+            }
+          }
+        }
+
+        if (!empty($components_needed) && is_array($components_needed)) {
+          $components = array_intersect($components, $components_needed);
+        }
+        if (empty($components)) {
+          drush_log(dt('Current state already matches defaults, aborting.'), 'ok');
+        }
+        else {
+          foreach ($components as $component) {
+            if (drush_confirm(dt('Do you really want to revert @component?', array('@component' => $component)))) {
+              features_revert(array($module => array($component)));
+              drush_log(dt('Reverted @component.', array('@component' => $component)), 'ok');
+            }
+            else {
+              drush_log(dt('Skipping @component.', array('@component' => $component)), 'ok');
+            }
+          }
+        }
+      }
+      else if ($feature) {
+        _features_drush_set_error($module, 'FEATURES_FEATURE_NOT_ENABLED');
+      }
+      else {
+        _features_drush_set_error($module);
+      }
+    }
+  }
+  else {
+    drush_features_list();
+    return;
+  }
+}
+
+/**
+ * Revert all enabled features to their definitions in code.
+ *
+ * @param ...
+ *   (Optional) A list of features to exclude from being reverted.
+ */
+function drush_features_revert_all() {
+  module_load_include('inc', 'features', 'features.export');
+  $force = drush_get_option('force');
+  $features_to_exclude = func_get_args();
+
+  $features_to_revert = array();
+  foreach (features_get_features(NULL, TRUE) as $module) {
+    if ($module->status && !in_array($module->name, $features_to_exclude)) {
+      // If forced, add module regardless of status.
+      if ($force) {
+        $features_to_revert[] = $module->name;
+      }
+      else {
+        switch (features_get_storage($module->name)) {
+          case FEATURES_OVERRIDDEN:
+          case FEATURES_NEEDS_REVIEW:
+          case FEATURES_REBUILDABLE:
+            $features_to_revert[] = $module->name;
+            break;
+        }
+      }
+    }
+  }
+
+  if ($features_to_revert) {
+    drush_print(dt('The following modules will be reverted: !modules', array('!modules' => implode(', ', $features_to_revert))));
+    if (drush_confirm(dt('Do you really want to continue?'))) {
+      foreach ($features_to_revert as $module) {
+        drush_invoke_process(drush_sitealias_get_record('@self'), 'features-revert', array($module), array('force' => $force, '#integrate' => TRUE));
+      }
+    }
+    else {
+      return drush_user_abort('Aborting.');
+    }
+  }
+  else {
+    drush_log(dt('Current state already matches defaults, aborting.'), 'ok');
+  }
+}
+
+/**
+ * Show the diff of a feature module.
+ */
+function drush_features_diff() {
+  if (!$args = func_get_args()) {
+    drush_features_list();
+    return;
+  }
+  $module = $args[0];
+  $feature = features_load_feature($module);
+  if (!module_exists($module)) {
+    drush_log(dt('No such feature is enabled: ' . $module), 'error');
+    return;
+  }
+  module_load_include('inc', 'features', 'features.export');
+  $overrides = features_detect_overrides($feature);
+  if (empty($overrides)) {
+    drush_log(dt('Feature is in its default state. No diff needed.'), 'ok');
+    return;
+  }
+  module_load_include('inc', 'diff', 'diff.engine');
+
+  if (!class_exists('DiffFormatter')) {
+    if (drush_confirm(dt('It seems that the Diff module is not available. Would you like to download and enable it?'))) {
+      // Download it if it's not already here.
+      $project_info = drush_get_projects();
+      if (empty($project_info['diff']) && !drush_invoke_process(drush_sitealias_get_record('@self'), 'dl', array('diff'), array('#integrate' => TRUE))) {
+        return drush_set_error(dt('Diff module could not be downloaded.'));
+      }
+
+      if (!drush_invoke_process(drush_sitealias_get_record('@self'), 'en', array('diff'), array('#integrate' => TRUE))) {
+        return drush_set_error(dt('Diff module could not be enabled.'));
+      }
+    }
+    else {
+      return drush_set_error(dt('Diff module is not enabled.'));
+    }
+    // If we're still here, now we can include the diff.engine again.
+    module_load_include('inc', 'diff', 'diff.engine');
+  }
+
+  $lines = (int) drush_get_option('lines');
+  $lines = $lines > 0 ? $lines : 2;
+
+  $formatter = new DiffFormatter();
+  $formatter->leading_context_lines = $lines;
+  $formatter->trailing_context_lines = $lines;
+  $formatter->show_header = FALSE;
+
+  if (drush_get_context('DRUSH_NOCOLOR')) {
+    $red = $green = "%s";
+  }
+  else {
+    $red = "\033[31;40m\033[1m%s\033[0m";
+    $green = "\033[0;32;40m\033[1m%s\033[0m";
+  }
+
+  // Print key for colors
+  drush_print(dt('Legend: '));
+  drush_print(sprintf($red,   dt('Code:       drush features-revert will remove the overrides.')));
+  drush_print(sprintf($green, dt('Overrides:  drush features-update will update the exported feature with the displayed overrides')));
+  drush_print();
+
+  foreach ($overrides as $component => $items) {
+    $diff = new Diff(explode("\n", $items['default']), explode("\n", $items['normal']));
+    drush_print();
+    drush_print(dt("Component: !component", array('!component' => $component)));
+    $rows = explode("\n", $formatter->format($diff));
+    foreach ($rows as $row) {
+      if (strpos($row, '>') === 0) {
+        drush_print(sprintf($green, $row));
+      }
+      elseif (strpos($row, '<') === 0) {
+        drush_print(sprintf($red, $row));
+      }
+      else {
+        drush_print($row);
+      }
+    }
+  }
+}
+
+/**
+ * Helper function to call drush_set_error().
+ *
+ * @param $feature
+ *   The string name of the feature.
+ * @param $error
+ *   A text string identifying the type of error.
+ * @return
+ *   FALSE.  See drush_set_error().
+ */
+function _features_drush_set_error($feature, $error = '') {
+  $args = array('!feature' => $feature);
+
+  switch ($error) {
+    case 'FEATURES_FEATURE_NOT_ENABLED':
+      $message = 'The feature !feature is not enabled.';
+      break;
+    case 'FEATURES_COMPONENT_NOT_FOUND':
+      $message = 'The given component !feature could not be found.';
+      break;
+    default:
+      $error = 'FEATURES_FEATURE_NOT_FOUND';
+      $message = 'The feature !feature could not be found.';
+  }
+
+  return drush_set_error($error, dt($message, $args));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.export.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1005 @@
+<?php
+
+/**
+ * @param $info - feature info array
+ * @param $module_name
+ * @return fully populated export array
+ */
+function features_populate($info, $module_name) {
+  // Sanitize items.
+  $items = !empty($info['features']) ? array_filter($info['features']) : array();
+  $items['dependencies'] = !empty($info['dependencies']) ? drupal_map_assoc(array_filter($info['dependencies'])) : array();
+
+  // Populate stub
+  $stub = array('features' => array(), 'dependencies' => array(), 'conflicts' => array()) + $info + array('features_exclude' => array());
+  $export = _features_populate($items, $stub, $module_name, TRUE);
+
+  // Add Features API version. Any module with this entry in the .info file
+  // will be treated as a Feature and included in the admin/build/features UI.
+  $export['features']['features_api']['api:' . FEATURES_API] = TRUE;
+  // Allow other modules to alter the export.
+  drupal_alter('features_export', $export, $module_name);
+
+  // Clean up and standardize order
+  foreach (array_keys($export['features']) as $k) {
+    ksort($export['features'][$k]);
+  }
+  ksort($export['features']);
+  ksort($export['dependencies']);
+  ksort($export['features_exclude']);
+
+  return $export;
+}
+
+/**
+ * Iterate and descend into a feature definition to extract module
+ * dependencies and feature definition. Calls hook_features_export for modules
+ * that implement it.
+ *
+ * @param $pipe
+ *  Associative of array of module => info-for-module
+ * @param $export
+ *  Associative array of items, and module dependencies which define a feature.
+ *  Passed by reference.
+ *
+ * @return fully populated $export array.
+ */
+function _features_populate($pipe, &$export, $module_name = '', $reset = FALSE) {
+  static $processed = array();
+  features_include();
+  if ($reset) {
+    $processed = array();
+  }
+  foreach ($pipe as $component => $data) {
+    // Convert already defined items to dependencies.
+//    _features_resolve_dependencies($data, $export, $module_name, $component);
+    // Remove any excluded items.
+    if (!empty($export['features_exclude'][$component])) {
+      $data = array_diff($data, $export['features_exclude'][$component]);
+      if ($component == 'dependencies' && !empty($export['dependencies'])) {
+        $export['dependencies'] = array_diff($export['dependencies'], $export['features_exclude'][$component]);
+      }
+    }
+    if (!empty($data) && $function = features_hook($component, 'features_export')) {
+      // Pass module-specific data and export array.
+      // We don't use features_invoke() here since we need to pass $export by reference.
+      $more = $function($data, $export, $module_name, $component);
+      // Add the context information.
+      $export['component'] = $component;
+      $export['module_name'] = $module_name;
+      // Allow other modules to manipulate the pipe to add in additional modules.
+      drupal_alter(array('features_pipe', 'features_pipe_' . $component), $more, $data, $export);
+      // Remove the component information.
+      unset($export['component']);
+      unset($export['module_name']);
+      // Allow for export functions to request additional exports, but avoid
+      // circular references on already processed components.
+      $processed[$component] = isset($processed[$component]) ? array_merge($processed[$component], $data) : $data;
+
+      if (!empty($more)) {
+        // Remove already processed components.
+        foreach ($more as $component_name => $component_data) {
+          if (isset($processed[$component_name])) {
+            $more[$component_name] = array_diff($component_data, $processed[$component_name]);
+          }
+        }
+        if ($more = array_filter($more)) {
+          _features_populate($more, $export, $module_name);
+        }
+      }
+    }
+  }
+  return $export;
+}
+
+/**
+ * Iterates over data and convert to dependencies if already defined elsewhere.
+ */
+function _features_resolve_dependencies(&$data, &$export, $module_name, $component) {
+  if ($map = features_get_default_map($component)) {
+    foreach ($data as $key => $item) {
+      // If this node type is provided by a different module, add it as a dependency
+      if (isset($map[$item]) && $map[$item] != $module_name) {
+        $export['dependencies'][$map[$item]] = $map[$item];
+        unset($data[$key]);
+      }
+    }
+  }
+}
+
+/**
+ * Iterates over a list of dependencies and kills modules that are
+ * captured by other modules 'higher up'.
+ */
+function _features_export_minimize_dependencies($dependencies, $module_name = '') {
+  // Ensure that the module doesn't depend upon itself
+  if (!empty($module_name) && !empty($dependencies[$module_name])) {
+    unset($dependencies[$module_name]);
+  }
+
+  // Do some cleanup:
+  // - Remove modules required by Drupal core.
+  // - Protect against direct circular dependencies.
+  // - Remove "intermediate" dependencies.
+  $required = drupal_required_modules();
+  foreach ($dependencies as $k => $v) {
+    if (empty($v) || in_array($v, $required)) {
+      unset($dependencies[$k]);
+    }
+    else {
+      $module = features_get_modules($v);
+      if ($module && !empty($module->info['dependencies'])) {
+        // If this dependency depends on the module itself, we have a circular dependency.
+        // Don't let it happen. Only you can prevent forest fires.
+        if (in_array($module_name, $module->info['dependencies'])) {
+          unset($dependencies[$k]);
+        }
+        // Iterate through the dependency's dependencies and remove any dependencies
+        // that are captured by it.
+        else {
+          foreach ($module->info['dependencies'] as $j => $dependency) {
+            if (array_search($dependency, $dependencies) !== FALSE) {
+              $position = array_search($dependency, $dependencies);
+              unset($dependencies[$position]);
+            }
+          }
+        }
+      }
+    }
+  }
+  return drupal_map_assoc(array_unique($dependencies));
+}
+
+/**
+ * Iterates over a list of dependencies and maximize the list of modules.
+ */
+function _features_export_maximize_dependencies($dependencies, $module_name = '', $maximized = array(), $first = TRUE) {
+  foreach ($dependencies as $k => $v) {
+    $parsed_dependency = drupal_parse_dependency($v);
+    $name = $parsed_dependency['name'];
+    if (!in_array($name, $maximized)) {
+      $maximized[] = $name;
+      $module = features_get_modules($name);
+      if ($module && !empty($module->info['dependencies'])) {
+        $maximized = array_merge($maximized, _features_export_maximize_dependencies($module->info['dependencies'], $module_name, $maximized, FALSE));
+      }
+    }
+  }
+  return array_unique($maximized);
+}
+
+/**
+ * Prepare a feature export array into a finalized info array.
+ * @param $export
+ *  An exported feature definition.
+ * @param $module_name
+ *  The name of the module to be exported.
+ * @param $reset
+ *  Boolean flag for resetting the module cache. Only set to true when
+ *  doing a final export for delivery.
+ */
+function features_export_prepare($export, $module_name, $reset = FALSE, $add_deprecated = TRUE) {
+  $existing = features_get_modules($module_name, $reset);
+
+  // copy certain exports directly into info
+  $copy_list = array('scripts', 'stylesheets');
+  foreach ($copy_list as $item) {
+    if(isset($export[$item])) {
+      $existing->info[$item] = $export[$item];
+    }
+  }
+
+  // Prepare info string -- if module exists, merge into its existing info file
+  $defaults = !empty($existing->info) ? $existing->info : array('core' => '7.x', 'package' => 'Features');
+  $export = array_merge($defaults, $export);
+
+  $deprecated = features_get_deprecated();
+  // Cleanup info array
+  foreach ($export['features'] as $component => $data) {
+    // if performing the final export, do not export deprecated components
+    if (($reset || !$add_deprecated) && !empty($deprecated[$component])) {
+      unset($export['features'][$component]);
+    }
+    else {
+      $export['features'][$component] = array_keys($data);
+    }
+  }
+  if (isset($export['dependencies'])) {
+    $export['dependencies'] = array_values($export['dependencies']);
+  }
+  if (isset($export['conflicts'])) {
+    unset($export['conflicts']);
+  }
+
+  // Order info array.
+  $standard_info = array();
+  foreach (array_merge(array('name', 'description', 'core', 'package', 'version', 'project', 'dependencies'), $copy_list) as $item) {
+    if (isset($export[$item])) {
+      $standard_info[$item] = $export[$item];
+    }
+  }
+  if (isset($export['php']) && ($export['php'] != DRUPAL_MINIMUM_PHP)) {
+    $standard_info['php'] = $export['php'];
+  }
+  unset($export['php']);
+
+  $export = features_array_diff_assoc_recursive($export, $standard_info);
+  ksort($export);
+  return array_merge($standard_info, $export);
+}
+
+/**
+ * Generate an array of hooks and their raw code.
+ */
+function features_export_render_hooks($export, $module_name, $reset = FALSE) {
+  features_include();
+  $code = array();
+
+  // Sort components to keep exported code consistent
+  ksort($export['features']);
+
+  foreach ($export['features'] as $component => $data) {
+    if (!empty($data)) {
+      // Sort the items so that we don't generate different exports based on order
+      asort($data);
+      if (features_hook($component, 'features_export_render')) {
+        $hooks = features_invoke($component, 'features_export_render', $module_name, $data, $export);
+        $code[$component] = $hooks;
+      }
+    }
+  }
+  return $code;
+}
+
+/**
+ * Render feature export into an array representing its files.
+ *
+ * @param $export
+ *  An exported feature definition.
+ * @param $module_name
+ *  The name of the module to be exported.
+ * @param $reset
+ *  Boolean flag for resetting the module cache. Only set to true when
+ *  doing a final export for delivery.
+ *
+ * @return array of info file and module file contents.
+ */
+function features_export_render($export, $module_name, $reset = FALSE) {
+  $code = array();
+
+  // Generate hook code
+  $component_hooks = features_export_render_hooks($export, $module_name, $reset);
+  $components = features_get_components();
+  $deprecated = features_get_deprecated($components);
+
+  // Group component code into their respective files
+  foreach ($component_hooks as $component => $hooks) {
+    if ($reset && !empty($deprecated[$component])) {
+      // skip deprecated components on final export
+      continue;
+    }
+    $file = array('name' => 'features');
+    if (isset($components[$component]['default_file'])) {
+      switch ($components[$component]['default_file']) {
+        case FEATURES_DEFAULTS_INCLUDED:
+          $file['name'] = "features.$component";
+          break;
+        case FEATURES_DEFAULTS_CUSTOM:
+          $file['name'] = $components[$component]['default_filename'];
+          break;
+      }
+    }
+
+    if (!isset($code[$file['name']])) {
+      $code[$file['name']] = array();
+    }
+
+    foreach ($hooks as $hook_name => $hook_info) {
+      $hook_code = is_array($hook_info) ? $hook_info['code'] : $hook_info;
+      $hook_args = is_array($hook_info) && !empty($hook_info['args']) ? $hook_info['args'] : '';
+      $hook_file = is_array($hook_info) && !empty($hook_info['file']) ? $hook_info['file'] : $file['name'];
+      $code[$hook_file][$hook_name] = features_export_render_defaults($module_name, $hook_name, $hook_code, $hook_args);
+    }
+  }
+
+  // Finalize strings to be written to files
+  $code = array_filter($code);
+  foreach ($code as $filename => $contents) {
+    $code[$filename] = "<?php\n/**\n * @file\n * {$module_name}.{$filename}.inc\n */\n\n". implode("\n\n", $contents) ."\n";
+  }
+
+  // Generate info file output
+  $export = features_export_prepare($export, $module_name, $reset);
+  $code['info'] = features_export_info($export);
+
+  // Used to create or manipulate the generated .module for features.inc.
+  $modulefile_features_inc = "<?php\n/**\n * @file\n * Code for the {$export['name']} feature.\n */\n\ninclude_once '{$module_name}.features.inc';\n";
+  $modulefile_blank = "<?php\n/**\n * @file\n * Drupal needs this blank file.\n */\n";
+
+  // Prepare the module
+  // If module exists, let it be and include it in the files
+  if ($existing = features_get_modules($module_name, TRUE)) {
+    $code['module'] = file_get_contents($existing->filename);
+
+    // If the current module file does not reference the features.inc include,
+    // @TODO this way of checking does not account for the possibility of inclusion instruction being commented out.
+    if (isset($code['features']) && strpos($code['module'], "{$module_name}.features.inc") === FALSE) {
+      // If .module does not begin with <?php\n, just add a warning.
+      if (strpos($code['module'], "<?php\n") !== 0) {
+        features_log(t('@module does not appear to include the @include file.', array('@module' => "{$module_name}.module", '@include' => "{$module_name}.features.inc")), 'warning');
+      }
+      else {
+        // Remove the old message if it exists, else just remove the <?php
+        $length = strpos($code['module'], $modulefile_blank) === 0 ? strlen($modulefile_blank) : 6;
+        $code['module'] = $modulefile_features_inc . substr($code['module'], $length);
+      }
+    }
+
+    if ($reset) {
+      // only check for deprecated files on final export
+
+      // Deprecated files. Display a message for any of these files letting the
+      // user know that they may be removed.
+      $deprecated_files = array(
+        "{$module_name}.defaults",
+        "{$module_name}.features.views",
+        "{$module_name}.features.node"
+      );
+      // add deprecated components
+      foreach ($deprecated as $component) {
+        $info = features_get_components($component);
+        $filename = isset($info['default_file']) && $info['default_file'] == FEATURES_DEFAULTS_CUSTOM ? $info['default_filename'] : "features.{$component}";
+        $deprecated_files[] = "{$module_name}.$filename";
+      }
+      foreach (file_scan_directory(drupal_get_path('module', $module_name), '/.*/') as $file) {
+        if (in_array($file->name, $deprecated_files, TRUE)) {
+          features_log(t('The file @filename has been deprecated and can be removed.', array('@filename' => $file->filename)), 'status');
+        }
+        elseif ($file->name === "{$module_name}.features" && empty($code['features'])) {
+          // Try and remove features.inc include.
+          if (strpos($code['module'], "{$module_name}.features.inc")) {
+            $code['module'] = str_replace($modulefile_features_inc, $modulefile_blank, $code['module']);
+          }
+          // If unable to remove the include, add a message to remove.
+          if (strpos($code['module'], "{$module_name}.features.inc")) {
+            $code['features'] = "<?php\n\n// This file is deprecated and can be removed.\n// Please remove include_once('{$module_name}.features.inc') in {$module_name}.module as well.\n";
+          }
+          else {
+            $code['features'] = "<?php\n\n// This file is deprecated and can be removed.\n";
+          }
+        }
+      }
+    }
+  }
+  // Add a stub module to include the defaults
+  else if (!empty($code['features'])) {
+    $code['module'] = $modulefile_features_inc;
+  }
+  else {
+    $code['module'] = $modulefile_blank;
+  }
+  return $code;
+}
+
+/**
+ * Detect differences between DB and code components of a feature.
+ */
+function features_detect_overrides($module) {
+  static $cache;
+  if (!isset($cache)) {
+    $cache = array();
+  }
+  if (!isset($cache[$module->name])) {
+    // Rebuild feature from .info file description and prepare an export from current DB state.
+    $export = features_populate($module->info, $module->name);
+    $export = features_export_prepare($export, $module->name, FALSE, FALSE);
+
+    $overridden = array();
+
+    // Compare feature info
+    _features_sanitize($module->info);
+    _features_sanitize($export);
+
+    $compare = array('normal' => features_export_info($export), 'default' => features_export_info($module->info));
+    if ($compare['normal'] !== $compare['default']) {
+      $overridden['info'] = $compare;
+    }
+
+    // Collect differences at a per-component level
+    $states = features_get_component_states(array($module->name), FALSE);
+    foreach ($states[$module->name] as $component => $state) {
+      if ($state != FEATURES_DEFAULT) {
+        $normal = features_get_normal($component, $module->name);
+        $default = features_get_default($component, $module->name);
+        _features_sanitize($normal);
+        _features_sanitize($default);
+
+        $compare = array('normal' => features_var_export($normal), 'default' => features_var_export($default));
+        if (_features_linetrim($compare['normal']) !== _features_linetrim($compare['default'])) {
+          $overridden[$component] = $compare;
+        }
+      }
+    }
+    $cache[$module->name] = $overridden;
+  }
+  return $cache[$module->name];
+}
+
+/**
+ * Gets the available default hooks keyed by components.
+ */
+function features_get_default_hooks($component = NULL, $reset = FALSE) {
+  return features_get_components($component, 'default_hook', $reset);
+}
+
+/**
+ * Gets the available default hooks keyed by components.
+ */
+function features_get_default_alter_hook($component) {
+  $default_hook = features_get_components($component, 'default_hook');
+  $alter_hook = features_get_components($component, 'alter_hook');
+  $alter_type = features_get_components($component, 'alter_type');
+  return empty($alter_type) || $alter_type != 'none' ? ($alter_hook ? $alter_hook : $default_hook) : FALSE;
+}
+
+/**
+ * Return a code string representing an implementation of a defaults module hook.
+ */
+function features_export_render_defaults($module, $hook, $code, $args = '') {
+  $output = array();
+  $output[] = "/**";
+  $output[] = " * Implements hook_{$hook}().";
+  $output[] = " */";
+  $output[] = "function {$module}_{$hook}(" . $args . ") {";
+  $output[] = $code;
+  $output[] = "}";
+  return implode("\n", $output);
+}
+
+/**
+ * Generate code friendly to the Drupal .info format from a structured array.
+ *
+ * @param $info
+ *   An array or single value to put in a module's .info file.
+ * @param $parents
+ *   Array of parent keys (internal use only).
+ *
+ * @return
+ *   A code string ready to be written to a module's .info file.
+ */
+function features_export_info($info, $parents = array()) {
+  $output = '';
+  if (is_array($info)) {
+    foreach ($info as $k => $v) {
+      $child = $parents;
+      $child[] = $k;
+      $output .= features_export_info($v, $child);
+    }
+  }
+  else if (!empty($info) && count($parents)) {
+    $line = array_shift($parents);
+    foreach ($parents as $key) {
+      $line .= is_numeric($key) ? "[]" : "[{$key}]";
+    }
+    $line .=  " = {$info}\n";
+    return $line;
+  }
+  return $output;
+}
+
+/**
+ * Tar creation function. Written by dmitrig01.
+ *
+ * @param $name
+ *   Filename of the file to be tarred.
+ * @param $contents
+ *   String contents of the file.
+ *
+ * @return
+ *   A string of the tar file contents.
+ */
+function features_tar_create($name, $contents) {
+  /* http://www.mkssoftware.com/docs/man4/tar.4.asp */
+  /* http://www.phpclasses.org/browse/file/21200.html */
+  $tar = '';
+  $bigheader = $header = '';
+  if (strlen($name) > 100) {
+    $bigheader = pack("a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155a12",
+        '././@LongLink', '0000000', '0000000', '0000000',
+        sprintf("%011o", strlen($name)), '00000000000',
+        '        ', 'L', '', 'ustar ', '0',
+        '', '', '', '', '', '');
+
+    $bigheader .= str_pad($name, floor((strlen($name) + 512 - 1) / 512) * 512, "\0");
+
+    $checksum = 0;
+    for ($i = 0; $i < 512; $i++) {
+      $checksum += ord(substr($bigheader, $i, 1));
+    }
+    $bigheader = substr_replace($bigheader, sprintf("%06o", $checksum)."\0 ", 148, 8);
+  }
+ $header = pack("a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155a12", // book the memorie area
+    substr($name,0,100),  //  0     100     File name
+    '100644 ',            // File permissions
+    '   765 ',            // UID,
+    '   765 ',            // GID,
+    sprintf("%11s ", decoct(strlen($contents))), // Filesize,
+    sprintf("%11s", decoct(REQUEST_TIME)),       // Creation time
+    '        ',        // 148     8         Check sum for header block
+    '',                // 156     1         Link indicator / ustar Type flag
+    '',                // 157     100     Name of linked file
+    'ustar ',          // 257     6         USTAR indicator "ustar"
+    ' ',               // 263     2         USTAR version "00"
+    '',                // 265     32         Owner user name
+    '',                // 297     32         Owner group name
+    '',                // 329     8         Device major number
+    '',                // 337     8         Device minor number
+    '',                // 345     155     Filename prefix
+    '');               // 500     12         ??
+
+  $checksum = 0;
+  for ($i = 0; $i < 512; $i++) {
+    $checksum += ord(substr($header, $i, 1));
+  }
+  $header = substr_replace($header, sprintf("%06o", $checksum)."\0 ", 148, 8);
+  $tar = $bigheader.$header;
+
+  $buffer = str_split($contents, 512);
+  foreach ($buffer as $item) {
+    $tar .= pack("a512", $item);
+  }
+  return $tar;
+}
+
+/**
+ * Export var function -- from Views.
+ */
+function features_var_export($var, $prefix = '', $init = TRUE, $count = 0) {
+  if ($count > 50) {
+    watchdog('features', 'Recursion depth reached in features_var_export', array());
+    return '';
+  }
+
+  if (is_object($var)) {
+    $output = method_exists($var, 'export') ? $var->export() : features_var_export((array) $var, '', FALSE, $count+1);
+  }
+  else if (is_array($var)) {
+    if (empty($var)) {
+      $output = 'array()';
+    }
+    else {
+      $output = "array(\n";
+      foreach ($var as $key => $value) {
+        // Using normal var_export on the key to ensure correct quoting.
+        $output .= "  " . var_export($key, TRUE) . " => " . features_var_export($value, '  ', FALSE, $count+1) . ",\n";
+      }
+      $output .= ')';
+    }
+  }
+  else if (is_bool($var)) {
+    $output = $var ? 'TRUE' : 'FALSE';
+  }
+  else if (is_int($var)) {
+    $output = intval($var);
+  }
+  else if (is_numeric($var)) {
+    $output = floatval($var);
+  }
+  else if (is_string($var) && strpos($var, "\n") !== FALSE) {
+    // Replace line breaks in strings with a token for replacement
+    // at the very end. This protects whitespace in strings from
+    // unintentional indentation.
+    $var = str_replace("\n", "***BREAK***", $var);
+    $output = var_export($var, TRUE);
+  }
+  else {
+    $output = var_export($var, TRUE);
+  }
+
+  if ($prefix) {
+    $output = str_replace("\n", "\n$prefix", $output);
+  }
+
+  if ($init) {
+    $output = str_replace("***BREAK***", "\n", $output);
+  }
+
+  return $output;
+}
+
+/**
+ * Helper function to return an array of t()'d translatables strings.
+ * Useful for providing a separate array of translatables with your
+ * export so that string extractors like potx can detect them.
+ */
+function features_translatables_export($translatables, $indent = '') {
+  $output = '';
+  $translatables = array_filter(array_unique($translatables));
+  if (!empty($translatables)) {
+    $output .= "{$indent}// Translatables\n";
+    $output .= "{$indent}// Included for use with string extractors like potx.\n";
+    sort($translatables);
+    foreach ($translatables as $string) {
+      $output .= "{$indent}t(" . features_var_export($string) . ");\n";
+    }
+  }
+  return $output;
+}
+
+/**
+ * Get a summary storage state for a feature.
+ */
+function features_get_storage($module_name) {
+  // Get component states, and array_diff against array(FEATURES_DEFAULT).
+  // If the returned array has any states that don't match FEATURES_DEFAULT,
+  // return the highest state.
+  $states = features_get_component_states(array($module_name), FALSE);
+  $states = array_diff($states[$module_name], array(FEATURES_DEFAULT));
+  $storage = !empty($states) ? max($states) : FEATURES_DEFAULT;
+  return $storage;
+}
+
+/**
+ * Wrapper around features_get_[storage] to return an md5hash of a normalized
+ * defaults/normal object array. Can be used to compare normal/default states
+ * of a module's component.
+ */
+function features_get_signature($state = 'default', $module_name, $component, $reset = FALSE) {
+  switch ($state) {
+    case 'cache':
+      $codecache = variable_get('features_codecache', array());
+      return isset($codecache[$module_name][$component]) ? $codecache[$module_name][$component] : FALSE;
+    case 'default':
+      $objects = features_get_default($component, $module_name, TRUE, $reset);
+      break;
+    case 'normal':
+      $objects = features_get_normal($component, $module_name, $reset);
+      break;
+  }
+  if (!empty($objects)) {
+    $objects = (array) $objects;
+    _features_sanitize($objects);
+    return md5(_features_linetrim(features_var_export($objects)));
+  }
+  return FALSE;
+}
+
+/**
+ * Set the signature of a module/component pair in the codecache.
+ */
+function features_set_signature($module, $component, $signature = NULL) {
+  $var_codecache = variable_get('features_codecache', array());
+  $signature = isset($signature) ? $signature : features_get_signature('default', $module, $component, TRUE);
+  $var_codecache[$module][$component] = $signature;
+  variable_set('features_codecache', $var_codecache);
+}
+
+/**
+ * Processing semaphore operations.
+ */
+function features_semaphore($op, $component) {
+  // Note: we don't use variable_get() here as the inited variable
+  // static cache may be stale. Retrieving directly from the DB narrows
+  // the possibility of collision.
+  $semaphore = db_query("SELECT value FROM {variable} WHERE name = :name", array(':name' => 'features_semaphore'))->fetchField();
+  $semaphore = !empty($semaphore) ? unserialize($semaphore) : array();
+
+  switch ($op) {
+    case 'get':
+      return isset($semaphore[$component]) ? $semaphore[$component] : FALSE;
+    case 'set':
+      $semaphore[$component] = REQUEST_TIME;
+      variable_set('features_semaphore', $semaphore);
+      break;
+    case 'del':
+      if (isset($semaphore[$component])) {
+        unset($semaphore[$component]);
+        variable_set('features_semaphore', $semaphore);
+      }
+      break;
+  }
+}
+
+/**
+ * Get normal objects for a given module/component pair.
+ */
+function features_get_normal($component, $module_name, $reset = FALSE) {
+  static $cache;
+  if (!isset($cache) || $reset) {
+    $cache = array();
+  }
+  if (!isset($cache[$module_name][$component])) {
+    features_include();
+    $code = NULL;
+    $module = features_get_features($module_name);
+
+    // Special handling for dependencies component.
+    if ($component === 'dependencies') {
+      $cache[$module_name][$component] = isset($module->info['dependencies']) ? array_filter($module->info['dependencies'], 'module_exists') : array();
+    }
+    // All other components.
+    else {
+      $default_hook = features_get_default_hooks($component);
+      if ($module && $default_hook && isset($module->info['features'][$component]) && features_hook($component, 'features_export_render')) {
+        $code = features_invoke($component, 'features_export_render', $module_name, $module->info['features'][$component], NULL);
+        $cache[$module_name][$component] = isset($code[$default_hook]) ? eval($code[$default_hook]) : FALSE;
+      }
+    }
+
+    // Clear out vars for memory's sake.
+    unset($code);
+    unset($module);
+  }
+  return isset($cache[$module_name][$component]) ? $cache[$module_name][$component] : FALSE;
+}
+
+/**
+ * Get defaults for a given module/component pair.
+ */
+function features_get_default($component, $module_name = NULL, $alter = TRUE, $reset = FALSE) {
+  static $cache = array();
+  $alter = !empty($alter); // ensure $alter is a true/false boolean
+  features_include();
+  features_include_defaults($component);
+  $default_hook = features_get_default_hooks($component);
+  $components = features_get_components();
+
+  // Collect defaults for all modules if no module name was specified.
+  if (isset($module_name)) {
+    $modules = array($module_name);
+  }
+  else {
+    if ($component === 'dependencies') {
+      $modules = array_keys(features_get_features());
+    }
+    else {
+      $modules = array();
+      foreach (features_get_component_map($component) as $component_modules) {
+        $modules = array_merge($modules, $component_modules);
+      }
+      $modules = array_unique($modules);
+    }
+  }
+
+  // Collect and cache information for each specified module.
+  foreach ($modules as $m) {
+    if (!isset($cache[$component][$alter][$m]) || $reset) {
+      // Special handling for dependencies component.
+      if ($component === 'dependencies') {
+        $module = features_get_features($m);
+        $cache[$component][$alter][$m] = isset($module->info['dependencies']) ? $module->info['dependencies'] : array();
+        unset($module);
+      }
+      // All other components
+      else {
+        if ($default_hook && module_hook($m, $default_hook)) {
+          $cache[$component][$alter][$m] = call_user_func("{$m}_{$default_hook}");
+          if (is_array($cache[$component][$alter][$m])) {
+            $alter_type = features_get_components('alter_type', $component);
+            if ($alter && (!isset($alter_type) || $alter_type == FEATURES_ALTER_TYPE_NORMAL)) {
+              if ($alter_hook = features_get_default_alter_hook($component)) {
+                drupal_alter($alter_hook, $cache[$component][$alter][$m]);
+              }
+            }
+          }
+          else {
+            $cache[$component][$alter][$m] = FALSE;
+          }
+        }
+        else {
+          $cache[$component][$alter][$m] = FALSE;
+        }
+      }
+    }
+  }
+
+  // A specific module was specified. Retrieve only its components.
+  if (isset($module_name)) {
+    return isset($cache[$component][$alter][$module_name]) ? $cache[$component][$alter][$module_name] : FALSE;
+  }
+  // No module was specified. Retrieve all components.
+  $all_defaults = array();
+  if (isset($cache[$component][$alter])) {
+    foreach (array_filter($cache[$component][$alter]) as $module_components) {
+      $all_defaults = array_merge($all_defaults, $module_components);
+    }
+  }
+  return $all_defaults;
+}
+
+/**
+ * Get a map of components to their providing modules.
+ */
+function features_get_default_map($component, $attribute = NULL, $callback = NULL, $reset = FALSE) {
+  static $map = array();
+
+  global $features_ignore_conflicts;
+  if ($features_ignore_conflicts) {
+    return FALSE;
+  }
+
+  features_include();
+  features_include_defaults($component);
+  if ((!isset($map[$component]) || $reset) && $default_hook = features_get_default_hooks($component)) {
+    $map[$component] = array();
+    foreach (module_implements($default_hook) as $module) {
+      if ($defaults = features_get_default($component, $module)) {
+        foreach ($defaults as $key => $object) {
+          if (isset($callback)) {
+            if ($object_key = $callback($object)) {
+              $map[$component][$object_key] = $module;
+            }
+          }
+          elseif (isset($attribute)) {
+            if (is_object($object) && isset($object->{$attribute})) {
+              $map[$component][$object->{$attribute}] = $module;
+            }
+            elseif (is_array($object) && isset($object[$attribute])) {
+              $map[$component][$object[$attribute]] = $module;
+            }
+          }
+          elseif (!isset($attribute) && !isset($callback)) {
+            if (!is_numeric($key)) {
+              $map[$component][$key] = $module;
+            }
+          }
+          else {
+            return FALSE;
+          }
+        }
+      }
+    }
+  }
+  return isset($map[$component]) ? $map[$component] : FALSE;
+}
+
+/**
+ * Retrieve an array of features/components and their current states.
+ */
+function features_get_component_states($features = array(), $rebuild_only = TRUE, $reset = FALSE) {
+  static $cache;
+  if (!isset($cache) || $reset) {
+    $cache = array();
+  }
+
+  $features = !empty($features) ? $features : array_keys(features_get_features());
+
+  // Retrieve only rebuildable components if requested.
+  features_include();
+  $components = array_keys(features_get_components());
+  if ($rebuild_only) {
+    foreach ($components as $k => $component) {
+      if (!features_hook($component, 'features_rebuild')) {
+        unset($components[$k]);
+      }
+    }
+  }
+
+  foreach ($features as $feature) {
+    $cache[$feature] = isset($cache[$feature]) ? $cache[$feature] : array();
+    if (module_exists($feature)) {
+      foreach ($components as $component) {
+        if (!isset($cache[$feature][$component])) {
+          $normal = features_get_signature('normal', $feature, $component, $reset);
+          $default = features_get_signature('default', $feature, $component, $reset);
+          $codecache = features_get_signature('cache', $feature, $component, $reset);
+          $semaphore = features_semaphore('get', $component);
+
+          // DB and code states match, there is nothing more to check.
+          if ($normal == $default) {
+            $cache[$feature][$component] = FEATURES_DEFAULT;
+
+            // Stale semaphores can be deleted.
+            features_semaphore('del', $component);
+
+            // Update code cache if it is stale, clear out semaphore if it stale.
+            if ($default != $codecache) {
+              features_set_signature($feature, $component, $default);
+            }
+          }
+          // Component properly implements exportables.
+          else if (!features_hook($component, 'features_rebuild')) {
+            $cache[$feature][$component] = FEATURES_OVERRIDDEN;
+          }
+          // Component does not implement exportables.
+          else {
+            if (empty($semaphore)) {
+              // Exception for dependencies. Dependencies are always rebuildable.
+              if ($component === 'dependencies') {
+                $cache[$feature][$component] = FEATURES_REBUILDABLE;
+              }
+              // All other rebuildable components require comparison.
+              else {
+                // Code has not changed, but DB does not match. User has DB overrides.
+                if ($codecache == $default) {
+                  $cache[$feature][$component] = FEATURES_OVERRIDDEN;
+                }
+                // DB has no modifications to prior code state (or this is initial install).
+                else if (empty($codecache) || $codecache == $normal) {
+                  $cache[$feature][$component] = FEATURES_REBUILDABLE;
+                }
+                // None of the states match. Requires user intervention.
+                else if ($codecache != $default) {
+                  $cache[$feature][$component] = FEATURES_NEEDS_REVIEW;
+                }
+              }
+            }
+            else {
+              // Semaphore is still within processing horizon. Do nothing.
+              if ((REQUEST_TIME - $semaphore) < FEATURES_SEMAPHORE_TIMEOUT) {
+                $cache[$feature][$component] = FEATURES_REBUILDING;
+              }
+              // A stale semaphore means a previous rebuild attempt did not complete.
+              // Attempt to complete the rebuild.
+              else {
+                $cache[$feature][$component] = FEATURES_REBUILDABLE;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  // Filter cached components on the way out to ensure that even if we have
+  // cached more data than has been requested, the return value only reflects
+  // the requested features/components.
+  $return = $cache;
+  $return = array_intersect_key($return, array_flip($features));
+  foreach ($return as $k => $v) {
+    $return[$k] = array_intersect_key($return[$k], array_flip($components));
+  }
+  return $return;
+}
+
+/**
+ * Helper function to eliminate whitespace differences in code.
+ */
+function _features_linetrim($code) {
+  $code = explode("\n", $code);
+  foreach ($code as $k => $line) {
+    $code[$k] = trim($line);
+  }
+  return implode("\n", $code);
+}
+
+/**
+ * "Sanitizes" an array recursively, performing two key operations:
+ * - Sort an array by its keys (assoc) or values (non-assoc)
+ * - Remove any null or empty values for associative arrays (array_filter()).
+ */
+function _features_sanitize(&$array) {
+  if (is_array($array)) {
+    $is_assoc = _features_is_assoc($array);
+    if ($is_assoc) {
+      ksort($array, SORT_STRING);
+      $array = array_filter($array);
+    }
+    else {
+      sort($array);
+    }
+    foreach ($array as $k => $v) {
+      if (is_array($v)) {
+        _features_sanitize($array[$k]);
+        if ($is_assoc && empty($array[$k])) {
+          unset($array[$k]);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Is the given array an associative array. This basically extracts the keys twice to get the
+ * numerically ordered keys. It then does a diff with the original array and if there is no
+ * key diff then the original array is not associative.
+ *
+ * NOTE: If you have non-sequential numerical keys, this will identify the array as assoc.
+ *
+ * Borrowed from: http://www.php.net/manual/en/function.is-array.php#96724
+ *
+ * @return True is the array is an associative array, false otherwise
+ */
+function _features_is_assoc($array) {
+  return (is_array($array) && (0 !== count(array_diff_key($array, array_keys(array_keys($array)))) || count($array)==0));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = "Features"
+description = "Provides feature management for Drupal."
+core = 7.x
+package = "Features"
+files[] = tests/features.test
+
+configure = admin/structure/features/settings
+
+; Information added by drupal.org packaging script on 2013-08-26
+version = "7.x-2.0-rc3"
+core = "7.x"
+project = "features"
+datestamp = "1377548845"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,121 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the features module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function features_install() {
+  _features_install_menu();
+  db_update('system')
+    ->fields(array('weight' =>  20))
+    ->condition('name', 'features')
+    ->condition('type', 'module')
+    ->execute();
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function features_uninstall() {
+  variable_del('features_codecache');
+  variable_del('features_semaphore');
+  variable_del('features_ignored_orphans');
+  if (db_table_exists('menu_custom')) {
+    db_delete('menu_custom')
+      ->condition('menu_name', 'features')
+      ->execute();
+  }
+  db_delete('menu_links')
+    ->condition('module', 'features')
+    ->execute();
+}
+
+/**
+ * Create menu. See menu.install for an example.
+ */
+function _features_install_menu() {
+  if (db_table_exists('menu_custom') && !db_query("SELECT menu_name FROM {menu_custom} WHERE menu_name = :menu_name", array(':menu_name' => 'features'))->fetchField()) {
+    $t = get_t();
+    $id = db_insert('menu_custom')
+      ->fields(array(
+        'menu_name' => 'features',
+        'title' => $t('Features'),
+        'description' => $t('Menu items for any enabled features.'),
+      ))
+      ->execute();
+  }
+}
+
+/**
+ * Update 6100: Set module on all feature node types to 'features'.
+
+ * This update can be re-run as needed to repair any node types that are not
+ * removed after disabling the associated feature.
+ *
+ * Any feature implementing a node component that was exported prior to this
+ * version of the features.module will need to have its 'module' declaration
+ * in hook_node_info() changed from 'node' to 'features'.
+ */
+function features_update_6100() {
+  $ret = array();
+
+  foreach (features_get_features(NULL, TRUE) as $feature) {
+    if (module_exists($feature->name) && $types = module_invoke($feature->name, 'node_info')) {
+      foreach ($types as $type => $type_data) {
+        $sql = "SELECT COUNT(*) FROM {node_type} WHERE module = 'node' AND type = '%s'";
+        // Only update if the hook_node_info type's module is 'features' and the db type's
+        // module is 'node'.
+        if (($type_data['module'] == 'features') && db_query($sql, $type)->fetchField()) {
+          $ret[] = update_sql("UPDATE {node_type} SET module = 'features' WHERE type = '$type'");
+        }
+      }
+    }
+  }
+  return $ret;
+}
+
+/**
+ * Update 6101: Set codestate signature for all features.
+ *
+ * This update generates a codestate for all feature/component pairs which
+ * have been installed prior to this version of Features. This prevents
+ * automatic rebuilds from occurring against any rebuildable components
+ * that have been overridden.
+ */
+function features_update_6101() {
+  // Ensure all of our own API functions still exist in in this version
+  // of Features. It's possible that the "future me" will not have these
+  // functions, so I should check.
+  module_load_include('inc', 'features', "features.export");
+  $functions = array(
+    'features_include',
+    'features_hook',
+    'features_get_components',
+    'features_get_features',
+    'features_get_signature',
+    'features_set_signature',
+  );
+  $doit = TRUE;
+  foreach ($functions as $function) {
+    $doit = $doit && function_exists($function);
+  }
+  if ($doit) {
+    features_include();
+    $features = array_keys(features_get_features(NULL, TRUE));
+    $components = array_keys(features_get_components());
+    foreach ($features as $feature) {
+      if (module_exists($feature)) {
+        foreach ($components as $component) {
+          if (features_hook($component, 'features_rebuild') && features_get_signature('cache', $feature, $component) === FALSE) {
+            features_set_signature($feature, $component, -1);
+          }
+        }
+      }
+    }
+  }
+  return array();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,437 @@
+/**
+ * jQuery.fn.sortElements
+ * --------------
+ * @param Function comparator:
+ *   Exactly the same behaviour as [1,2,3].sort(comparator)
+ *
+ * @param Function getSortable
+ *   A function that should return the element that is
+ *   to be sorted. The comparator will run on the
+ *   current collection, but you may want the actual
+ *   resulting sort to occur on a parent or another
+ *   associated element.
+ *
+ *   E.g. $('td').sortElements(comparator, function(){
+ *      return this.parentNode;
+ *   })
+ *
+ *   The <td>'s parent (<tr>) will be sorted instead
+ *   of the <td> itself.
+ *
+ * Credit: http://james.padolsey.com/javascript/sorting-elements-with-jquery/
+ *
+ */
+jQuery.fn.sortElements = (function(){
+
+    var sort = [].sort;
+
+    return function(comparator, getSortable) {
+
+        getSortable = getSortable || function(){return this;};
+
+        var placements = this.map(function(){
+
+            var sortElement = getSortable.call(this),
+                parentNode = sortElement.parentNode,
+
+                // Since the element itself will change position, we have
+                // to have some way of storing its original position in
+                // the DOM. The easiest way is to have a 'flag' node:
+                nextSibling = parentNode.insertBefore(
+                    document.createTextNode(''),
+                    sortElement.nextSibling
+                );
+
+            return function() {
+
+                if (parentNode === this) {
+                    throw new Error(
+                        "You can't sort elements if any one is a descendant of another."
+                    );
+                }
+
+                // Insert before flag:
+                parentNode.insertBefore(this, nextSibling);
+                // Remove flag:
+                parentNode.removeChild(nextSibling);
+
+            };
+
+        });
+
+        return sort.call(this, comparator).each(function(i){
+            placements[i].call(getSortable.call(this));
+        });
+
+    };
+
+})();
+
+(function ($) {
+  Drupal.behaviors.features = {
+    attach: function(context, settings) {
+      // Features management form
+      $('table.features:not(.processed)', context).each(function() {
+        $(this).addClass('processed');
+
+        // Check the overridden status of each feature
+        Drupal.features.checkStatus();
+
+        // Add some nicer row hilighting when checkboxes change values
+        $('input', this).bind('change', function() {
+          if (!$(this).attr('checked')) {
+            $(this).parents('tr').removeClass('enabled').addClass('disabled');
+          }
+          else {
+            $(this).parents('tr').addClass('enabled').removeClass('disabled');
+          }
+        });
+      });
+
+      // Export form component selector
+      $('form.features-export-form select.features-select-components:not(.processed)', context).each(function() {
+        $(this)
+          .addClass('processed')
+          .change(function() {
+            var target = $(this).val();
+            $('div.features-select').hide();
+            $('div.features-select-' + target).show();
+            return false;
+        }).trigger('change');
+      });
+
+      // Export form machine-readable JS
+      $('.feature-name:not(.processed)', context).each(function() {
+        $('.feature-name')
+          .addClass('processed')
+          .after(' <small class="feature-module-name-suffix">&nbsp;</small>');
+        if ($('.feature-module-name').val() === $('.feature-name').val().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/_+/g, '_') || $('.feature-module-name').val() === '') {
+          $('.feature-module-name').parents('.form-item').hide();
+          $('.feature-name').bind('keyup change', function() {
+            var machine = $(this).val().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/_+/g, '_');
+            if (machine !== '_' && machine !== '') {
+              $('.feature-module-name').val(machine);
+              $('.feature-module-name-suffix').empty().append(' Machine name: ' + machine + ' [').append($('<a href="#">'+ Drupal.t('Edit') +'</a>').click(function() {
+                $('.feature-module-name').parents('.form-item').show();
+                $('.feature-module-name-suffix').hide();
+                $('.feature-name').unbind('keyup');
+                return false;
+              })).append(']');
+            }
+            else {
+              $('.feature-module-name').val(machine);
+              $('.feature-module-name-suffix').text('');
+            }
+          });
+          $('.feature-name').keyup();
+        }
+      });
+
+      //View info dialog
+      var infoDialog = $('#features-info-file');
+      if (infoDialog.length != 0) {
+        infoDialog.dialog({
+          autoOpen: false,
+          modal: true,
+          draggable: false,
+          resizable: false,
+          width: 600,
+          height: 480
+        });
+      }
+
+      if ((Drupal.settings.features != undefined) && (Drupal.settings.features.info != undefined)) {
+        $('#features-info-file textarea').val(Drupal.settings.features.info);
+        $('#features-info-file').dialog('open');
+        //To be reset by the button click ajax
+        Drupal.settings.features.info = undefined;
+      }
+
+      // mark any conflicts with a class
+      if ((Drupal.settings.features != undefined) && (Drupal.settings.features.conflicts != undefined)) {
+        for (var moduleName in Drupal.settings.features.conflicts) {
+          moduleConflicts = Drupal.settings.features.conflicts[moduleName];
+          $('#features-export-wrapper input[type=checkbox]', context).each(function() {
+            if (!$(this).hasClass('features-checkall')) {
+              var key = $(this).attr('name');
+              var matches = key.match(/^([^\[]+)(\[.+\])?\[(.+)\]\[(.+)\]$/);
+              var component = matches[1];
+              var item = matches[4];
+              if ((component in moduleConflicts) && (moduleConflicts[component].indexOf(item) != -1)) {
+                $(this).parent().addClass('features-conflict');
+              }
+            }
+          });
+        }
+      }
+
+      function _checkAll(value) {
+        if (value) {
+          $('#features-export-wrapper .component-select input[type=checkbox]:visible', context).each(function() {
+            var move_id = $(this).attr('id');
+            $(this).click();
+            $('#'+ move_id).attr('checked', 'checked');
+        });
+        }
+        else {
+          $('#features-export-wrapper .component-added input[type=checkbox]:visible', context).each(function() {
+            var move_id = $(this).attr('id');
+            $('#'+ move_id).removeAttr('checked');
+            $(this).click();
+            $('#'+ move_id).removeAttr('checked');
+          });
+        }
+      }
+
+      function moveCheckbox(item, section, value) {
+        var curParent = item;
+        if ($(item).hasClass('form-type-checkbox')) {
+          item = $(item).children('input[type=checkbox]');
+        }
+        else {
+          curParent = $(item).parents('.form-type-checkbox');
+        }
+        var newParent = $(curParent).parents('.features-export-parent').find('.form-checkboxes.component-'+section);
+        $(curParent).detach();
+        $(curParent).appendTo(newParent);
+        var list = ['select', 'added', 'detected', 'included'];
+        for (i in list) {
+          $(curParent).removeClass('component-' + list[i]);
+          $(item).removeClass('component-' + list[i]);
+        }
+        $(curParent).addClass('component-'+section);
+        $(item).addClass('component-'+section);
+        if (value) {
+          $(item).attr('checked', 'checked');
+        }
+        else {
+          $(item).removeAttr('checked')
+        }
+        $(newParent).parent().removeClass('features-export-empty');
+
+        // re-sort new list of checkboxes based on labels
+        $(newParent).find('label').sortElements(
+          function(a, b){
+            return $(a).text() > $(b).text() ? 1 : -1;
+          },
+          function(){
+            return this.parentNode;
+          }
+        );
+      }
+
+      // provide timer for auto-refresh trigger
+      var timeoutID = 0;
+      var inTimeout = 0;
+      function _triggerTimeout() {
+        timeoutID = 0;
+        _updateDetected();
+      }
+      function _resetTimeout() {
+        inTimeout++;
+        // if timeout is already active, reset it
+        if (timeoutID != 0) {
+          window.clearTimeout(timeoutID);
+          if (inTimeout > 0) inTimeout--;
+        }
+        timeoutID = window.setTimeout(_triggerTimeout, 500);
+      }
+
+      function _updateDetected() {
+        var autodetect = $('#features-autodetect input[type=checkbox]');
+        if ((autodetect.length > 0) && (!autodetect.is(':checked'))) return;
+        // query the server for a list of components/items in the feature and update
+        // the auto-detected items
+        var items = [];  // will contain a list of selected items exported to feature
+        var components = {};  // contains object of component names that have checked items
+        $('#features-export-wrapper input[type=checkbox]:checked', context).each(function() {
+          if (!$(this).hasClass('features-checkall')) {
+            var key = $(this).attr('name');
+            var matches = key.match(/^([^\[]+)(\[.+\])?\[(.+)\]\[(.+)\]$/);
+            components[matches[1]] = matches[1];
+            if (!$(this).hasClass('component-detected')) {
+              items.push(key);
+            }
+          }
+        });
+        var featureName = $('#edit-module-name').val();
+        if (featureName == '') {
+          featureName = '*';
+        }
+        var url = Drupal.settings.basePath + 'features/ajaxcallback/' + featureName;
+        var excluded = Drupal.settings.features.excluded;
+        var postData = {'items': items, 'excluded': excluded};
+        jQuery.post(url, postData, function(data) {
+          if (inTimeout > 0) inTimeout--;
+          // if we have triggered another timeout then don't update with old results
+          if (inTimeout == 0) {
+            // data is an object keyed by component listing the exports of the feature
+            for (var component in data) {
+              var itemList = data[component];
+              $('#features-export-wrapper .component-' + component + ' input[type=checkbox]', context).each(function() {
+                var key = $(this).attr('value');
+                // first remove any auto-detected items that are no longer in component
+                if ($(this).hasClass('component-detected')) {
+                  if (!(key in itemList)) {
+                    moveCheckbox(this, 'select', false)
+                  }
+                }
+                // next, add any new auto-detected items
+                else if ($(this).hasClass('component-select')) {
+                  if (key in itemList) {
+                    moveCheckbox(this, 'detected', itemList[key]);
+                    $(this).parent().show(); // make sure it's not hidden from filter
+                  }
+                }
+              });
+            }
+            // loop over all selected components and check for any that have been completely removed
+            for (var component in components) {
+              if ((data == null) || !(component in data)) {
+                $('#features-export-wrapper .component-' + component + ' input[type=checkbox].component-detected', context).each(function() {
+                  moveCheckbox(this, 'select', false);
+                });
+              }
+            }
+          }
+        }, "json");
+      }
+
+      // Handle component selection UI
+      $('#features-export-wrapper input[type=checkbox]', context).click(function() {
+        _resetTimeout();
+        if ($(this).hasClass('component-select')) {
+          moveCheckbox(this, 'added', true);
+        }
+        else if ($(this).hasClass('component-included')) {
+          moveCheckbox(this, 'added', false);
+        }
+        else if ($(this).hasClass('component-added')) {
+          if ($(this).is(':checked')) {
+            moveCheckbox(this, 'included', true);
+          }
+          else {
+            moveCheckbox(this, 'select', false);
+          }
+        }
+      });
+
+      // Handle select/unselect all
+      $('#features-filter .features-checkall', context).click(function() {
+        if ($(this).attr('checked')) {
+          _checkAll(true);
+          $(this).next().html(Drupal.t('Deselect all'));
+        }
+        else {
+          _checkAll(false);
+          $(this).next().html(Drupal.t('Select all'));
+        }
+        _resetTimeout();
+      });
+
+      // Handle filtering
+
+      // provide timer for auto-refresh trigger
+      var filterTimeoutID = 0;
+      var inFilterTimeout = 0;
+      function _triggerFilterTimeout() {
+        filterTimeoutID = 0;
+        _updateFilter();
+      }
+      function _resetFilterTimeout() {
+        inFilterTimeout++;
+        // if timeout is already active, reset it
+        if (filterTimeoutID != 0) {
+          window.clearTimeout(filterTimeoutID);
+          if (inFilterTimeout > 0) inFilterTimeout--;
+        }
+        filterTimeoutID = window.setTimeout(_triggerFilterTimeout, 200);
+      }
+      function _updateFilter() {
+        var filter = $('#features-filter input').val();
+        var regex = new RegExp(filter, 'i');
+        // collapse fieldsets
+        var newState = {};
+        var currentState = {};
+        $('#features-export-wrapper fieldset.features-export-component', context).each(function() {
+          // expand parent fieldset
+          var section = $(this).attr('id');
+          currentState[section] = !($(this).hasClass('collapsed'));
+          if (!(section in newState)) {
+            newState[section] = false;
+          }
+
+          $(this).find('div.component-select label').each(function() {
+            if (filter == '') {
+              if (currentState[section]) {
+                Drupal.toggleFieldset($('#'+section));
+                currentState[section] = false;
+              }
+              $(this).parent().show();
+            }
+            else if ($(this).text().match(regex)) {
+              $(this).parent().show();
+              newState[section] = true;
+            }
+            else {
+              $(this).parent().hide();
+            }
+          });
+        });
+        for (section in newState) {
+          if (currentState[section] != newState[section]) {
+            Drupal.toggleFieldset($('#'+section));
+          }
+        }
+      }
+      $('#features-filter input', context).bind("input", function() {
+        _resetFilterTimeout();
+      });
+      $('#features-filter .features-filter-clear', context).click(function() {
+        $('#features-filter input').val('');
+        _updateFilter();
+      });
+
+      // show the filter bar
+      $('#features-filter', context).removeClass('element-invisible');
+    }
+  }
+
+
+  Drupal.features = {
+    'checkStatus': function() {
+      $('table.features tbody tr').not('.processed').filter(':first').each(function() {
+        var elem = $(this);
+        $(elem).addClass('processed');
+        var uri = $(this).find('a.admin-check').attr('href');
+        if (uri) {
+          $.get(uri, [], function(data) {
+            $(elem).find('.admin-loading').hide();
+            switch (data.storage) {
+              case 3:
+                $(elem).find('.admin-rebuilding').show();
+                break;
+              case 2:
+                $(elem).find('.admin-needs-review').show();
+                break;
+              case 1:
+                $(elem).find('.admin-overridden').show();
+                break;
+              default:
+                $(elem).find('.admin-default').show();
+                break;
+            }
+            Drupal.features.checkStatus();
+          }, 'json');
+        }
+        else {
+            Drupal.features.checkStatus();
+          }
+      });
+    }
+  };
+
+
+})(jQuery);
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/features.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1095 @@
+<?php
+
+/**
+ * @file
+ * Module file for the features module, which enables the capture and
+ * management of features in Drupal. A feature is a collection of Drupal
+ * entities which taken together satisfy a certain use-case.
+ */
+
+define('FEATURES_API', '2');
+
+define('FEATURES_MODULE_ENABLED', 1);
+define('FEATURES_MODULE_DISABLED', 0);
+define('FEATURES_MODULE_MISSING', -1);
+define('FEATURES_MODULE_CONFLICT', 2);
+
+define('FEATURES_REBUILDABLE', -1);
+define('FEATURES_DEFAULT', 0);
+define('FEATURES_OVERRIDDEN', 1);
+define('FEATURES_NEEDS_REVIEW', 2);
+define('FEATURES_REBUILDING', 3);
+define('FEATURES_CONFLICT', 4);
+define('FEATURES_DISABLED', 5);
+define('FEATURES_CHECKING', 6);
+define('FEATURES_ALTER_TYPE_NORMAL', 'normal');
+define('FEATURES_ALTER_TYPE_INLINE', 'inline');
+define('FEATURES_ALTER_TYPE_NONE', 'none');
+
+// Duration of rebuild semaphore: 10 minutes.
+define('FEATURES_SEMAPHORE_TIMEOUT', 10 * 60);
+
+/**
+ * Components with this 'default_file' flag will have exports written to the
+ * common defaults file 'MODULENAME.features.inc'. This is the default
+ * behavior.
+ */
+define('FEATURES_DEFAULTS_INCLUDED_COMMON', 0);
+
+/**
+ * Components with this 'default_file' flag will have exports written to a
+ * defaults based on the component name like 'MODULENAME.features.COMPONENT-NAME.inc'.
+ * Any callers to this component's defaults hook must call
+ * features_include_defaults('component') in order to include this file.
+ */
+define('FEATURES_DEFAULTS_INCLUDED', 1);
+
+/**
+ * Components with this 'default_file' flag must specify a filename for their
+ * exports. Additionally a stub will NOT be written to 'MODULENAME.features.inc'
+ * allowing the file to be included directly by the implementing module.
+ */
+define('FEATURES_DEFAULTS_CUSTOM', 2);
+
+/**
+ * Components with this 'duplicates' flag may not have multiple features provide the
+ * same component key in their info files. This is the default behavior.
+ */
+define('FEATURES_DUPLICATES_CONFLICT', 0);
+
+/**
+ * Components with this 'duplicates' flag are allowed to have multiple features
+ * provide the same component key in their info files.
+ */
+define('FEATURES_DUPLICATES_ALLOWED', 1);
+
+/**
+ * Implements hook_menu().
+ */
+function features_menu() {
+  $items = array();
+  $items['admin/structure/features'] = array(
+    'title' => 'Features',
+    'description' => 'Manage features.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('features_admin_form'),
+    'type' => MENU_NORMAL_ITEM,
+    'file' => 'features.admin.inc',
+  );
+  $items['admin/structure/features/cleanup'] = array(
+    'title' => 'Cleanup',
+    'description' => 'Clear cache after enabling/disabling a feature.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('features_cleanup_form', 4),
+    'type' => MENU_CALLBACK,
+    'file' => 'features.admin.inc',
+    'weight' => 1,
+  );
+  $items['admin/structure/features/manage'] = array(
+    'title' => 'Manage',
+    'description' => 'Enable and disable features.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('features_admin_form'),
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'file' => 'features.admin.inc',
+  );
+  $items['admin/structure/features/create'] = array(
+    'title' => 'Create feature',
+    'description' => 'Create a new feature.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('features_export_form'),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer features'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => "features.admin.inc",
+    'weight' => 10,
+  );
+  $items['admin/structure/features/settings'] = array(
+    'title' => 'Settings',
+    'description' => 'Adjust settings for using features module.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('features_settings_form'),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer features'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => "features.admin.inc",
+    'weight' => 11,
+  );
+
+
+  $items['admin/structure/features/%feature'] = array(
+    'title callback' => 'features_get_feature_title',
+    'title arguments' => array(3),
+    'description' => 'Display components of a feature.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('features_admin_components', 3),
+    'load arguments' => array(3, TRUE),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer features'),
+    'type' => MENU_CALLBACK,
+    'file' => 'features.admin.inc',
+  );
+  $items['admin/structure/features/%feature/view'] = array(
+    'title' => 'View',
+    'description' => 'Display components of a feature.',
+    'access callback' => 'user_access',
+    'access arguments' => array('administer features'),
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/structure/features/%feature/recreate'] = array(
+    'title' => 'Recreate',
+    'description' => 'Recreate an existing feature.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('features_export_form', 3),
+    'load arguments' => array(3, TRUE),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer features'),
+    'type' => MENU_LOCAL_TASK,
+    'file' => "features.admin.inc",
+    'weight' => 11,
+  );
+  if (module_exists('diff')) {
+    $items['admin/structure/features/%feature/diff'] = array(
+      'title' => 'Review overrides',
+      'description' => 'Compare default and current feature.',
+      'page callback' => 'features_feature_diff',
+      'page arguments' => array(3, 5),
+      'load arguments' => array(3, TRUE),
+      'access callback' => 'features_access_override_actions',
+      'access arguments' => array(3),
+      'type' => MENU_LOCAL_TASK,
+      'file' => 'features.admin.inc',
+    );
+  }
+  $items['admin/structure/features/%feature/status'] = array(
+    'title' => 'Status',
+    'description' => 'Javascript status call back.',
+    'page callback' => 'features_feature_status',
+    'page arguments' => array(3),
+    'load arguments' => array(3, TRUE),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer features'),
+    'type' => MENU_CALLBACK,
+    'file' => 'features.admin.inc',
+  );
+  $items['features/autocomplete/packages'] = array(
+    'page callback' => 'features_autocomplete_packages',
+    'access arguments' => array('administer features'),
+    'type' => MENU_CALLBACK,
+    'file' => 'features.admin.inc',
+  );
+  $items['features/ajaxcallback/%'] = array(
+    'title callback' => 'features_get_feature_components',
+    'description' => 'Return components of a feature.',
+    'page callback' => 'features_export_components_json',
+    'page arguments' => array(2),
+    'access callback' => 'user_access',
+    'access arguments' => array('administer features'),
+    'type' => MENU_CALLBACK,
+    'file' => 'features.admin.inc',
+  );
+  foreach ($items as $path => $item) {
+    if (!isset($item['access callback'])) {
+      $items[$path]['access callback'] = 'user_access';
+      $items[$path]['access arguments'] = array('manage features');
+    }
+  }
+  return $items;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function features_theme() {
+  $base = array(
+    'path' => drupal_get_path('module', 'features') . '/theme',
+    'file' => 'theme.inc',
+  );
+
+  $items = array();
+  $items['features_module_status'] = array(
+    'variables' => array('module' => null, 'status' => null)
+  ) + $base;
+
+  $items['features_components'] = array(
+    'variables' => array('info' => null, 'sources' => null),
+  ) + $base;
+
+  $items['features_component_key'] = $base;
+  $items['features_component_list'] = array(
+    'variables' => array('components' => array(), 'source' => array(), 'conflicts' => array()),
+  ) + $base;
+
+  $items['features_storage_link'] = array(
+    'variables' => array('storage' => null, 'text' => null, 'path' => null, 'options' => array()),
+  ) + $base;
+
+  $items['features_form_components'] =
+  $items['features_form_export'] =
+  $items['features_form_package'] = array(
+    'render element' => 'form',
+  ) + $base;
+
+  $items['features_form_buttons'] = array(
+    'render element' => 'element',
+  ) + $base;
+
+
+  $items['features_admin_components'] = array(
+    'render element' => 'form',
+    'template' => 'features-admin-components',
+  ) + $base;
+
+  return $items;
+}
+
+/**
+ * Implements hook_flush_caches().
+ */
+function features_flush_caches() {
+  if (variable_get('features_rebuild_on_flush', TRUE)) {
+    features_rebuild();
+    // Don't flush the modules cache during installation, for performance reasons.
+    if (variable_get('install_task') == 'done') {
+      features_get_modules(NULL, TRUE);
+    }
+  }
+  return array();
+}
+
+/**
+ * Implements hook_form().
+ */
+function features_form($node, $form_state) {
+  return node_content_form($node, $form_state);
+}
+
+/**
+ * Implements hook_permission().
+ */
+function features_permission() {
+  return array(
+    'administer features' => array(
+      'title' => t('Administer features'),
+      'description' => t('Perform administration tasks on features.'),
+      'restrict access' => TRUE,
+    ),
+    'manage features' => array(
+      'title' => t('Manage features'),
+      'description' => t('View, enable and disable features.'),
+      'restrict access' => TRUE,
+    ),
+    'generate features' => array(
+      'title' => t('Generate features'),
+      'description' => t('Allow feature exports to be generated and written directly to site.'),
+      'restrict access' => TRUE,
+    ),
+  );
+}
+
+/**
+ * Implements hook_help().
+ */
+function features_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#features':
+      $output = file_get_contents(drupal_get_path('module', 'features') .'/README.txt');
+      return module_exists('markdown') ? filter_xss_admin(module_invoke('markdown', 'filter', 'process', 0, -1, $output)) : '<pre>'. check_plain($output) .'</pre>';
+    case 'admin/build/features':
+      return '<p>'. t('A "Feature" is a certain type of Drupal module which contains a package of configuration that, when enabled, provides a new set of functionality for your Drupal site. Enable features by selecting the checkboxes below and clicking the Save configuration button. If the configuration of the feature has been changed its "State" will be either "overridden" or "needs review", otherwise it will be "default", indicating that the configuration has not been changed. Click on the state to see more details about the feature and its components.') .'</p>';
+  }
+}
+
+/**
+ * Implements hook_modules_disabled().
+ */
+function features_modules_disabled($modules) {
+  // Go through all modules and gather features that can be disabled.
+  $items = array();
+  foreach ($modules as $module) {
+    if ($feature = features_load_feature($module)) {
+      $items[$module] = array_keys($feature->info['features']);
+    }
+  }
+
+  if (!empty($items)) {
+    _features_restore('disable', $items);
+    // Rebuild the list of features includes.
+    features_include(TRUE);
+  }
+}
+
+/**
+ * Implements hook_modules_enabled().
+ */
+function features_modules_enabled($modules) {
+  // Go through all modules and gather features that can be enabled.
+  $items = array();
+  foreach ($modules as $module) {
+    if ($feature = features_load_feature($module)) {
+      $items[$module] = array_keys($feature->info['features']);
+    }
+  }
+
+  if (!empty($items)) {
+    _features_restore('enable', $items);
+    // Rebuild the list of features includes.
+    features_include(TRUE);
+  }
+}
+
+/**
+ * Load includes for any modules that implement the features API and
+ * load includes for those provided by features.
+ */
+function features_include($reset = FALSE) {
+  static $once;
+  if (!isset($once) || $reset) {
+    $once = TRUE;
+
+    // Features provides integration on behalf of these modules.
+    // The features include provides handling for the feature dependencies.
+    // Note that ctools is placed last because it implements hooks "dynamically" for other modules.
+    $modules = array('features', 'block', 'context', 'field', 'filter', 'image', 'locale', 'menu', 'node', 'taxonomy', 'user', 'views', 'ctools');
+
+    foreach (array_filter($modules, 'module_exists') as $module) {
+      module_load_include('inc', 'features', "includes/features.$module");
+    }
+
+    if (module_exists('ctools')) {
+      // Finally, add ctools eval'd implementations.
+      ctools_features_declare_functions($reset);
+    }
+
+    // Clear static cache, since we've now included new implementers.
+    foreach (features_get_components(NULL, 'file', $reset) as $file) {
+      if (is_file(DRUPAL_ROOT . '/' . $file)) {
+        require_once DRUPAL_ROOT . '/' . $file;
+      }
+    }
+  }
+}
+
+/**
+ * Load features includes for all components that require includes before
+ * collecting defaults.
+ */
+function features_include_defaults($components = NULL, $reset = FALSE) {
+  static $included = array();
+  static $include_components;
+
+  // Build an array of components that require inclusion:
+  // Views, CTools components and those using FEATURES_DEFAULTS_INCLUDED.
+  if (!isset($include_components) || $reset) {
+    $include_components = features_get_components();
+    foreach ($include_components as $component => $info) {
+      if (!isset($info['api']) && (!isset($info['default_file']) || $info['default_file'] !== FEATURES_DEFAULTS_INCLUDED)) {
+        unset($include_components[$component]);
+      }
+    }
+  }
+
+  // If components are specified, only include for the specified components.
+  if (isset($components)) {
+    $components = is_array($components) ? $components : array($components);
+  }
+  // Use all include components if none are explicitly specified.
+  else {
+    $components = array_keys($include_components);
+  }
+  foreach ($components as $component) {
+    if (isset($include_components[$component]) && (!isset($included[$component]) || $reset)) {
+      $info = $include_components[$component];
+      // Inclusion of ctools components.
+      if (isset($info['api'], $info['module'], $info['current_version'])) {
+        ctools_include('plugins');
+        ctools_plugin_api_include($info['module'], $info['api'], $info['current_version'], $info['current_version']);
+      }
+      // Inclusion of defaults for components using FEATURES_DEFAULTS_INCLUDED.
+      else {
+        $features = isset($features) ? $features : features_get_features(NULL, $reset);
+        foreach ($features as $feature) {
+          $filename = isset($info['default_file']) && $info['default_file'] == FEATURES_DEFAULTS_CUSTOM ? $info['default_filename'] : "features.{$component}";
+          if (module_exists($feature->name) && isset($feature->info['features'][$component])) {
+            module_load_include('inc', $feature->name, "{$feature->name}.$filename");
+          }
+        }
+      }
+      $included[$component] = TRUE;
+    }
+  }
+}
+
+/**
+ * Feature object loader.  DEPRECATED but included for backwards compatibility
+ */
+function feature_load($name, $reset = FALSE) {
+  return features_load_feature($name, $reset);
+}
+
+/**
+ * Feature object loader.
+ */
+function features_load_feature($name, $reset = FALSE) {
+  // Use an alternative code path during installation, for better performance.
+  if (variable_get('install_task') != 'done') {
+    static $features;
+
+    if (!isset($features[$name])) {
+      // Set defaults for module info.
+      $defaults = array(
+        'dependencies' => array(),
+        'description' => '',
+        'package' => 'Other',
+        'version' => NULL,
+        'php' => DRUPAL_MINIMUM_PHP,
+        'files' => array(),
+        'bootstrap' => 0,
+      );
+      $info = drupal_parse_info_file(drupal_get_path('module', $name) . '/' . $name . '.info');
+
+      $features[$name] = FALSE;
+      if (!empty($info['features']) && empty($info['hidden'])) {
+        // Build a fake file object with the data needed during installation.
+        $features[$name] = new stdClass;
+        $features[$name]->name = $name;
+        $features[$name]->filename = drupal_get_path('module', $name) . '/' . $name . '.module';
+        $features[$name]->type = 'module';
+        $features[$name]->info = $info + $defaults;
+      }
+    }
+
+    return $features[$name];
+  }
+  else {
+    return features_get_features($name, $reset);
+  }
+}
+
+/**
+ * Return a module 'object' including .info information.
+ *
+ * @param $name
+ *   The name of the module to retrieve information for. If ommitted,
+ *   an array of all available modules will be returned.
+ * @param $reset
+ *   Whether to reset the cache.
+ *
+ * @return
+ *   If a module is request (and exists) a module object is returned. If no
+ *   module is requested info for all modules is returned.
+ */
+function features_get_modules($name = NULL, $reset = FALSE) {
+  return features_get_info('module', $name, $reset);
+}
+
+/**
+ * Returns the array of supported components.
+ *
+ * @see hook_features_api
+ *
+ * @param $component
+ *   A specific type of component that supports features.
+ * @param $key
+ *   A key that hook_features_api supports.
+ *
+ * @return An array of component labels keyed by the component names.
+ */
+function features_get_components($component = NULL, $key = NULL, $reset = FALSE) {
+  features_include();
+  $components = &drupal_static(__FUNCTION__);
+  $component_by_key = &drupal_static(__FUNCTION__ . '_by_key');
+
+  if ($reset || !isset($components) || !isset($component_by_key)) {
+    $components = $component_by_key = array();
+    if (!$reset && ($cache = cache_get('features_api'))) {
+      $components = $cache->data;
+    }
+    else {
+      $components = module_invoke_all('features_api');
+      drupal_alter('features_api', $components);
+      cache_set('features_api', $components);
+    }
+
+    foreach ($components as $component_type => $component_information) {
+      foreach ($component_information as $component_key => $component_value) {
+        $component_by_key[$component_key][$component_type] = $component_value;
+      }
+    }
+  }
+
+  if ($key && $component) {
+    return !empty($components[$component][$key]) ? $components[$component][$key] : NULL;
+  }
+  elseif ($key) {
+    return !empty($component_by_key[$key]) ? $component_by_key[$key] : array();
+  }
+  elseif ($component) {
+    return $components[$component];
+  }
+  return $components;
+}
+
+/**
+ * Returns components that are offered as an option on feature creation.
+ */
+function features_get_feature_components() {
+  return array_intersect_key(features_get_components(), array_filter(features_get_components(NULL, 'feature_source')));
+}
+
+/**
+ * Invoke a component callback.
+ */
+function features_invoke($component, $callback) {
+  $args = func_get_args();
+  unset($args[0], $args[1]);
+  // Append the component name to the arguments.
+  $args[] = $component;
+  if ($function = features_hook($component, $callback)) {
+    return call_user_func_array($function, $args);
+  }
+}
+
+/**
+ * Checks whether a component implements the given hook.
+ *
+ * @return
+ *   The function implementing the hook, or FALSE.
+ */
+function features_hook($component, $hook, $reset = FALSE) {
+  // Determine the function callback base.
+  $base = features_get_components($component, 'base');
+  $base = isset($base) ? $base : $component;
+  return function_exists($base . '_' . $hook) ? $base . '_' . $hook : FALSE;
+}
+
+/**
+ * Enables and installs an array of modules, ignoring those
+ * already enabled & installed. Consider this a helper or
+ * extension to drupal_install_modules().
+ *
+ * @param $modules
+ *   An array of modules to install.
+ * @param $reset
+ *   Clear the module info cache.
+ */
+function features_install_modules($modules) {
+  module_load_include('inc', 'features', 'features.export');
+  $files = system_rebuild_module_data();
+
+  // Build maximal list of dependencies.
+  $install = array();
+  foreach ($modules as $name) {
+    // Parse the dependency string into the module name and version information.
+    $parsed_name = drupal_parse_dependency($name);
+    $name = $parsed_name['name'];
+    if ($file = $files[$name]) {
+      $install[] = $name;
+      if (!empty($file->info['dependencies'])) {
+        $install = array_merge($install, _features_export_maximize_dependencies($file->info['dependencies']));
+      }
+    }
+  }
+
+  // Filter out enabled modules.
+  $enabled = array_filter($install, 'module_exists');
+  $install = array_diff($install, $enabled);
+
+  if (!empty($install)) {
+    // Make sure the install API is available.
+    $install = array_unique($install);
+    include_once DRUPAL_ROOT . '/' . './includes/install.inc';
+    module_enable($install);
+  }
+}
+
+/**
+ * Wrapper around features_get_info() that returns an array
+ * of module info objects that are features.
+ */
+function features_get_features($name = NULL, $reset = FALSE) {
+  return features_get_info('feature', $name, $reset);
+}
+
+/**
+ * Helper for retrieving info from system table.
+ */
+function features_get_info($type = 'module', $name = NULL, $reset = FALSE) {
+  static $cache;
+  if (!isset($cache)) {
+    $cache = cache_get('features_module_info');
+  }
+  if (empty($cache) || $reset) {
+    $data = array(
+      'feature' => array(),
+      'module' => array(),
+    );
+    $ignored = variable_get('features_ignored_orphans', array());
+    $files = system_rebuild_module_data();
+
+    foreach ($files as $row) {
+      // Avoid false-reported feature overrides for php = 5.2.4 line in .info file.
+      if (isset($row->info['php'])) {
+        unset($row->info['php']);
+      }
+      // If module is no longer enabled, remove it from the ignored orphans list.
+      if (in_array($row->name, $ignored, TRUE) && !$row->status) {
+        $key = array_search($row->name, $ignored, TRUE);
+        unset($ignored[$key]);
+      }
+
+      if (!empty($row->info['features'])) {
+        // Fix css/js paths
+        if (!empty($row->info['stylesheets'])) {
+          foreach($row->info['stylesheets'] as $media => $css) {
+            $row->info['stylesheets'][$media] = array_keys($css);
+          }
+        }
+        if (!empty($row->info['scripts'])) {
+          $row->info['scripts'] = array_keys($row->info['scripts']);
+        }
+        // Rework the features array, to change the vocabulary permission
+        // features.
+        foreach ($row->info['features'] as $component => $features) {
+          if ($component == 'user_permission') {
+            foreach ($features as $key => $feature) {
+              // Export vocabulary permissions using the machine name, instead
+              // of vocabulary id.
+              _user_features_change_term_permission($feature);
+              $row->info['features'][$component][$key] = $feature;
+            }
+          }
+        }
+        $data['feature'][$row->name] = $row;
+      }
+      $data['module'][$row->name] = $row;
+    }
+
+    // Sort features according to dependencies.
+    // @see install_profile_modules()
+    $required = array();
+    $non_required = array();
+
+    $modules = array_keys($data['feature']);
+    foreach ($modules as $module) {
+      if ($files[$module]->requires) {
+        $modules = array_merge($modules, array_keys($files[$module]->requires));
+      }
+    }
+    $modules = array_unique($modules);
+    foreach ($modules as $module) {
+      if (!empty($files[$module]->info['features'])) {
+        if (!empty($files[$module]->info['required'])) {
+          $required[$module] = $files[$module]->sort;
+        }
+        else {
+          $non_required[$module] = $files[$module]->sort;
+        }
+      }
+    }
+    arsort($required);
+    arsort($non_required);
+
+    $sorted = array();
+    foreach ($required + $non_required as $module => $weight) {
+      $sorted[$module] = $data['feature'][$module];
+    }
+    $data['feature'] = $sorted;
+
+    variable_set('features_ignored_orphans', $ignored);
+    cache_set("features_module_info", $data);
+    $cache = new stdClass();
+    $cache->data = $data;
+  }
+  if (!empty($name)) {
+    return !empty($cache->data[$type][$name]) ? clone $cache->data[$type][$name] : array();
+  }
+  return !empty($cache->data[$type]) ? $cache->data[$type] : array();
+}
+
+/**
+ * Generate an array of feature dependencies that have been orphaned.
+ */
+function features_get_orphans($reset = FALSE) {
+  static $orphans;
+  if (!isset($orphans) || $reset) {
+    module_load_include('inc', 'features', 'features.export');
+    $orphans = array();
+
+    // Build a list of all dependencies for enabled and disabled features.
+    $dependencies = array('enabled' => array(), 'disabled' => array());
+    $features = features_get_features();
+    foreach ($features as $feature) {
+      $key = module_exists($feature->name) ? 'enabled' : 'disabled';
+      if (!empty($feature->info['dependencies'])) {
+        $dependencies[$key] = array_merge($dependencies[$key], _features_export_maximize_dependencies($feature->info['dependencies']));
+      }
+    }
+    $dependencies['enabled'] = array_unique($dependencies['enabled']);
+    $dependencies['disabled'] = array_unique($dependencies['disabled']);
+
+    // Find the list of orphaned modules.
+    $orphaned = array_diff($dependencies['disabled'], $dependencies['enabled']);
+    $orphaned = array_intersect($orphaned, module_list(FALSE, FALSE));
+    $orphaned = array_diff($orphaned, drupal_required_modules());
+    $orphaned = array_diff($orphaned, array('features'));
+
+    // Build final list of modules that can be disabled.
+    $modules = features_get_modules(NULL, TRUE);
+    $enabled = module_list();
+    _module_build_dependencies($modules);
+
+    foreach ($orphaned as $module) {
+      if (!empty($modules[$module]->required_by)) {
+        foreach ($modules[$module]->required_by as $module_name => $dependency) {
+          $modules[$module]->required_by[$module_name] = $dependency['name'];
+        }
+        // Determine whether any dependents are actually enabled.
+        $dependents = array_intersect($modules[$module]->required_by, $enabled);
+        if (empty($dependents)) {
+          $info = features_get_modules($module);
+          $orphans[$module] = $info;
+        }
+      }
+    }
+  }
+  return $orphans;
+}
+
+/**
+ * Detect potential conflicts between any features that provide
+ * identical components.
+ */
+function features_get_conflicts($reset = FALSE) {
+  $conflicts = array();
+  $component_info = features_get_components();
+  $map = features_get_component_map(NULL, $reset);
+
+  foreach ($map as $type => $components) {
+    // Only check conflicts for components we know about.
+    if (isset($component_info[$type])) {
+      foreach ($components as $component => $modules) {
+        if (isset($component_info[$type]['duplicates']) && $component_info[$type]['duplicates'] == FEATURES_DUPLICATES_ALLOWED) {
+          continue;
+        }
+        else if (count($modules) > 1) {
+          foreach ($modules as $module) {
+            if (!isset($conflicts[$module])) {
+              $conflicts[$module] = array();
+            }
+            foreach ($modules as $m) {
+              if ($m != $module) {
+                $conflicts[$module][$m][$type][] = $component;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return $conflicts;
+}
+
+/**
+ * Provide a component to feature map.
+ */
+function features_get_component_map($key = NULL, $reset = FALSE) {
+  static $map;
+  if (!isset($map) || $reset) {
+    $map = array();
+    $features = features_get_features(NULL, $reset);
+    foreach ($features as $feature) {
+      foreach ($feature->info['features'] as $type => $components) {
+        if (!isset($map[$type])) {
+          $map[$type] = array();
+        }
+        foreach ($components as $component) {
+          $map[$type][$component][] = $feature->name;
+        }
+      }
+    }
+  }
+  if (isset($key)) {
+    return isset($map[$key]) ? $map[$key] : array();
+  }
+  return $map;
+}
+
+/**
+ * Simple wrapper returns the status of a module.
+ */
+function features_get_module_status($module) {
+  if (module_exists($module)) {
+    return FEATURES_MODULE_ENABLED;
+  }
+  else if (features_get_modules($module)) {
+    return FEATURES_MODULE_DISABLED;
+  }
+  else {
+    return FEATURES_MODULE_MISSING;
+  }
+}
+
+/**
+ * Menu title callback.
+ */
+function features_get_feature_title($feature) {
+  return $feature->info['name'];
+}
+
+/**
+ * Menu access callback for whether a user should be able to access
+ * override actions for a given feature.
+ */
+function features_access_override_actions($feature) {
+  if (user_access('administer features')) {
+    static $access = array();
+    if (!isset($access[$feature->name])) {
+      // Set a value first. We may get called again from within features_detect_overrides().
+      $access[$feature->name] = FALSE;
+
+      features_include();
+      module_load_include('inc', 'features', 'features.export');
+      $access[$feature->name] = in_array(features_get_storage($feature->name), array(FEATURES_OVERRIDDEN, FEATURES_NEEDS_REVIEW)) && user_access('administer features');
+    }
+    return $access[$feature->name];
+  }
+  return FALSE;
+}
+
+/**
+ * Implements hook_form_alter() for system_modules form().
+ */
+function features_form_system_modules_alter(&$form) {
+  features_rebuild();
+}
+
+/**
+ * Restore the specified modules to the default state.
+ */
+function _features_restore($op, $items = array()) {
+  // Set this variable in $conf if having timeout issues during install/rebuild.
+  if (variable_get('features_restore_time_limit_' . $op, FALSE) !== FALSE) {
+    drupal_set_time_limit(variable_get('features_restore_time_limit_' . $op, FALSE));
+  }
+
+  module_load_include('inc', 'features', 'features.export');
+  features_include();
+
+  switch ($op) {
+    case 'revert':
+      $restore_states = array(FEATURES_OVERRIDDEN, FEATURES_REBUILDABLE, FEATURES_NEEDS_REVIEW);
+      $restore_hook = 'features_revert';
+      $log_action = 'Revert';
+      break;
+    case 'rebuild':
+      $restore_states = array(FEATURES_REBUILDABLE);
+      $restore_hook = 'features_rebuild';
+      $log_action = 'Rebuild';
+      break;
+    case 'disable':
+      $restore_hook = 'features_disable_feature';
+      $log_action = 'Disable';
+      break;
+    case 'enable':
+      $restore_hook = 'features_enable_feature';
+      $log_action = 'Enable';
+      break;
+  }
+
+  if (empty($items)) {
+    // Drush may execute a whole chain of commands that may trigger feature
+    // rebuilding multiple times during a single request. Make sure we do not
+    // rebuild the same cached list of modules over and over again by setting
+    // $reset to TRUE.
+    // Note: this may happen whenever more than one feature will be enabled
+    // in chain, for example also using features_install_modules().
+    $states = features_get_component_states(array(), ($op == 'rebuild'), defined('DRUSH_BASE_PATH'));
+    foreach ($states as $module_name => $components) {
+      foreach ($components as $component => $state) {
+        if (in_array($state, $restore_states)) {
+          $items[$module_name][] = $component;
+        }
+      }
+    }
+  }
+
+  foreach ($items as $module_name => $components) {
+    foreach ($components as $component) {
+      // Invoke pre hook
+      $pre_hook = 'pre_' . $restore_hook;
+      module_invoke($module_name, $pre_hook, $component);
+
+      if (features_hook($component, $restore_hook)) {
+        // Set a semaphore to prevent other instances of the same script from running concurrently.
+        watchdog('features', '@actioning @module_name / @component.', array('@action' => $log_action, '@component' => $component, '@module_name' => $module_name));
+        features_semaphore('set', $component);
+        features_invoke($component, $restore_hook, $module_name);
+
+        // If the script completes, remove the semaphore and set the code signature.
+        features_semaphore('del', $component);
+        features_set_signature($module_name, $component);
+        watchdog('features', '@action completed for @module_name / @component.', array('@action' => $log_action, '@component' => $component, '@module_name' => $module_name));
+      }
+
+      // Invoke post hook
+      $post_hook = 'post_' . $restore_hook;
+      module_invoke($module_name, $post_hook, $component);
+    }
+  }
+}
+
+/**
+ * Wrapper around _features_restore().
+ */
+function features_revert($revert = array()) {
+  return _features_restore('revert', $revert);
+}
+
+/**
+ * Wrapper around _features_restore().
+ */
+function features_rebuild($rebuild = array()) {
+  return _features_restore('rebuild', $rebuild);
+}
+
+/**
+ * Revert a single features module.
+ *
+ * @param string $module
+ *   A features module machine name. This module must be a
+ *   features module and enabled.
+ */
+function features_revert_module($module) {
+  if (($feature = feature_load($module, TRUE)) && module_exists($module)) {
+    $components = array();
+    foreach (array_keys($feature->info['features']) as $component) {
+      if (features_hook($component, 'features_revert')) {
+        $components[] = $component;
+      }
+    }
+    features_revert(array($module => $components));
+  }
+}
+
+/**
+ * Utility functions ==================================================
+ */
+
+/**
+ * Log a message, environment agnostic.
+ *
+ * @param $message
+ *   The message to log.
+ * @param $severity
+ *   The severity of the message: status, warning or error.
+ */
+function features_log($message, $severity = 'status') {
+  if (function_exists('drush_verify_cli')) {
+    $message = strip_tags($message);
+    if ($severity == 'status') {
+      $severity = 'ok';
+    }
+    elseif ($severity == 'error') {
+      drush_set_error($message);
+      return;
+    }
+    drush_log($message, $severity);
+    return;
+  }
+  drupal_set_message($message, $severity, FALSE);
+}
+
+/**
+ * Implements hook_hook_info().
+ */
+function features_hook_info() {
+  $hooks = array(
+    'features_api',
+    'features_pipe_alter',
+    'features_export_alter',
+  );
+  return array_fill_keys($hooks, array('group' => 'features'));
+}
+
+/**
+ * Change vocabularies permission, from vocab id to machine name and vice versa.
+ */
+function _user_features_change_term_permission(&$perm, $type = 'vid') {
+  // Export vocabulary permissions using the machine name, instead of vocabulary
+  // id.
+  if (strpos($perm, 'edit terms in ') !== FALSE || strpos($perm, 'delete terms in ') !== FALSE) {
+    preg_match("/(?<=\040)([^\s]+?)$/", trim($perm), $voc_id);
+    $vid = $voc_id[0];
+    if (is_numeric($vid) && $type == 'vid') {
+      if (function_exists('taxonomy_vocabulary_load')) {
+        if ($voc = taxonomy_vocabulary_load($vid)) {
+          $perm = str_replace($vid, $voc->machine_name, $perm);
+        }
+      }
+    }
+    elseif ($type == 'machine_name') {
+      if ($voc = taxonomy_vocabulary_machine_name_load($vid)) {
+        $perm = str_replace($vid, $voc->vid, $perm);
+      }
+    }
+  }
+}
+
+/**
+ * Recursively computes the difference of arrays with additional index check.
+ *
+ * This is a version of array_diff_assoc() that supports multidimensional
+ * arrays.
+ *
+ * @param array $array1
+ *   The array to compare from.
+ * @param array $array2
+ *   The array to compare to.
+ *
+ * @return array
+ *   Returns an array containing all the values from array1 that are not present
+ *   in array2.
+ */
+function features_array_diff_assoc_recursive(array $array1, array $array2) {
+  $difference = array();
+  foreach ($array1 as $key => $value) {
+    if (is_array($value)) {
+      if (!isset($array2[$key]) || !is_array($array2[$key])) {
+        $difference[$key] = $value;
+      }
+      else {
+        $new_diff = features_array_diff_assoc_recursive($value, $array2[$key]);
+        if (!empty($new_diff)) {
+          $difference[$key] = $new_diff;
+        }
+      }
+    }
+    elseif (!isset($array2[$key]) || $array2[$key] != $value) {
+      $difference[$key] = $value;
+    }
+  }
+  return $difference;
+}
+
+/**
+ * Returns an array of deprecated components
+ * Rather than deprecating the component directly, we look for other components
+ * that supersedes the component
+ * @param $components
+ *   The array of components (component_info) from features_get_components typically.
+ */
+function features_get_deprecated($components = array()) {
+  if (empty($components)) {
+    $components = features_get_components();
+  }
+  $deprecated = array();
+  foreach ($components as $component => $component_info) {
+    if (!empty($component_info['supersedes'])) {
+      $deprecated[$component_info['supersedes']] = $component_info['supersedes'];
+    }
+  }
+  return $deprecated;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.block.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function block_features_api() {
+  return array();
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function block_features_export($data, &$export) {
+  $pipe = array();
+  foreach ($data as $bid) {
+    $split = explode('-', $bid);
+    $module = array_shift($split);
+    $delta = implode('-', $split);
+
+    $export['dependencies'][$module] = $module;
+
+    switch ($module) {
+      case 'views':
+        if (strlen($delta) == 32) {
+          $hashes = variable_get('views_block_hashes', array());
+          if (!empty($hashes[$delta])) {
+            $delta = $hashes[$delta];
+          }
+        }
+
+        $delta_split = explode('-', $delta);
+        $view_name = $delta_split[0];
+        if (!empty($view_name)) {
+          $pipe['views'][] = $view_name;
+        }
+        break;
+    }
+  }
+  return $pipe;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.context.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Implements hook_features_export().
+ */
+function context_features_export($data, &$export, $module_name = '') {
+  $pipe = ctools_component_features_export('context', $data, $export, $module_name);
+
+  $contexts = context_load();
+  foreach ($data as $identifier) {
+    if (isset($contexts[$identifier])) {
+      $context = $contexts[$identifier];
+      // Conditions.
+      // Currently only node and views conditions are supported.
+      // @TODO: Should this be delegated to a method on the plugin?
+      foreach (array('node', 'views') as $key) {
+        if (!empty($context->conditions{$key}['values'])) {
+          foreach ($context->conditions{$key}['values'] as $item) {
+            // Special pipe for views
+            if ($key === 'views') {
+              $split = explode(':', $item);
+              $view_name = array_shift($split);
+              $pipe[$key][$view_name] = $view_name;
+            }
+            else {
+              $pipe[$key][$item] = $item;
+            }
+          }
+        }
+      }
+      // Reactions.
+      if (!empty($context->reactions['block']['blocks'])) {
+        foreach ($context->reactions['block']['blocks'] as $block) {
+          $block = (array) $block;
+          $bid = "{$block['module']}-{$block['delta']}";
+          $pipe['block'][$bid] = $bid;
+        }
+      }
+    }
+  }
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_revert().
+ *
+ * @param $module
+ * name of module to revert content for
+ */
+function context_features_revert($module = NULL) {
+  $return = ctools_component_features_revert('context', $module);
+  context_invalidate_cache();
+  return $return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.ctools.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,378 @@
+<?php
+
+function ctools_features_declare_functions($reset = FALSE) {
+/**
+ * This is called by Features to ensure ctools component functions are defined
+ * Dynamically declare functions under a ctools component's namespace if they are not already declared.
+ */
+  if (function_exists('_ctools_features_get_info')) {
+   foreach (_ctools_features_get_info(NULL, $reset) as $component => $info) {
+      $code = '';
+      if (!function_exists("{$info['module']}_features_api")) {
+        $code .= 'function '. $info['module'] .'_features_api() { return ctools_component_features_api("'. $info['module'] .'"); }';
+      }
+
+      // ctools component with owner defined as "ctools"
+      if (!function_exists("{$component}_features_api") && $info['module'] === 'ctools') {
+        $code .= 'function '. $component .'_features_api() { return ctools_component_features_api("'. $component .'"); }';
+      }
+
+      if (!function_exists("{$component}_features_export")) {
+        $code .= 'function '. $component .'_features_export($data, &$export, $module_name = "") { return ctools_component_features_export("'. $component .'", $data, $export, $module_name); }';
+      }
+      if (!function_exists("{$component}_features_export_options")) {
+        $code .= 'function '. $component .'_features_export_options() { return ctools_component_features_export_options("'. $component .'"); }';
+      }
+      if (!function_exists("{$component}_features_export_render")) {
+        $code .= 'function '. $component .'_features_export_render($module, $data, $export = NULL) { return ctools_component_features_export_render("'. $component .'", $module, $data, $export); }';
+      }
+      if (!function_exists("{$component}_features_revert")) {
+        $code .= 'function '. $component .'_features_revert($module) { return ctools_component_features_revert("'. $component .'", $module); }';
+      }
+      eval($code);
+    }
+  }
+}
+
+/**
+ * Implements hook_features_api().
+ */
+function ctools_features_api() {
+  return array(
+    'ctools' => array(
+      'name' => 'CTools export API',
+      'feature_source' => TRUE,
+      'duplicates' => FEATURES_DUPLICATES_ALLOWED,
+      // CTools API integration does not include a default hook declaration as
+      // it is not a proper default hook.
+      // 'default_hook' => 'ctools_plugin_api',
+    ),
+  );
+}
+
+/**
+ * Implements hook_features_export().
+ * Adds references to the ctools mothership hook, ctools_plugin_api().
+ */
+function ctools_features_export($data, &$export, $module_name = '') {
+  // Add ctools dependency
+  $export['dependencies']['ctools'] = 'ctools';
+
+  // Add the actual ctools components which will need to be accounted for in
+  // hook_ctools_plugin_api(). The components are actually identified by a
+  // delimited list of values: `module_name:api:current_version`
+  foreach ($data as $component) {
+    if ($info = _ctools_features_get_info($component)) {
+      $identifier = "{$info['module']}:{$info['api']}:{$info['current_version']}";
+      $export['features']['ctools'][$identifier] = $identifier;
+    }
+  }
+
+  return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ * Adds the ctools mothership hook, ctools_plugin_api().
+ */
+function ctools_features_export_render($module, $data) {
+  $component_exports =  array();
+  foreach ($data as $component) {
+    $code = array();
+    if ($info = _ctools_features_get_info($component)) {
+      // For background on why we change the output for hook_views_api()
+      // see http://drupal.org/node/1459120.
+      if ($info['module'] == 'views') {
+        $code[] = '  return array("api" => "3.0");';
+      }
+      else {
+        $code[] = '  if ($module == "'. $info['module'] .'" && $api == "'. $info['api'] .'") {';
+        $code[] = '    return array("version" => "'. $info['current_version'] .'");';
+        $code[] = '  }';
+      }
+    }
+    ctools_include('plugins');
+    $plugin_api_hook_name = ctools_plugin_api_get_hook($info['module'], $info['api']);
+
+    if (key_exists($plugin_api_hook_name, $component_exports)) {
+      $component_exports[$plugin_api_hook_name]['code'] .= "\n" . implode("\n", $code);
+    }
+    else {
+      $component_exports[$plugin_api_hook_name] = array(
+        'code' => implode("\n", $code),
+        'args' => '$module = NULL, $api = NULL',
+      );
+    }
+  }
+
+  return $component_exports;
+
+}
+
+/**
+ * Master implementation of hook_features_api() for all ctools components.
+ *
+ * Note that this master hook does not use $component like the others, but uses the
+ * component module's namespace instead.
+ */
+function ctools_component_features_api($module_name) {
+  $api = array();
+  foreach (_ctools_features_get_info() as $component => $info) {
+    // if module owner is set to "ctools" we need to compare the component
+    if ($info['module'] == $module_name || ($info['module'] === 'ctools' && $component == $module_name) ) {
+      $api[$component] = $info;
+    }
+  }
+  return $api;
+}
+
+/**
+ * Master implementation of hook_features_export_options() for all ctools components.
+ */
+function ctools_component_features_export_options($component) {
+  $options = array();
+
+  ctools_include('export');
+  $schema = ctools_export_get_schema($component);
+  if ($schema && $schema['export']['bulk export']) {
+    if (!empty($schema['export']['list callback']) && function_exists($schema['export']['list callback'])) {
+      $options = $schema['export']['list callback']();
+    }
+    else {
+      $options = _ctools_features_export_default_list($component, $schema);
+    }
+  }
+  asort($options);
+  return $options;
+}
+
+/**
+ * Master implementation of hook_features_export() for all ctools components.
+ */
+function ctools_component_features_export($component, $data, &$export, $module_name = '') {
+  // Add the actual implementing module as a dependency
+  $info = _ctools_features_get_info();
+  if ($module_name !== $info[$component]['module']) {
+    $export['dependencies'][$info[$component]['module']] = $info[$component]['module'];
+  }
+
+  // Add the components
+  foreach ($data as $object_name) {
+    if ($object = _ctools_features_export_crud_load($component, $object_name)) {
+      // If this object is provided as a default by a different module, don't
+      // export and add that module as a dependency instead.
+      if (!empty($object->export_module) && $object->export_module !== $module_name) {
+        $export['dependencies'][$object->export_module] = $object->export_module;
+        if (isset($export['features'][$component][$object_name])) {
+          unset($export['features'][$component][$object_name]);
+        }
+      }
+      // Otherwise, add the component.
+      else {
+        $export['features'][$component][$object_name] = $object_name;
+      }
+    }
+  }
+
+  // Let CTools handle API integration for this component.
+  return array('ctools' => array($component));
+}
+
+/**
+ * Master implementation of hook_features_export_render() for all ctools components.
+ */
+function ctools_component_features_export_render($component, $module, $data) {
+  // Reset the export display static to prevent clashes.
+  drupal_static_reset('panels_export_display');
+
+  ctools_include('export');
+  $schema = ctools_export_get_schema($component);
+
+  if (function_exists($schema['export']['to hook code callback'])) {
+    $export = $schema['export']['to hook code callback']($data, $module);
+    $code = explode("{\n", $export);
+    array_shift($code);
+    $code = explode('}', implode($code, "{\n"));
+    array_pop($code);
+    $code = implode('}', $code);
+  }
+  else {
+    $code = '  $export = array();'."\n\n";
+    foreach ($data as $object_name) {
+      if ($object = _ctools_features_export_crud_load($component, $object_name)) {
+        $identifier = $schema['export']['identifier'];
+        $code .= _ctools_features_export_crud_export($component, $object, '  ');
+        $code .= "  \$export[" . ctools_var_export($object_name) . "] = \${$identifier};\n\n";
+      }
+    }
+    $code .= '  return $export;';
+  }
+
+  return array($schema['export']['default hook'] => $code);
+}
+
+/**
+ * Master implementation of hook_features_revert() for all ctools components.
+ */
+function ctools_component_features_revert($component, $module) {
+  if ($objects = features_get_default($component, $module)) {
+    foreach ($objects as $name => $object) {
+      // Some things (like views) do not use the machine name as key
+      // and need to be loaded explicitly in order to be deleted.
+      $object = ctools_export_crud_load($component, $name);
+      if ($object && ($object->export_type & EXPORT_IN_DATABASE)) {
+        _ctools_features_export_crud_delete($component, $object);
+      }
+    }
+  }
+}
+
+/**
+ * Helper function to return various ctools information for components.
+ */
+function _ctools_features_get_info($identifier = NULL, $reset = FALSE) {
+  static $components;
+  if (!isset($components) || $reset) {
+    $components = array();
+    $modules = features_get_info();
+    ctools_include('export');
+    drupal_static('ctools_export_get_schemas', NULL, $reset);
+    foreach (ctools_export_get_schemas_by_module() as $module => $schemas) {
+      foreach ($schemas as $table => $schema) {
+        if ($schema['export']['bulk export']) {
+          // Let the API owner take precedence as the owning module.
+          $api_module = isset($schema['export']['api']['owner']) ? $schema['export']['api']['owner'] : $module;
+          $components[$table] = array(
+            'name' => isset($modules[$api_module]->info['name']) ? $modules[$api_module]->info['name'] : $api_module,
+            'default_hook' => $schema['export']['default hook'],
+            'default_file' => FEATURES_DEFAULTS_CUSTOM,
+            'module' => $api_module,
+            'feature_source' => TRUE,
+          );
+          if (isset($schema['export']['api'])) {
+            $components[$table] += array(
+              'api' => $schema['export']['api']['api'],
+              'default_filename' => $schema['export']['api']['api'],
+              'current_version' => $schema['export']['api']['current_version'],
+            );
+          }
+        }
+      }
+    }
+  }
+
+  // Return information specific to a particular component.
+  if (isset($identifier)) {
+    // Identified by the table name.
+    if (isset($components[$identifier])) {
+      return $components[$identifier];
+    }
+    // New API identifier. Allows non-exportables related CTools APIs to be
+    // supported by an explicit `module:api:current_version` key.
+    else if (substr_count($identifier, ':') === 2) {
+      list($module, $api, $current_version) = explode(':', $identifier);
+      // If a schema component matches the provided identifier, provide that
+      // information. This also ensures that the version number is up to date.
+      foreach ($components as $table => $info) {
+        if ($info['module'] == $module && $info['api'] == $api && $info['current_version'] >= $current_version) {
+          return $info;
+        }
+      }
+      // Fallback to just giving back what was provided to us.
+      return array('module' => $module, 'api' => $api, 'current_version' => $current_version);
+    }
+    return FALSE;
+  }
+
+  return $components;
+}
+
+/**
+ * Wrapper around ctools_export_crud_export() for < 1.7 compatibility.
+ */
+function _ctools_features_export_crud_export($table, $object, $indent = '') {
+  return ctools_api_version('1.7') ? ctools_export_crud_export($table, $object, $indent) : ctools_export_object($table, $object, $indent);
+}
+
+/**
+ * Wrapper around ctools_export_crud_load() for < 1.7 compatibility.
+ */
+function _ctools_features_export_crud_load($table, $name) {
+  if (ctools_api_version('1.7')) {
+    return ctools_export_crud_load($table, $name);
+  }
+  elseif ($objects = ctools_export_load_object($table, 'names', array($name))) {
+    return array_shift($objects);
+  }
+  return FALSE;
+}
+
+/**
+ * Wrapper around ctools_export_default_list() for < 1.7 compatibility.
+ */
+function _ctools_features_export_default_list($table, $schema) {
+  if (ctools_api_version('1.7')) {
+    return ctools_export_default_list($table, $schema);
+  }
+  elseif ($objects = ctools_export_load_object($table, 'all')) {
+    return drupal_map_assoc(array_keys($objects));
+  }
+  return array();
+}
+
+/**
+ * Wrapper around ctools_export_crud_delete() for < 1.7 compatibility.
+ */
+function _ctools_features_export_crud_delete($table, $object) {
+  if (ctools_api_version('1.7')) {
+    ctools_export_crud_delete($table, $object);
+  }
+  else {
+    $schema = ctools_export_get_schema($table);
+    $export = $schema['export'];
+    db_query("DELETE FROM {{$table}} WHERE {$export['key']} = '%s'", $object->{$export['key']});
+  }
+}
+
+/**
+ * Implements hook_features_export_render() for page_manager.
+ */
+function page_manager_pages_features_export_render($module, $data) {
+  // Reset the export display static to prevent clashes.
+  drupal_static_reset('panels_export_display');
+
+  // Ensure that handlers have their code included before exporting.
+  page_manager_get_tasks();
+  return ctools_component_features_export_render('page_manager_pages', $module, $data);
+}
+
+/**
+ * Implements hook_features_revert() for page_manager.
+ */
+function page_manager_pages_features_revert($module) {
+  if ($pages = features_get_default('page_manager_pages', $module)) {
+    require_once drupal_get_path('module', 'ctools') . '/page_manager/plugins/tasks/page.inc';
+    foreach ($pages as $page) {
+      page_manager_page_delete($page);
+    }
+  }
+}
+
+/**
+ * Implements hook_features_pipe_COMPONENT_alter() for views_view.
+ */
+function views_features_pipe_views_view_alter(&$pipe, $data, $export) {
+  // @todo Remove this check before next stable release.
+  if (!function_exists('views_plugin_list')) {
+    return;
+  }
+
+  $map = array_flip($data);
+  foreach (views_plugin_list() as $plugin) {
+    foreach ($plugin['views'] as $view_name) {
+      if (isset($map[$view_name])) {
+        $pipe['dependencies'][$plugin['module']] = $plugin['module'];
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function features_features_api() {
+  return array(
+    'dependencies' => array(
+      'name' => 'Dependencies',
+      'feature_source' => TRUE,
+      'duplicates' => FEATURES_DUPLICATES_ALLOWED,
+    ),
+  );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function dependencies_features_export_options() {
+  // Excluded modules.
+  $excluded = drupal_required_modules();
+  $options = array();
+  foreach (features_get_modules() as $module_name => $info) {
+    if (!in_array($module_name, $excluded) && $info->status && !empty($info->info)) {
+      $options[$module_name] = $info->info['name'];
+    }
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function dependencies_features_export($data, &$export, $module_name = '') {
+  // Don't allow a module to depend upon itself.
+  if (!empty($data[$module_name])) {
+    unset($data[$module_name]);
+  }
+
+  // Clean up existing dependencies and merge.
+  $export['dependencies'] = _features_export_minimize_dependencies($export['dependencies'], $module_name);
+  $export['dependencies'] = array_merge($data, $export['dependencies']);
+  $export['dependencies'] = array_unique($export['dependencies']);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function dependencies_features_revert($module) {
+  dependencies_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ * Ensure that all of a feature's dependencies are enabled.
+ */
+function dependencies_features_rebuild($module) {
+  $feature = features_get_features($module);
+  if (!empty($feature->info['dependencies'])) {
+    $install = array();
+    foreach ($feature->info['dependencies'] as $dependency) {
+      // Parse the dependency string into the module name and version information.
+      $parsed_dependency = drupal_parse_dependency($dependency);
+      $dependency = $parsed_dependency['name'];
+      if (!module_exists($dependency)) {
+        $install[] = $dependency;
+      }
+    }
+    if (!empty($install)) {
+      features_install_modules($install);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,530 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function field_features_api() {
+  return array(
+    'field' => array(
+      // this is deprecated by field_base and field_instance
+      // but retained for compatibility with older exports
+      'name' => t('Fields'),
+      'default_hook' => 'field_default_fields',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'feature_source' => FALSE,
+    ),
+    'field_base' => array(
+      'name' => t('Field Bases'),
+      'default_hook' => 'field_default_field_bases',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'feature_source' => TRUE,
+      'supersedes' => 'field',
+    ),
+    'field_instance' => array(
+      'name' => t('Field Instances'),
+      'default_hook' => 'field_default_field_instances',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'feature_source' => TRUE,
+      'supersedes' => 'field',
+    )
+  );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function field_base_features_export_options() {
+  $options = array();
+  $fields = field_info_fields();
+  foreach ($fields as $field_name => $field) {
+    $options[$field_name] = $field_name;
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function field_instance_features_export_options() {
+  $options = array();
+  foreach (field_info_fields() as $field_name => $field) {
+    foreach ($field['bundles'] as $entity_type => $bundles) {
+      foreach ($bundles as $bundle) {
+        $identifier = "{$entity_type}-{$bundle}-{$field_name}";
+        $options[$identifier] = $identifier;
+      }
+    }
+  }
+  ksort($options);
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function field_base_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+  $map = features_get_default_map('field_base');
+
+  // The field_default_field_bases() hook integration is provided by the
+  // features module so we need to add it as a dependency.
+  $export['dependencies']['features'] = 'features';
+
+  foreach ($data as $identifier) {
+    if ($base = features_field_base_load($identifier)) {
+      // If this field is already provided by another module, remove the field
+      // and add the other module as a dependency.
+      if (isset($map[$identifier]) && $map[$identifier] != $module_name) {
+        if (isset($export['features']['field_base'][$identifier])) {
+          unset($export['features']['field_base'][$identifier]);
+        }
+        $module = $map[$identifier];
+        $export['dependencies'][$module] = $module;
+      }
+      // If the field has not yet been exported, add it
+      else {
+        $export['features']['field_base'][$identifier] = $identifier;
+        $export['dependencies'][$base['module']] = $base['module'];
+        if ($base['storage']['type'] != variable_get('field_storage_default', 'field_sql_storage')) {
+          $export['dependencies'][$base['storage']['module']] = $base['storage']['module'];
+        }
+        // If taxonomy field, add in the vocabulary
+        if ($base['type'] == 'taxonomy_term_reference' && !empty($base['settings']['allowed_values'])) {
+          foreach ($base['settings']['allowed_values'] as $allowed_values) {
+            if (!empty($allowed_values['vocabulary'])) {
+              $pipe['taxonomy'][] = $allowed_values['vocabulary'];
+            }
+          }
+        }
+      }
+    }
+  }
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function field_instance_features_export($data, &$export, $module_name = '') {
+  $pipe = array('field_base' => array());
+  $map = features_get_default_map('field_instance');
+
+  // The field_default_field_instances() hook integration is provided by the
+  // features module so we need to add it as a dependency.
+  $export['dependencies']['features'] = 'features';
+
+  foreach ($data as $identifier) {
+    if ($instance = features_field_instance_load($identifier)) {
+      // If this field is already provided by another module, remove the field
+      // and add the other module as a dependency.
+      if (isset($map[$identifier]) && $map[$identifier] != $module_name) {
+        if (isset($export['features']['field_instance'][$identifier])) {
+          unset($export['features']['field_instance'][$identifier]);
+        }
+        $module = $map[$identifier];
+        $export['dependencies'][$module] = $module;
+      }
+      // If the field has not yet been exported, add it
+      else {
+        $export['features']['field_instance'][$identifier] = $identifier;
+        $export['dependencies'][$instance['widget']['module']] = $instance['widget']['module'];
+        foreach ($instance['display'] as $key => $display) {
+          if (isset($display['module'])) {
+            $export['dependencies'][$display['module']] = $display['module'];
+            // @TODO: handle the pipe to image styles
+          }
+        }
+        $pipe['field_base'][] = $instance['field_name'];
+      }
+    }
+  }
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function field_base_features_export_render($module, $data, $export = NULL) {
+  $translatables = $code = array();
+  $code[] = '  $field_bases = array();';
+  $code[] = '';
+  foreach ($data as $identifier) {
+    if ($field = features_field_base_load($identifier)) {
+      unset($field['columns']);
+      // unset($field['locked']);
+      // Only remove the 'storage' declaration if the field is using the default
+      // storage type.
+      if ($field['storage']['type'] == variable_get('field_storage_default', 'field_sql_storage')) {
+        unset($field['storage']);
+      }
+      // If we still have a storage declaration here it means that a non-default
+      // storage type was altered into to the field definition. And noone would
+      // never need to change the 'details' key, so don't render it.
+      if (isset($field['storage']['details'])) {
+        unset($field['storage']['details']);
+      }
+
+      _field_instance_features_export_sort($field);
+      $field_export = features_var_export($field, '  ');
+      $field_identifier = features_var_export($identifier);
+      $code[] = "  // Exported field_base: {$field_identifier}";
+      $code[] = "  \$field_bases[{$field_identifier}] = {$field_export};";
+      $code[] = "";
+    }
+  }
+  $code[] = '  return $field_bases;';
+  $code = implode("\n", $code);
+  return array('field_default_field_bases' => $code);
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function field_instance_features_export_render($module, $data, $export = NULL) {
+  $translatables = $code = array();
+
+  $code[] = '  $field_instances = array();';
+  $code[] = '';
+
+  foreach ($data as $identifier) {
+    if ($instance = features_field_instance_load($identifier)) {
+      _field_instance_features_export_sort($instance);
+      $field_export = features_var_export($instance, '  ');
+      $instance_identifier = features_var_export($identifier);
+      $code[] = "  // Exported field_instance: {$instance_identifier}";
+      $code[] = "  \$field_instances[{$instance_identifier}] = {$field_export};";
+      $code[] = "";
+
+      if (!empty($instance['label'])) {
+        $translatables[] = $instance['label'];
+      }
+      if (!empty($instance['description'])) {
+        $translatables[] = $instance['description'];
+      }
+    }
+  }
+  if (!empty($translatables)) {
+    $code[] = features_translatables_export($translatables, '  ');
+  }
+  $code[] = '  return $field_instances;';
+  $code = implode("\n", $code);
+  return array('field_default_field_instances' => $code);
+}
+
+// Helper to enforce consistency in field export arrays.
+function _field_instance_features_export_sort(&$field, $sort = TRUE) {
+
+  // Some arrays are not sorted to preserve order (for example allowed_values).
+  static $sort_blacklist = array(
+      'allowed_values',
+      'format_handlers',
+  );
+
+  if ($sort) {
+    uksort($field, 'strnatcmp');
+  }
+  foreach ($field as $k => $v) {
+    if (is_array($v)) {
+      _field_instance_features_export_sort($field[$k], !in_array($k, $sort_blacklist));
+    }
+  }
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function field_base_features_revert($module) {
+  field_base_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function field_instance_features_revert($module) {
+  field_instance_features_rebuild($module);
+}
+
+/**
+ * Implements of hook_features_rebuild().
+ * Rebuilds fields from code defaults.
+ */
+function field_base_features_rebuild($module) {
+  if ($fields = features_get_default('field_base', $module)) {
+    field_info_cache_clear();
+
+    // Load all the existing field bases up-front so that we don't
+    // have to rebuild the cache all the time.
+    $existing_fields = field_info_fields();
+
+    foreach ($fields as $field) {
+      // Create or update field.
+      if (isset($existing_fields[$field['field_name']])) {
+        $existing_field = $existing_fields[$field['field_name']];
+        if ($field + $existing_field != $existing_field) {
+          field_update_field($field);
+        }
+      }
+      else {
+        field_create_field($field);
+        $existing_fields[$field['field_name']] = $field;
+      }
+      variable_set('menu_rebuild_needed', TRUE);
+    }
+  }
+}
+
+/**
+ * Implements of hook_features_rebuild().
+ * Rebuilds field instances from code defaults.
+ */
+function field_instance_features_rebuild($module) {
+  if ($instances = features_get_default('field_instance', $module)) {
+    field_info_cache_clear();
+
+    // Load all the existing instances up-front so that we don't
+    // have to rebuild the cache all the time.
+    $existing_instances = field_info_instances();
+
+    foreach ($instances as $field_instance) {
+      // If the field base information does not exist yet, cancel out.
+      if (!field_info_field($field_instance['field_name'])) {
+        continue;
+      }
+
+      // Create or update field instance.
+      if (isset($existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']])) {
+        $existing_instance = $existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']];
+        if ($field_instance + $existing_instance != $existing_instance) {
+          try {
+            field_update_instance($field_instance);
+          }
+          catch (FieldException $e) {
+            watchdog('features', 'Attempt to update field instance %label (in %entity entity type %bundle bundle) failed: %message', array('%label' => $field_instance['field_name'], '%entity' => $field_instance['entity_type'], '%bundle' => $field_instance['bundle'], '%message' => $e->getMessage()), WATCHDOG_ERROR);
+          }
+        }
+      }
+      else {
+        try {
+          field_create_instance($field_instance);
+        }
+        catch (FieldException $e) {
+          watchdog('features', 'Attempt to create field instance %label (in %entity entity type %bundle bundle) failed: %message', array('%label' => $field_instance['field_name'], '%entity' => $field_instance['entity_type'], '%bundle' => $field_instance['bundle'], '%message' => $e->getMessage()), WATCHDOG_ERROR);
+        }
+        $existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']] = $field_instance;
+      }
+    }
+
+    if ($instances) {
+      variable_set('menu_rebuild_needed', TRUE);
+    }
+  }
+}
+
+/**
+ * Load a field base configuration by a field_name identifier.
+ */
+function features_field_base_load($field_name) {
+  if ($field_info = field_info_field($field_name)) {
+    unset($field_info['id']);
+    unset($field_info['bundles']);
+    return $field_info;
+  }
+  return FALSE;
+}
+
+/**
+ * Load a field's instance configuration by an entity_type-bundle-field_name
+ * identifier.
+ */
+function features_field_instance_load($identifier) {
+  list($entity_type, $bundle, $field_name) = explode('-', $identifier);
+  if ($instance_info = field_info_instance($entity_type, $field_name, $bundle)) {
+    unset($instance_info['id']);
+    unset($instance_info['field_id']);
+    return $instance_info;
+  }
+  return FALSE;
+}
+
+/* ----- DEPRECATED FIELD EXPORT -----
+ * keep this code for backward compatibility with older exports
+ * until v3.x
+ */
+
+/**
+ * Implements hook_features_export_options().
+ */
+function field_features_export_options() {
+  $options = array();
+  $instances = field_info_instances();
+  foreach ($instances as $entity_type => $bundles) {
+    foreach ($bundles as $bundle => $fields) {
+      foreach ($fields as $field) {
+        $identifier = "{$entity_type}-{$bundle}-{$field['field_name']}";
+        $options[$identifier] = $identifier;
+      }
+    }
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function field_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+  // Convert 'field' to 'field_instance' on features-update.
+  $pipe['field_instance'] = $data;
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function field_features_export_render($module, $data, $export = NULL) {
+  $translatables = $code = array();
+
+  $code[] = '  $fields = array();';
+  $code[] = '';
+  foreach ($data as $identifier) {
+    if ($field = features_field_load($identifier)) {
+      unset($field['field_config']['columns']);
+      // Only remove the 'storage' declaration if the field is using the default
+      // storage type.
+      if ($field['field_config']['storage']['type'] == variable_get('field_storage_default', 'field_sql_storage')) {
+        unset($field['field_config']['storage']);
+      }
+      // If we still have a storage declaration here it means that a non-default
+      // storage type was altered into to the field definition. And noone would
+      // never need to change the 'details' key, so don't render it.
+      if (isset($field['field_config']['storage']['details'])) {
+        unset($field['field_config']['storage']['details']);
+      }
+
+      _field_features_export_sort($field);
+      $field_export = features_var_export($field, '  ');
+      $field_identifier = features_var_export($identifier);
+      $code[] = "  // Exported field: {$field_identifier}.";
+      $code[] = "  \$fields[{$field_identifier}] = {$field_export};";
+      $code[] = "";
+
+      // Add label and description to translatables array.
+      if (!empty($field['field_instance']['label'])) {
+        $translatables[] = $field['field_instance']['label'];
+      }
+      if (!empty($field['field_instance']['description'])) {
+        $translatables[] = $field['field_instance']['description'];
+      }
+    }
+  }
+  if (!empty($translatables)) {
+    $code[] = features_translatables_export($translatables, '  ');
+  }
+  $code[] = '  return $fields;';
+  $code = implode("\n", $code);
+  return array('field_default_fields' => $code);
+}
+
+// Helper to enforce consistency in field export arrays.
+function _field_features_export_sort(&$field, $sort = TRUE) {
+
+  // Some arrays are not sorted to preserve order (for example allowed_values).
+  static $sort_blacklist = array(
+    'allowed_values',
+    'format_handlers',
+  );
+
+  if ($sort) {
+    ksort($field);
+  }
+  foreach ($field as $k => $v) {
+    if (is_array($v)) {
+      _field_features_export_sort($field[$k], !in_array($k, $sort_blacklist));
+    }
+  }
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function field_features_revert($module) {
+  field_features_rebuild($module);
+}
+
+/**
+ * Implements of hook_features_rebuild().
+ * Rebuilds fields from code defaults.
+ */
+function field_features_rebuild($module) {
+  if ($fields = features_get_default('field', $module)) {
+    field_info_cache_clear();
+
+    // Load all the existing fields and instance up-front so that we don't
+    // have to rebuild the cache all the time.
+    $existing_fields = field_info_fields();
+    $existing_instances = field_info_instances();
+
+    foreach ($fields as $field) {
+      // Create or update field.
+      $field_config = $field['field_config'];
+      if (isset($existing_fields[$field_config['field_name']])) {
+        $existing_field = $existing_fields[$field_config['field_name']];
+        if ($field_config + $existing_field != $existing_field) {
+          try {
+            field_update_field($field_config);
+          }
+          catch (FieldException $e) {
+            watchdog('features', 'Attempt to update field %label failed: %message', array('%label' => $field_config['field_name'], '%message' => $e->getMessage()), WATCHDOG_ERROR);
+          }
+        }
+      }
+      else {
+        try {
+          field_create_field($field_config);
+        }
+        catch (FieldException $e) {
+          watchdog('features', 'Attempt to create field %label failed: %message', array('%label' => $field_config['field_name'], '%message' => $e->getMessage()), WATCHDOG_ERROR);
+        }
+        $existing_fields[$field_config['field_name']] = $field_config;
+      }
+
+      // Create or update field instance.
+      $field_instance = $field['field_instance'];
+      if (isset($existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']])) {
+        $existing_instance = $existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']];
+        if ($field_instance + $existing_instance != $existing_instance) {
+          field_update_instance($field_instance);
+        }
+      }
+      else {
+        field_create_instance($field_instance);
+        $existing_instances[$field_instance['entity_type']][$field_instance['bundle']][$field_instance['field_name']] = $field_instance;
+      }
+    }
+
+    if ($fields) {
+      variable_set('menu_rebuild_needed', TRUE);
+    }
+  }
+}
+
+/**
+ * Load a field's configuration and instance configuration by an
+ * entity_type-bundle-field_name identifier.
+ */
+function features_field_load($identifier) {
+  list($entity_type, $bundle, $field_name) = explode('-', $identifier);
+  $field_info = field_info_field($field_name);
+  $instance_info = field_info_instance($entity_type, $field_name, $bundle);
+  if ($field_info && $instance_info) {
+    unset($field_info['id']);
+    unset($field_info['bundles']);
+    unset($instance_info['id']);
+    unset($instance_info['field_id']);
+    return array(
+      'field_config' => $field_info,
+      'field_instance' => $instance_info,
+    );
+  }
+  return FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.filter.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function filter_features_api() {
+  return array(
+    'filter' => array(
+      'name' => t('Text formats'),
+      'default_hook' => 'filter_default_formats',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'feature_source' => TRUE
+    ),
+  );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function filter_features_export_options() {
+  $options = array();
+  foreach (filter_formats() as $format => $info) {
+    $options[$format] = $info->name;
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function filter_features_export($data, &$export, $module_name = '') {
+  // The filter_default_formats() hook integration is provided by the
+  // features module so we need to add it as a dependency.
+  $export['dependencies']['features'] = 'features';
+
+  $filter_info = filter_get_filters();
+  foreach ($data as $name) {
+    if ($format = features_filter_format_load($name)) {
+      // Add format to exports
+      $export['features']['filter'][$format->format] = $format->format;
+
+      // Iterate through filters and ensure each filter's module is included as a dependency
+      foreach (array_keys($format->filters) as $name) {
+        if (isset($filter_info[$name], $filter_info[$name]['module'])) {
+          $module = $filter_info[$name]['module'];
+          $export['dependencies'][$module] = $module;
+        }
+      }
+    }
+  }
+
+  $pipe = array();
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function filter_features_export_render($module, $data, $export = NULL) {
+  $code = array();
+  $code[] = '  $formats = array();';
+  $code[] = '';
+
+  foreach ($data as $name) {
+    if ($format = features_filter_format_load($name)) {
+      $format_export = features_var_export($format, '  ');
+      $format_identifier = features_var_export($format->format);
+      $code[] = "  // Exported format: {$format->name}.";
+      $code[] = "  \$formats[{$format_identifier}] = {$format_export};";
+      $code[] = "";
+    }
+  }
+
+  $code[] = '  return $formats;';
+  $code = implode("\n", $code);
+  return array('filter_default_formats' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function filter_features_revert($module) {
+  return filter_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function filter_features_rebuild($module) {
+  if ($defaults = features_get_default('filter', $module)) {
+    foreach ($defaults as $format) {
+      $format = (object) $format;
+      filter_format_save($format);
+    }
+  }
+}
+
+/**
+ * Load a filter format by its name.
+ */
+function features_filter_format_load($name) {
+  // Use machine name for retrieving the format if available.
+  $query = db_select('filter_format');
+  $query->fields('filter_format');
+  $query->condition('format', $name);
+
+  // Retrieve filters for the format and attach.
+  if ($format = $query->execute()->fetchObject()) {
+    $format->filters = array();
+    foreach (filter_list_format($format->format) as $filter) {
+      if (!empty($filter->status)) {
+        $format->filters[$filter->name]['weight'] = $filter->weight;
+        $format->filters[$filter->name]['status'] = $filter->status;
+        $format->filters[$filter->name]['settings'] = $filter->settings;
+      }
+    }
+    return $format;
+  }
+  return FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.image.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function image_features_api() {
+  return array(
+    'image' => array(
+      'name' => t('Image styles'),
+      'feature_source' => TRUE,
+      'default_hook' => 'image_default_styles',
+      'alter_hook' => 'image_styles',
+    )
+  );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function image_features_export_options() {
+  $options = array();
+  foreach (image_styles() as $name => $style) {
+    $options[$name] = $style['name'];
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function image_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+  $map = features_get_default_map('image');
+  foreach ($data as $style) {
+    $export['dependencies']['image'] = 'image';
+    // If another module provides this style, add it as a dependency
+    if (isset($map[$style]) && $map[$style] != $module_name) {
+      $module = $map[$style];
+      $export['dependencies'][$module] = $module;
+    }
+    // Otherwise, export the style
+    elseif (image_style_load($style)) {
+      $export['features']['image'][$style] = $style;
+    }
+  }
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function image_features_export_render($module_name, $data, $export = NULL) {
+  $code = array();
+  $code[] = '  $styles = array();';
+  $code[] = '';
+  foreach ($data as $name) {
+    if ($style = image_style_load($name)) {
+      _image_features_style_sanitize($style);
+      $style_export = features_var_export($style, '  ');
+      $style_identifier = features_var_export($name);
+      $code[] = "  // Exported image style: {$name}.";
+      $code[] = "  \$styles[{$style_identifier}] = {$style_export};";
+      $code[] = "";
+    }
+  }
+  $code[] = '  return $styles;';
+  $code = implode("\n", $code);
+  return array('image_default_styles' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function image_features_revert($module) {
+  if ($default_styles = features_get_default('image', $module)) {
+    foreach (array_keys($default_styles) as $default_style) {
+      if ($style = image_style_load($default_style)) {
+        if ($style['storage'] != IMAGE_STORAGE_DEFAULT) {
+          image_default_style_revert($style);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Remove unnecessary keys for export.
+ */
+function _image_features_style_sanitize(&$style, $child = FALSE) {
+  $omit = $child ? array('isid', 'ieid', 'storage') : array('isid', 'ieid', 'storage', 'module');
+  if (is_array($style)) {
+    foreach ($style as $k => $v) {
+      if (in_array($k, $omit, TRUE)) {
+        unset($style[$k]);
+      }
+      else if (is_array($v)) {
+        _image_features_style_sanitize($style[$k], TRUE);
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.locale.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,162 @@
+<?php
+
+/**
+ * @file
+ *  Features hooks for language.
+ */
+
+/**
+ * Implements of hook_features_api().
+ */
+function locale_features_api() {
+  return array(
+    'language' => array(
+      'name' => t('Languages'),
+      'default_hook' => 'locale_default_languages',
+      'feature_source' => TRUE,
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+    ),
+  );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function language_features_export_options() {
+  return locale_language_list('native', TRUE);
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function language_features_export($data, &$export, $module_name = '') {
+  $export['dependencies']['features'] = 'features';
+  $export['dependencies']['locale'] = 'locale';
+
+  $language_list = locale_language_list('native', TRUE);
+
+  foreach ($data as $name) {
+    // Only export existing languages.
+    if (!empty($language_list[$name])) {
+      // Add language to exports.
+      $export['features']['language'][$name] = $name;
+    }
+  }
+
+  // No pipe to return.
+  return array();
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function language_features_export_render($module, $data, $export = NULL) {
+  $code = array();
+  $code[] = '  $languages = array();';
+  $code[] = '';
+
+  $language_list = language_list();
+
+  foreach ($data as $name) {
+    // Only render existing languages.
+    if (!empty($language_list[$name])) {
+
+      $var = (array) $language_list[$name];
+      // Unset javascript hash
+      unset($var['javascript']);
+
+      $lang_export = features_var_export($var, '  ');
+      $lang_identifier = features_var_export($name);
+      $code[] = "  // Exported language: $name.";
+      $code[] = "  \$languages[{$lang_identifier}] = {$lang_export};";
+    }
+  }
+
+  $code[] = '  return $languages;';
+  $code = implode("\n", $code);
+  return array('locale_default_languages' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function language_features_revert($module) {
+  return language_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function language_features_rebuild($module) {
+  if ($defaults = features_get_default('language', $module)) {
+    foreach ($defaults as $key => $language) {
+      _features_language_save((object) $language);
+    }
+
+    // Set correct language count.
+    $enabled_languages = db_select('languages')
+      ->condition('enabled', 1)
+      ->fields('languages')
+      ->execute()
+      ->rowCount();
+    variable_set('language_count', $enabled_languages);
+  }
+}
+
+/**
+ * Helper function to save the language to database.
+ *
+ * @see locale_languages_edit_form_submit()
+ */
+function _features_language_save($language) {
+
+  $current_language = db_select('languages')
+    ->condition('language', $language->language)
+    ->fields('languages')
+    ->execute()
+    ->fetchAssoc();
+
+  // Set the default language when needed.
+  $default = language_default();
+
+  // Insert new language via api function.
+  if (empty($current_language)) {
+    locale_add_language($language->language,
+                        $language->name,
+                        $language->native,
+                        $language->direction,
+                        $language->domain,
+                        $language->prefix,
+                        $language->enabled,
+                        ($language->language == $default->language));
+    // Additional params, locale_add_language does not implement.
+    db_update('languages')
+      ->fields(array(
+        'plurals' => empty($language->plurals) ? 0 : $language->plurals,
+        'formula' => empty($language->formula) ? '' : $language->formula,
+      ))
+      ->condition('language', $language->language)
+      ->execute();
+  }
+  // Update Existing language.
+  else {
+    // @TODO: get properties from schema.
+    $properties = array('language', 'name', 'native', 'direction', 'enabled', 'plurals', 'formula', 'domain', 'prefix', 'weight', 'javascript');
+    // The javascript hash is not in the imported data but should be empty
+    if (!isset($language->javascript)) {
+      $language->javascript = '';
+    }
+
+    $fields = array_intersect_key((array) $language, array_flip($properties));
+    db_update('languages')
+      ->fields($fields)
+      ->condition('language', $language->language)
+      ->execute();
+
+    // Set the default language when needed.
+    $default = language_default();
+    if ($default->language == $language->language) {
+      variable_set('language_default', (object) $fields);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.menu.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,312 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function menu_features_api() {
+  return array(
+    'menu_custom' => array(
+      'name' => t('Menus'),
+      'default_hook' => 'menu_default_menu_custom',
+      'feature_source' => TRUE,
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+    ),
+    'menu_links' => array(
+      'name' => t('Menu links'),
+      'default_hook' => 'menu_default_menu_links',
+      'feature_source' => TRUE,
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+    ),
+    // DEPRECATED
+    'menu' => array(
+      'name' => t('Menu items'),
+      'default_hook' => 'menu_default_items',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+      'feature_source' => FALSE,
+    ),
+  );
+}
+
+/**
+ * Implements hook_features_export().
+ * DEPRECATED: This implementation simply migrates deprecated `menu` items
+ * to the `menu_links` type.
+ */
+function menu_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+  foreach ($data as $path) {
+    $pipe['menu_links'][] = "features:{$path}";
+  }
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function menu_custom_features_export_options() {
+  $options = array();
+  $result = db_query("SELECT * FROM {menu_custom} ORDER BY title", array(), array('fetch' => PDO::FETCH_ASSOC));
+  foreach ($result as $menu) {
+    $options[$menu['menu_name']] = $menu['title'];
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function menu_custom_features_export($data, &$export, $module_name = '') {
+  // Default hooks are provided by the feature module so we need to add
+  // it as a dependency.
+  $export['dependencies']['features'] = 'features';
+  $export['dependencies']['menu'] = 'menu';
+
+  // Collect a menu to module map
+  $pipe = array();
+  $map = features_get_default_map('menu_custom', 'menu_name');
+  foreach ($data as $menu_name) {
+    // If this menu is provided by a different module, add it as a dependency.
+    if (isset($map[$menu_name]) && $map[$menu_name] != $module_name) {
+      $export['dependencies'][$map[$menu_name]] = $map[$menu_name];
+    }
+    else {
+      $export['features']['menu_custom'][$menu_name] = $menu_name;
+    }
+  }
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render()
+ */
+function menu_custom_features_export_render($module, $data) {
+  $code = array();
+  $code[] = '  $menus = array();';
+  $code[] = '';
+
+  $translatables = array();
+  foreach ($data as $menu_name) {
+    $row = db_select('menu_custom')
+      ->fields('menu_custom')
+      ->condition('menu_name', $menu_name)
+      ->execute()
+      ->fetchAssoc();
+    if ($row) {
+      $export = features_var_export($row, '  ');
+      $code[] = "  // Exported menu: {$menu_name}.";
+      $code[] = "  \$menus['{$menu_name}'] = {$export};";
+      $translatables[] = $row['title'];
+      $translatables[] = $row['description'];
+    }
+  }
+  if (!empty($translatables)) {
+    $code[] = features_translatables_export($translatables, '  ');
+  }
+
+  $code[] = '';
+  $code[] = '  return $menus;';
+  $code = implode("\n", $code);
+  return array('menu_default_menu_custom' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function menu_custom_features_revert($module) {
+  menu_custom_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function menu_custom_features_rebuild($module) {
+  if ($defaults = features_get_default('menu_custom', $module)) {
+    foreach ($defaults as $menu) {
+      menu_save($menu);
+    }
+  }
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function menu_links_features_export_options() {
+  global $menu_admin;
+  // Need to set this to TRUE in order to get menu links that the
+  // current user may not have access to (i.e. user/login)
+  $menu_admin = TRUE;
+  $use_menus = array_intersect_key(menu_get_menus(), array_flip(array_filter(variable_get('features_admin_menu_links_menus', array_keys(menu_get_menus())))));
+  $menu_links = menu_parent_options($use_menus, array('mlid' => 0));
+  $options = array();
+  foreach ($menu_links as $key => $name) {
+    list($menu_name, $mlid) = explode(':', $key, 2);
+    if ($mlid != 0) {
+      $link = menu_link_load($mlid);
+      $identifier = menu_links_features_identifier($link);
+      $options[$identifier] = "{$menu_name}: {$name}";
+    }
+  }
+  $menu_admin = FALSE;
+  return $options;
+}
+
+/**
+ * Callback for generating the menu link exportable identifier.
+ */
+function menu_links_features_identifier($link) {
+  return isset($link['menu_name'], $link['link_path']) ? "{$link['menu_name']}:{$link['link_path']}" : FALSE;
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function menu_links_features_export($data, &$export, $module_name = '') {
+  // Default hooks are provided by the feature module so we need to add
+  // it as a dependency.
+  $export['dependencies']['features'] = 'features';
+  $export['dependencies']['menu'] = 'menu';
+
+  // Collect a link to module map
+  $pipe = array();
+  $map = features_get_default_map('menu_links', 'menu_links_features_identifier');
+  foreach ($data as $identifier) {
+    if ($link = features_menu_link_load($identifier)) {
+      // If this link is provided by a different module, add it as a dependency.
+      if (isset($map[$identifier]) && $map[$identifier] != $module_name) {
+        $export['dependencies'][$map[$identifier]] = $map[$identifier];
+      }
+      else {
+        $export['features']['menu_links'][$identifier] = $identifier;
+      }
+      // For now, exclude a variety of common menus from automatic export.
+      // They may still be explicitly included in a Feature if the builder
+      // chooses to do so.
+      if (!in_array($link['menu_name'], array('features', 'primary-links', 'secondary-links', 'navigation', 'admin', 'devel'))) {
+        $pipe['menu_custom'][] = $link['menu_name'];
+      }
+    }
+  }
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render()
+ */
+function menu_links_features_export_render($module, $data) {
+  $code = array();
+  $code[] = '  $menu_links = array();';
+  $code[] = '';
+
+  $translatables = array();
+  foreach ($data as $identifier) {
+    if ($link = features_menu_link_load($identifier)) {
+      // Replace plid with a parent path.
+      if (!empty($link['plid']) && $parent = menu_link_load($link['plid'])) {
+        $link['parent_path'] = $parent['link_path'];
+      }
+      unset($link['plid']);
+      unset($link['mlid']);
+
+      $code[] = "  // Exported menu link: {$identifier}";
+      $code[] = "  \$menu_links['{$identifier}'] = ". features_var_export($link, '  ') .";";
+      $translatables[] = $link['link_title'];
+    }
+  }
+  if (!empty($translatables)) {
+    $code[] = features_translatables_export($translatables, '  ');
+  }
+
+  $code[] = '';
+  $code[] = '  return $menu_links;';
+  $code = implode("\n", $code);
+  return array('menu_default_menu_links' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function menu_links_features_revert($module) {
+  menu_links_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function menu_links_features_rebuild($module) {
+  if ($menu_links = features_get_default('menu_links', $module)) {
+    menu_links_features_rebuild_ordered($menu_links);
+  }
+}
+
+/**
+ * Generate a depth tree of all menu links.
+ */
+function menu_links_features_rebuild_ordered($menu_links, $reset = FALSE) {
+  static $ordered;
+  static $all_links;
+  if (!isset($ordered) || $reset) {
+    $ordered = array();
+    $unordered = features_get_default('menu_links');
+
+    // Order all links by depth.
+    if ($unordered) {
+      do {
+        $current = count($unordered);
+        foreach ($unordered as $key => $link) {
+          $identifier = menu_links_features_identifier($link);
+          $parent = isset($link['parent_path']) ? "{$link['menu_name']}:{$link['parent_path']}" : '';
+          if (empty($parent)) {
+            $ordered[$identifier] = 0;
+            $all_links[$identifier] = $link;
+            unset($unordered[$key]);
+          }
+          elseif (isset($ordered[$parent])) {
+            $ordered[$identifier] = $ordered[$parent] + 1;
+            $all_links[$identifier] = $link;
+            unset($unordered[$key]);
+          }
+        }
+      } while (count($unordered) < $current);
+    }
+    asort($ordered);
+  }
+
+  // Ensure any default menu items that do not exist are created.
+  foreach (array_keys($ordered) as $identifier) {
+    $link = $all_links[$identifier];
+    $existing = features_menu_link_load($identifier);
+    if (!$existing || in_array($link, $menu_links)) {
+      // Retrieve the mlid if this is an existing item.
+      if ($existing) {
+        $link['mlid'] = $existing['mlid'];
+      }
+      // Retrieve the plid for a parent link.
+      if (!empty($link['parent_path']) && $parent = features_menu_link_load("{$link['menu_name']}:{$link['parent_path']}")) {
+        $link['plid'] = $parent['mlid'];
+      }
+      else {
+        $link['plid'] = 0;
+      }
+      menu_link_save($link);
+    }
+  }
+}
+
+/**
+ * Load a menu link by its menu_name:link_path identifier.
+ */
+function features_menu_link_load($identifier) {
+  list($menu_name, $link_path) = explode(':', $identifier, 2);
+  $link = db_select('menu_links')
+    ->fields('menu_links', array('menu_name', 'mlid', 'plid', 'link_path', 'router_path', 'link_title', 'options', 'module', 'hidden', 'external', 'has_children', 'expanded', 'weight'))
+    ->condition('menu_name', $menu_name)
+    ->condition('link_path', $link_path)
+    ->addTag('features_menu_link')
+    ->execute()
+    ->fetchAssoc();
+  if ($link) {
+    $link['options'] = unserialize($link['options']);
+    return $link;
+  }
+  return FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.node.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function node_features_api() {
+  return array(
+    'node' => array(
+      'name' => t('Content types'),
+      'feature_source' => TRUE,
+      'default_hook' => 'node_info',
+    ),
+  );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function node_features_export_options() {
+  return node_type_get_names();
+}
+
+/**
+ * Implements hook_features_export.
+ */
+function node_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+  $map = features_get_default_map('node');
+
+  foreach ($data as $type) {
+    // Poll node module to determine who provides the node type.
+    if ($info = node_type_get_type($type)) {
+      // If this node type is provided by a different module, add it as a dependency
+      if (isset($map[$type]) && $map[$type] != $module_name) {
+        $export['dependencies'][$map[$type]] = $map[$type];
+      }
+      // Otherwise export the node type.
+      elseif (in_array($info->base, array('node_content', 'features'))) {
+        $export['features']['node'][$type] = $type;
+        $export['dependencies']['node'] = 'node';
+        $export['dependencies']['features'] = 'features';
+      }
+
+      $fields = field_info_instances('node', $type);
+      foreach ($fields as $name => $field) {
+        $pipe['field_instance'][] = "node-{$field['bundle']}-{$field['field_name']}";
+      }
+    }
+  }
+
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function node_features_export_render($module, $data, $export = NULL) {
+  $elements = array(
+    'name' => TRUE,
+    'base' => FALSE,
+    'description' => TRUE,
+    'has_title' => FALSE,
+    'title_label' => TRUE,
+    'help' => TRUE,
+  );
+  $output = array();
+  $output[] = '  $items = array(';
+  foreach ($data as $type) {
+    if ($info = node_type_get_type($type)) {
+      // Force module name to be 'features' if set to 'node. If we leave as
+      // 'node' the content type will be assumed to be database-stored by
+      // the node module.
+      $info->base = ($info->base === 'node') ? 'features' : $info->base;
+      $output[] = "    '{$type}' => array(";
+      foreach ($elements as $key => $t) {
+        if ($t) {
+          $text = str_replace("'", "\'", $info->$key);
+          $text = !empty($text) ? "t('{$text}')" : "''";
+          $output[] = "      '{$key}' => {$text},";
+        }
+        else {
+          $output[] = "      '{$key}' => '{$info->$key}',";
+        }
+      }
+      $output[] = "    ),";
+    }
+  }
+  $output[] = '  );';
+  $output[] = '  return $items;';
+  $output = implode("\n", $output);
+  return array('node_info' => $output);
+}
+
+/**
+ * Implements hook_features_revert().
+ *
+ * @param $module
+ * name of module to revert content for
+ */
+function node_features_revert($module = NULL) {
+  if ($default_types = features_get_default('node', $module)) {
+    foreach ($default_types as $type_name => $type_info) {
+      // Delete node types
+      // We don't use node_type_delete() because we do not actually
+      // want to delete the node type (and invoke hook_node_type()).
+      // This can lead to bad consequences like CCK deleting field
+      // storage in the DB.
+      db_delete('node_type')
+        ->condition('type', $type_name)
+        ->execute();
+    }
+    node_types_rebuild();
+    menu_rebuild();
+  }
+}
+
+/**
+ * Implements hook_features_disable().
+ *
+ * When a features module is disabled, modify any node types it provides so
+ * they can be deleted manually through the content types UI.
+ *
+ * @param $module
+ *   Name of module that has been disabled.
+ */
+function node_features_disable($module) {
+  if ($default_types = features_get_default('node', $module)) {
+    foreach ($default_types as $type_name => $type_info) {
+      $type_info = node_type_load($type_name);
+      $type_info->module = 'node';
+      $type_info->custom = 1;
+      $type_info->modified = 1;
+      $type_info->locked = 0;
+      node_type_save($type_info);
+    }
+  }
+}
+
+/**
+ * Implements hook_features_enable().
+ *
+ * When a features module is enabled, modify any node types it provides so
+ * they can no longer be deleted manually through the content types UI.
+ *
+ * @param $module
+ *   Name of module that has been enabled.
+ */
+function node_features_enable($module) {
+  if ($default_types = features_get_default('node', $module)) {
+    foreach ($default_types as $type_name => $type_info) {
+      // Ensure the type exists.
+      if ($type_info = node_type_load($type_name)) {
+        $type_info->module = $module;
+        $type_info->custom = 0;
+        $type_info->modified = 0;
+        $type_info->locked = 1;
+        node_type_save($type_info);
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.taxonomy.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function taxonomy_features_api() {
+  return array(
+    'taxonomy' => array(
+      'name' => t('Taxonomy'),
+      'feature_source' => TRUE,
+      'default_hook' => 'taxonomy_default_vocabularies',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+    ),
+  );
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function taxonomy_features_export_options() {
+  $vocabularies = array();
+  foreach (taxonomy_get_vocabularies() as $vocabulary) {
+    $vocabularies[$vocabulary->machine_name] = $vocabulary->name;
+  }
+  return $vocabularies;
+}
+
+/**
+ * Implements hook_features_export().
+ *
+ * @todo Test adding existing dependencies.
+ */
+function taxonomy_features_export($data, &$export, $module_name = '') {
+  $pipe = array();
+
+  // taxonomy_default_vocabularies integration is provided by Features.
+  $export['dependencies']['features'] = 'features';
+  $export['dependencies']['taxonomy'] = 'taxonomy';
+
+  // Add dependencies for each vocabulary.
+  $map = features_get_default_map('taxonomy');
+  foreach ($data as $machine_name) {
+    if (isset($map[$machine_name]) && $map[$machine_name] != $module_name) {
+      $export['dependencies'][$map[$machine_name]] = $map[$machine_name];
+    }
+    else {
+      $export['features']['taxonomy'][$machine_name] = $machine_name;
+
+      $fields = field_info_instances('taxonomy_term', $machine_name);
+      foreach ($fields as $name => $field) {
+        $pipe['field'][] = "taxonomy_term-{$field['bundle']}-{$field['field_name']}";
+        $pipe['field_instance'][] = "taxonomy_term-{$field['bundle']}-{$field['field_name']}";
+      }
+    }
+  }
+  return $pipe;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function taxonomy_features_export_render($module, $data) {
+  $vocabularies = taxonomy_get_vocabularies();
+  $code = array();
+  foreach ($data as $machine_name) {
+    foreach ($vocabularies as $vocabulary) {
+      if ($vocabulary->machine_name == $machine_name) {
+        // We don't want to break the entity cache, so we need to clone the
+        // vocabulary before unsetting the id.
+        $vocabulary = clone $vocabulary;
+        unset($vocabulary->vid);
+        $code[$machine_name] = $vocabulary;
+      }
+    }
+  }
+  $code = "  return ". features_var_export($code, '  ') .";";
+  return array('taxonomy_default_vocabularies' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function taxonomy_features_revert($module) {
+  taxonomy_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ *
+ * Rebuilds Taxonomy vocabularies from code defaults.
+ */
+function taxonomy_features_rebuild($module) {
+  if ($vocabularies = features_get_default('taxonomy', $module)) {
+    $existing = taxonomy_get_vocabularies();
+    foreach ($vocabularies as $vocabulary) {
+      $vocabulary = (object) $vocabulary;
+      foreach ($existing as $existing_vocab) {
+        if ($existing_vocab->machine_name === $vocabulary->machine_name) {
+          $vocabulary->vid = $existing_vocab->vid;
+        }
+      }
+      taxonomy_vocabulary_save($vocabulary);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/includes/features.user.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,290 @@
+<?php
+
+/**
+ * Implements hook_features_api().
+ */
+function user_features_api() {
+  return array(
+    'user_role' => array(
+      'name' => t('Roles'),
+      'feature_source' => TRUE,
+      'default_hook' => 'user_default_roles',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+    ),
+    'user_permission' => array(
+      'name' => t('Permissions'),
+      'feature_source' => TRUE,
+      'default_hook' => 'user_default_permissions',
+      'default_file' => FEATURES_DEFAULTS_INCLUDED,
+    ),
+  );
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function user_permission_features_export($data, &$export, $module_name = '') {
+  $export['dependencies']['features'] = 'features';
+
+  // Ensure the modules that provide the given permissions are included as dependencies.
+  $map = user_permission_get_modules();
+  foreach ($data as $perm) {
+    $perm_name = $perm;
+    // Export vocabulary permissions using the machine name, instead of
+    // vocabulary id.
+    _user_features_change_term_permission($perm_name, 'machine_name');
+    if (isset($map[$perm_name])) {
+      $perm_module = $map[$perm_name];
+      $export['dependencies'][$perm_module] = $perm_module;
+      $export['features']['user_permission'][$perm] = $perm;
+    }
+  }
+
+  return array();
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function user_permission_features_export_options() {
+  $modules = array();
+  $module_info = system_get_info('module');
+  foreach (module_implements('permission') as $module) {
+    $modules[$module_info[$module]['name']] = $module;
+  }
+  ksort($modules);
+
+  $options = array();
+  foreach ($modules as $display_name => $module) {
+    if ($permissions = module_invoke($module, 'permission')) {
+      foreach ($permissions as $perm => $perm_item) {
+        // Export vocabulary permissions using the machine name, instead of
+        // vocabulary id.
+        _user_features_change_term_permission($perm);
+        $options[$perm] = strip_tags("{$display_name}: {$perm_item['title']}");
+      }
+    }
+  }
+  return $options;
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function user_permission_features_export_render($module, $data) {
+  $perm_modules = &drupal_static(__FUNCTION__ . '_perm_modules');
+  if (!isset($perm_modules)) {
+    $perm_modules = user_permission_get_modules();
+  }
+
+  $code = array();
+  $code[] = '  $permissions = array();';
+  $code[] = '';
+
+  $permissions = _user_features_get_permissions();
+
+  foreach ($data as $perm_name) {
+    $permission = array();
+    // Export vocabulary permissions using the machine name, instead of
+    // vocabulary id.
+    $perm = $perm_name;
+    _user_features_change_term_permission($perm_name, 'machine_name');
+    $permission['name'] = $perm;
+    if (!empty($permissions[$perm_name])) {
+      sort($permissions[$perm_name]);
+      $permission['roles'] = drupal_map_assoc($permissions[$perm_name]);
+    }
+    else {
+      $permission['roles'] = array();
+    }
+    if (isset($perm_modules[$perm_name])) {
+      $permission['module'] = $perm_modules[$perm_name];
+    }
+    $perm_identifier = features_var_export($perm);
+    $perm_export = features_var_export($permission, '  ');
+    $code[] = "  // Exported permission: {$perm_identifier}.";
+    $code[] = "  \$permissions[{$perm_identifier}] = {$perm_export};";
+    $code[] = "";
+  }
+
+  $code[] = '  return $permissions;';
+  $code = implode("\n", $code);
+  return array('user_default_permissions' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function user_permission_features_revert($module) {
+  user_permission_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ * Iterate through default permissions and update the permissions map.
+ *
+ * @param $module
+ *   The module whose default user permissions should be rebuilt.
+ */
+function user_permission_features_rebuild($module) {
+  if ($defaults = features_get_default('user_permission', $module)) {
+    // Make sure the list of available node types is up to date, especially when
+    // installing multiple features at once, for example from an install profile
+    // or via drush.
+    node_types_rebuild();
+
+    $modules = user_permission_get_modules();
+    $roles = _user_features_get_roles();
+    $permissions_by_role = _user_features_get_permissions(FALSE);
+    foreach ($defaults as $permission) {
+      $perm = $permission['name'];
+      _user_features_change_term_permission($perm, 'machine_name');
+      if (empty($modules[$perm])) {
+        $args = array('!name' => $perm, '!module' => $module,);
+        $msg = t('Warning in features rebuild of !module. No module defines permission "!name".', $args);
+        drupal_set_message($msg, 'warning');
+        continue;
+      }
+      // Export vocabulary permissions using the machine name, instead of
+      // vocabulary id.
+      foreach ($roles as $role) {
+        if (in_array($role, $permission['roles'])) {
+          $permissions_by_role[$role][$perm] = TRUE;
+        }
+        else {
+          $permissions_by_role[$role][$perm] = FALSE;
+        }
+      }
+    }
+    // Write the updated permissions.
+    foreach ($roles as $rid => $role) {
+      if (isset($permissions_by_role[$role])) {
+        user_role_change_permissions($rid, $permissions_by_role[$role]);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_features_export().
+ */
+function user_role_features_export($data, &$export, $module_name = '') {
+  $export['dependencies']['features'] = 'features';
+  $map = features_get_default_map('user_role', 'name');
+  foreach ($data as $role) {
+    // Role is provided by another module. Add dependency.
+    if (isset($map[$role]) && $map[$role] != $module_name) {
+      $export['dependencies'][$map[$role]] = $map[$role];
+    }
+    // Export.
+    elseif(user_role_load_by_name($role)) {
+      $export['features']['user_role'][$role] = $role;
+    }
+  }
+  return array();
+}
+
+/**
+ * Implements hook_features_export_options().
+ */
+function user_role_features_export_options() {
+  return drupal_map_assoc(_user_features_get_roles(FALSE));
+}
+
+/**
+ * Implements hook_features_export_render().
+ */
+function user_role_features_export_render($module, $data) {
+  $code = array();
+  $code[] = '  $roles = array();';
+  $code[] = '';
+
+  foreach ($data as $name) {
+    if ($role = user_role_load_by_name($name)) {
+      unset($role->rid);
+      $role_identifier = features_var_export($name);
+      $role_export = features_var_export($role , '  ');
+      $code[] = "  // Exported role: {$name}.";
+      $code[] = "  \$roles[{$role_identifier}] = {$role_export};";
+      $code[] = "";
+    }
+  }
+
+  $code[] = '  return $roles;';
+  $code = implode("\n", $code);
+  return array('user_default_roles' => $code);
+}
+
+/**
+ * Implements hook_features_revert().
+ */
+function user_role_features_revert($module) {
+  user_role_features_rebuild($module);
+}
+
+/**
+ * Implements hook_features_rebuild().
+ */
+function user_role_features_rebuild($module) {
+  if ($defaults = features_get_default('user_role', $module)) {
+    foreach ($defaults as $role) {
+      $role = (object) $role;
+      if ($existing = user_role_load_by_name($role->name)) {
+        $role->rid = $existing->rid;
+      }
+      user_role_save($role);
+    }
+  }
+}
+
+/**
+ * Generate $rid => $role with role names untranslated.
+ */
+function _user_features_get_roles($builtin = TRUE) {
+  $roles = array();
+  foreach (user_roles() as $rid => $name) {
+    switch ($rid) {
+      case DRUPAL_ANONYMOUS_RID:
+        if ($builtin) {
+          $roles[$rid] = 'anonymous user';
+        }
+        break;
+      case DRUPAL_AUTHENTICATED_RID:
+        if ($builtin) {
+          $roles[$rid] = 'authenticated user';
+        }
+        break;
+      default:
+        $roles[$rid] = $name;
+        break;
+    }
+  }
+  return $roles;
+}
+
+/**
+ * Represent the current state of permissions as a perm to role name array map.
+ */
+function _user_features_get_permissions($by_role = TRUE) {
+  $map = user_permission_get_modules();
+  $roles = _user_features_get_roles();
+  $permissions = array();
+  foreach (user_role_permissions($roles) as $rid => $role_permissions) {
+    if ($by_role) {
+      foreach (array_keys(array_filter($role_permissions)) as $permission) {
+        if (isset($map[$permission])) {
+          $permissions[$permission][] = $roles[$rid];
+        }
+      }
+    }
+    else {
+      $permissions[$roles[$rid]] = array();
+      foreach ($role_permissions as $permission => $status) {
+        if (isset($map[$permission])) {
+          $permissions[$roles[$rid]][$permission] = $status;
+        }
+      }
+    }
+  }
+  return $permissions;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,289 @@
+<?php
+
+/**
+ * User permission component tests for Features
+ */
+class FeaturesUserTestCase extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  /**
+   * Test info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => t('Component tests'),
+      'description' => t('Run tests for components of Features.') ,
+      'group' => t('Features'),
+    );
+  }
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp(array(
+      'field',
+      'filter',
+      'image',
+      'taxonomy',
+      'views',
+      'features',
+      'features_test'
+    ));
+
+    // Run a features rebuild to ensure our feature is fully installed.
+    features_rebuild();
+
+    $admin_user = $this->drupalCreateUser(array('administer features'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Run test.
+   */
+  public function test() {
+    module_load_include('inc', 'features', 'features.export');
+
+    $components = array_filter(array(
+      'field_instance' => 'field',
+      'filter' => 'filter',
+      'image' => 'image',
+      'node' => 'node',
+      'user_permission' => 'user',
+      'views_view' => 'views',
+    ), 'module_exists');
+
+    foreach (array_keys($components) as $component) {
+      $callback = "_test_{$component}";
+
+      // Ensure that the component/default is properly available.
+      $object = $this->$callback('load');
+      $this->assertTrue(!empty($object), t('@component present.', array('@component' => $component)));
+
+      // Ensure that the component is defaulted.
+      $states = features_get_component_states(array('features_test'), FALSE, TRUE);
+      $this->assertTrue($states['features_test'][$component] === FEATURES_DEFAULT, t('@component state: Default.', array('@component' => $component)));
+
+      // Override component and test that Features detects the override.
+      $this->$callback('override', $this);
+      $states = features_get_component_states(array('features_test'), FALSE, TRUE);
+      $this->assertTrue($states['features_test'][$component] === FEATURES_OVERRIDDEN, t('@component state: Overridden.', array('@component' => $component)));
+    }
+
+    // Revert component and ensure that component has reverted.
+    // Do this in separate loops so we only have to run
+    // drupal_flush_all_caches() once.
+    foreach (array_keys($components) as $component) {
+      features_revert(array('features_test' => array($component)));
+    }
+    drupal_flush_all_caches();
+    foreach (array_keys($components) as $component) {
+      // Reload so things like Views can clear it's cache
+      $this->$callback('load');
+      $states = features_get_component_states(array('features_test'), FALSE, TRUE);
+      $this->assertTrue($states['features_test'][$component] === FEATURES_DEFAULT, t('@component reverted.', array('@component' => $component)));
+    }
+  }
+
+  protected function _test_field_instance($op = 'load') {
+    switch ($op) {
+      case 'load':
+        return field_info_instance('node', 'field_features_test', 'features_test');
+      case 'override':
+        $field_instance = field_info_instance('node', 'field_features_test', 'features_test');
+        $field_instance['label'] = 'Foo bar';
+        field_update_instance($field_instance);
+        break;
+    }
+  }
+
+  protected function _test_filter($op = 'load') {
+    // So... relying on our own API functions to test is pretty lame.
+    // But these modules don't have APIs either. So might as well use
+    // the ones we've written for them...
+    features_include();
+    switch ($op) {
+      case 'load':
+        return features_filter_format_load('features_test');
+      case 'override':
+        $format = features_filter_format_load('features_test');
+        unset($format->filters['filter_url']);
+        filter_format_save($format);
+        break;
+    }
+  }
+
+  protected function _test_image($op = 'load') {
+    switch ($op) {
+      case 'load':
+        return image_style_load('features_test');
+      case 'override':
+        $style = image_style_load('features_test');
+        $style = image_style_save($style);
+        foreach ($style['effects'] as $effect) {
+          $effect['data']['width'] = '120';
+          image_effect_save($effect);
+        }
+        break;
+    }
+  }
+
+  protected function _test_node($op = 'load') {
+    switch ($op) {
+      case 'load':
+        return node_type_get_type('features_test');
+      case 'override':
+        $type = node_type_get_type('features_test');
+        $type->description = 'Foo bar baz.';
+        $type->modified = TRUE;
+        node_type_save($type);
+        break;
+    }
+  }
+
+  protected function _test_views_view($op = 'load') {
+    switch ($op) {
+      case 'load':
+        return views_get_view('features_test', TRUE);
+      case 'override':
+        $view = views_get_view('features_test', TRUE);
+        $view->set_display('default');
+        $view->display_handler->override_option('title', 'Foo bar');
+        $view->save();
+        // Clear the load cache from above
+        views_get_view('features_test', TRUE);
+        break;
+    }
+  }
+
+  protected function _test_user_permission($op = 'load') {
+    switch ($op) {
+      case 'load':
+        $permissions = user_role_permissions(array(DRUPAL_AUTHENTICATED_RID => 'authenticated user'));
+        return !empty($permissions[DRUPAL_AUTHENTICATED_RID]['create features_test content']);
+      case 'override':
+        user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array('create features_test content' => 0));
+        break;
+    }
+  }
+}
+
+/**
+ * Tests enabling of feature modules.
+ */
+class FeaturesEnableTestCase extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  /**
+   * Test info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => t('Features enable tests'),
+      'description' => t('Run tests for enabling of features.') ,
+      'group' => t('Features'),
+    );
+  }
+
+
+  /**
+   * Run test for features_get_components on enable.
+   */
+  public function testFeaturesGetComponents() {
+
+    // Testing that features_get_components returns correct after enable.
+    $modules = array(
+      'features',
+      'taxonomy',
+      'features_test',
+    );
+
+    // Make sure features_get_components is cached if features already enabled.
+    if (!module_exists('features')) {
+      drupal_load('module', 'features');
+    }
+    features_get_components();
+
+    module_enable($modules);
+
+    // Make sure correct information for enabled modules is now cached.
+    $components = features_get_components();
+    $taxonomy_component_info = taxonomy_features_api();
+    $this->assertTrue(!empty($components['taxonomy']) && $components['taxonomy'] == $taxonomy_component_info['taxonomy'], 'features_get_components returns correct taxonomy information on enable');
+
+    features_rebuild();
+    $this->assertNotNull(taxonomy_vocabulary_machine_name_load('taxonomy_features_test'), 'Taxonomy vocabulary correctly enabled on enable.');
+  }
+}
+
+
+/**
+ * Tests intergration of ctools for features.
+ */
+class FeaturesCtoolsIntegrationTest extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  /**
+   * Test info.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => t('Features Chaos Tools integration'),
+      'description' => t('Run tests for ctool integration of features.') ,
+      'group' => t('Features'),
+    );
+  }
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp(array(
+      'features',
+      'ctools',
+    ));
+  }
+
+  /**
+   * Run test.
+   */
+  public function testModuleEnable() {
+    $try = array(
+      'strongarm',
+      'views',
+    );
+
+    // Trigger the first includes and the static to be set.
+    features_include();
+    $function_ends = array(
+      'features_export',
+      'features_export_options',
+      'features_export_render',
+      'features_revert',
+    );
+    foreach ($try as $module) {
+      $function = $module . '_features_api';
+      $this->assertFalse(function_exists($function), 'Chaos tools functions for ' . $module . ' do not exist while it is disabled.');
+      // Module enable will trigger declaring the new functions.
+      module_enable(array($module));
+    }
+
+    // CTools hooks only created when there is an actual feature exportable
+    // enabled.
+    module_enable(array('features_test'));
+
+    foreach ($try as $module) {
+      if (module_exists($module)) {
+        $function_exists = function_exists($function);
+        if ($function_exists) {
+          foreach ($function() as $component_type => $component_info) {
+            foreach ($function_ends as $function_end) {
+              $function_exists = $function_exists && function_exists($component_type . '_' . $function_end);
+            }
+          }
+        }
+        $this->assertTrue($function_exists, 'Chaos tools functions for ' . $module . ' exist when it is enabled.');
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.features.field_base.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,43 @@
+<?php
+/**
+ * @file
+ * features_test.features.field_base.inc
+ */
+
+/**
+ * Implements hook_field_default_field_bases().
+ */
+function features_test_field_default_field_bases() {
+  $field_bases = array();
+
+  // Exported field_base: 'field_features_test'
+  $field_bases['field_features_test'] = array(
+    'active' => 1,
+    'cardinality' => 1,
+    'deleted' => 0,
+    'entity_types' => array(),
+    'field_name' => 'field_features_test',
+    'foreign keys' => array(
+      'format' => array(
+        'columns' => array(
+          'format' => 'format',
+        ),
+        'table' => 'filter_format',
+      ),
+    ),
+    'indexes' => array(
+      'format' => array(
+        0 => 'format',
+      ),
+    ),
+    'locked' => 0,
+    'module' => 'text',
+    'settings' => array(
+      'max_length' => 255,
+    ),
+    'translatable' => 1,
+    'type' => 'text',
+  );
+
+  return $field_bases;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.features.field_instance.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,76 @@
+<?php
+/**
+ * @file
+ * features_test.features.field_instance.inc
+ */
+
+/**
+ * Implements hook_field_default_field_instances().
+ */
+function features_test_field_default_field_instances() {
+  $field_instances = array();
+
+  // Exported field_instance: 'node-features_test-field_features_test'
+  $field_instances['node-features_test-field_features_test'] = array(
+    'bundle' => 'features_test',
+    'default_value' => NULL,
+    'deleted' => 0,
+    'description' => '',
+    'display' => array(
+      'default' => array(
+        'label' => 'above',
+        'module' => 'text',
+        'settings' => array(),
+        'type' => 'text_default',
+        'weight' => 0,
+      ),
+      'full' => array(
+        'label' => 'above',
+        'settings' => array(),
+        'type' => 'hidden',
+        'weight' => 0,
+      ),
+      'print' => array(
+        'label' => 'above',
+        'settings' => array(),
+        'type' => 'hidden',
+        'weight' => 0,
+      ),
+      'rss' => array(
+        'label' => 'above',
+        'settings' => array(),
+        'type' => 'hidden',
+        'weight' => 0,
+      ),
+      'teaser' => array(
+        'label' => 'above',
+        'settings' => array(),
+        'type' => 'hidden',
+        'weight' => 0,
+      ),
+    ),
+    'entity_type' => 'node',
+    'field_name' => 'field_features_test',
+    'label' => 'Test',
+    'required' => 0,
+    'settings' => array(
+      'text_processing' => 0,
+      'user_register_form' => FALSE,
+    ),
+    'widget' => array(
+      'active' => 1,
+      'module' => 'text',
+      'settings' => array(
+        'size' => 60,
+      ),
+      'type' => 'text_textfield',
+      'weight' => -4,
+    ),
+  );
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('Test');
+
+  return $field_instances;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.features.filter.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,56 @@
+<?php
+/**
+ * @file
+ * features_test.features.filter.inc
+ */
+
+/**
+ * Implements hook_filter_default_formats().
+ */
+function features_test_filter_default_formats() {
+  $formats = array();
+
+  // Exported format: features_test.
+  $formats['features_test'] = array(
+    'format' => 'features_test',
+    'name' => 'features_test',
+    'cache' => 1,
+    'status' => 1,
+    'weight' => 0,
+    'filters' => array(
+      'filter_autop' => array(
+        'weight' => 10,
+        'status' => 1,
+        'settings' => array(),
+      ),
+      'filter_html' => array(
+        'weight' => 10,
+        'status' => 1,
+        'settings' => array(
+          'allowed_html' => '<a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>',
+          'filter_html_help' => 1,
+          'filter_html_nofollow' => 0,
+        ),
+      ),
+      'filter_htmlcorrector' => array(
+        'weight' => 10,
+        'status' => 1,
+        'settings' => array(),
+      ),
+      'filter_html_escape' => array(
+        'weight' => 10,
+        'status' => 1,
+        'settings' => array(),
+      ),
+      'filter_url' => array(
+        'weight' => 10,
+        'status' => 1,
+        'settings' => array(
+          'filter_url_length' => 72,
+        ),
+      ),
+    ),
+  );
+
+  return $formats;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @file
+ * features_test.features.inc
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function features_test_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "strongarm" && $api == "strongarm") {
+    return array("version" => "1");
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function features_test_views_api() {
+  return array("api" => "3.0");
+}
+
+/**
+ * Implements hook_image_default_styles().
+ */
+function features_test_image_default_styles() {
+  $styles = array();
+
+  // Exported image style: features_test.
+  $styles['features_test'] = array(
+    'name' => 'features_test',
+    'effects' => array(
+      2 => array(
+        'label' => 'Scale',
+        'help' => 'Scaling will maintain the aspect-ratio of the original image. If only a single dimension is specified, the other dimension will be calculated.',
+        'effect callback' => 'image_scale_effect',
+        'dimensions callback' => 'image_scale_dimensions',
+        'form callback' => 'image_scale_form',
+        'summary theme' => 'image_scale_summary',
+        'module' => 'image',
+        'name' => 'image_scale',
+        'data' => array(
+          'width' => 100,
+          'height' => 100,
+          'upscale' => 0,
+        ),
+        'weight' => 1,
+      ),
+    ),
+    'label' => 'features_test',
+  );
+
+  return $styles;
+}
+
+/**
+ * Implements hook_node_info().
+ */
+function features_test_node_info() {
+  $items = array(
+    'features_test' => array(
+      'name' => t('Testing: Features'),
+      'base' => 'node_content',
+      'description' => t('Content type provided for Features tests.'),
+      'has_title' => '1',
+      'title_label' => t('Title'),
+      'help' => '',
+    ),
+  );
+  return $items;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.features.taxonomy.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @file
+ * features_test.features.taxonomy.inc
+ */
+
+/**
+ * Implements hook_taxonomy_default_vocabularies().
+ */
+function features_test_taxonomy_default_vocabularies() {
+  return array(
+    'taxonomy_features_test' => array(
+      'name' => 'Taxonomy Features Test',
+      'machine_name' => 'taxonomy_features_test',
+      'description' => 'Taxonomy vocabulary',
+      'hierarchy' => 0,
+      'module' => 'taxonomy',
+      'weight' => 0,
+      'rdf_mapping' => array(
+        'rdftype' => array(
+          0 => 'skos:ConceptScheme',
+        ),
+        'name' => array(
+          'predicates' => array(
+            0 => 'dc:title',
+          ),
+        ),
+        'description' => array(
+          'predicates' => array(
+            0 => 'rdfs:comment',
+          ),
+        ),
+      ),
+    ),
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.features.user_permission.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @file
+ * features_test.features.user_permission.inc
+ */
+
+/**
+ * Implements hook_user_default_permissions().
+ */
+function features_test_user_default_permissions() {
+  $permissions = array();
+
+  // Exported permission: create features_test content.
+  $permissions['create features_test content'] = array(
+    'name' => 'create features_test content',
+    'roles' => array(
+      'anonymous user' => 'anonymous user',
+      'authenticated user' => 'authenticated user',
+    ),
+    'module' => 'node',
+  );
+
+  return $permissions;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,29 @@
+name = Features Tests
+description = Test module for Features testing.
+core = 7.x
+package = Testing
+php = 5.2.0
+dependencies[] = features
+dependencies[] = image
+dependencies[] = strongarm
+dependencies[] = taxonomy
+dependencies[] = views
+features[ctools][] = strongarm:strongarm:1
+features[ctools][] = views:views_default:3.0
+features[features_api][] = api:2
+features[field_base][] = field_features_test
+features[field_instance][] = node-features_test-field_features_test
+features[filter][] = features_test
+features[image][] = features_test
+features[node][] = features_test
+features[taxonomy][] = taxonomy_features_test
+features[user_permission][] = create features_test content
+features[views_view][] = features_test
+hidden = 1
+
+; Information added by drupal.org packaging script on 2013-08-26
+version = "7.x-2.0-rc3"
+core = "7.x"
+project = "features"
+datestamp = "1377548845"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,3 @@
+<?php
+
+include_once('features_test.features.inc');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/tests/features_test/features_test.views_default.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,38 @@
+<?php
+/**
+ * @file
+ * features_test.views_default.inc
+ */
+
+/**
+ * Implements hook_views_default_views().
+ */
+function features_test_views_default_views() {
+  $export = array();
+
+  $view = new view();
+  $view->name = 'features_test';
+  $view->description = 'Test view provided by Features testing module.';
+  $view->tag = 'testing';
+  $view->base_table = 'node';
+  $view->human_name = '';
+  $view->core = 0;
+  $view->api_version = '3.0';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Defaults */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->display->display_options['title'] = 'Test';
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'none';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['query']['options']['query_comment'] = FALSE;
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['style_plugin'] = 'default';
+  $handler->display->display_options['row_plugin'] = 'node';
+  $export['features_test'] = $view;
+
+  return $export;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/theme/features-admin-components.tpl.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+<?php
+?>
+<div class='clearfix features-components'>
+  <div class='column'>
+    <div class='info'>
+      <h3><?php print $name ?></h3>
+      <div class='description'><?php print $description ?></div>
+      <?php print $dependencies ?>
+    </div>
+  </div>
+  <div class='column'>
+    <div class='components'>
+      <?php print $components ?>
+      <?php if (!empty($key)): ?>
+        <div class='clearfix features-key'><?php print theme('links', array('links' => $key)) ?></div>
+      <?php endif; ?>
+      <?php if (!empty($buttons)): ?>
+        <div class='buttons clearfix'><?php print $buttons ?></div>
+      <?php endif; ?>
+    </div>
+  </div>
+  <?php print drupal_render_children($form) ?>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/features/theme/theme.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,331 @@
+<?php
+
+/**
+ * Display feature component info
+ */
+function template_preprocess_features_admin_components(&$vars) {
+  drupal_add_css(drupal_get_path('module', 'features') . '/features.css');
+  $form = $vars['form'];
+
+  // Basic info
+  $vars['name'] = $form['#info']['name'];
+  $vars['description'] = isset($form['#info']['description']) ? $form['#info']['description'] : '';
+
+  // Legend/key
+  $vars['key'] = array();
+
+  // Dependencies
+  $rows = array();
+  $modules = features_get_info();
+  foreach ($form['#dependencies'] as $dependency => $status) {
+    $rows[] = array(
+      array(
+        'data' => isset($modules[$dependency]->info['name']) ? $modules[$dependency]->info['name'] : $dependency,
+        'class' => 'component'
+      ),
+      theme('features_module_status', array('status' => $status)),
+    );
+  }
+  $vars['dependencies'] = theme('table', array('header' => array(t('Dependency'), t('Status')), 'rows' => $rows));
+
+  // Components
+  $rows = array();
+  $components = features_get_components();
+
+  // Display key for conflicting elements.
+  if (!empty($form['#conflicts'])) {
+    $vars['key'][] = array(
+      'title' => theme('features_storage_link', array('storage' => FEATURES_CONFLICT, 'text' => t('Conflicts with another feature'))),
+      'html' => TRUE,
+    );
+  }
+
+  if (!empty($form['#info']['features'])) {
+    foreach ($form['#info']['features'] as $component => $items) {
+      if (!empty($items)) {
+        $conflicts = array_key_exists($component, $form['#conflicts'])
+                ? $form['#conflicts'][$component]
+                : NULL;
+
+        $header = $data = array();
+        if (element_children($form['revert'])) {
+          $header[] = array(
+            'data' => isset($form['revert'][$component]) ? drupal_render($form['revert'][$component]) : '',
+            'header' => TRUE
+          );
+        }
+        $header[] = array(
+          'data' => isset($components[$component]['name']) ? $components[$component]['name'] : $component,
+          'header' => TRUE
+        );
+        $header[] = array(
+          'data' => drupal_render($form['components'][$component]),
+          'header' => TRUE
+        );
+        $rows[] = $header;
+
+        if (element_children($form['revert'])) {
+          $data[] = '';
+        }
+        $data[] = array(
+          'data' => theme('features_component_list', array('components' => $items, 'source' => $items, 'conflicts' => $conflicts)),
+          'colspan' => 2,
+          'class' => 'component'
+        );
+        $rows[] = $data;
+      }
+    }
+  }
+  $vars['components'] = theme('table', array('header' => array(), 'rows' => $rows));
+
+  // Other elements
+  $vars['buttons'] = drupal_render($form['buttons']);
+  $vars['form'] = $form;
+}
+
+/**
+ * Themes a module status display.
+ */
+function theme_features_module_status($vars) {
+  switch ($vars['status']) {
+    case FEATURES_MODULE_ENABLED:
+      $text_status = t('Enabled');
+      $class = 'admin-enabled';
+      break;
+    case FEATURES_MODULE_DISABLED:
+      $text_status = t('Disabled');
+      $class = 'admin-disabled';
+      break;
+    case FEATURES_MODULE_MISSING:
+      $text_status = t('Missing');
+      $class = 'admin-missing';
+      break;
+    case FEATURES_MODULE_CONFLICT:
+      $text_status = t('Enabled');
+      $class = 'admin-conflict';
+      break;
+  }
+  $text = !empty($vars['module']) ? $vars['module'] . ' (' . $text_status . ')' : $text_status;
+  return "<span class=\"$class\">$text</span>";
+}
+
+/**
+ * Themes a module status display.
+ */
+function theme_features_storage_link($vars) {
+  $classes = array(
+    FEATURES_OVERRIDDEN => 'admin-overridden',
+    FEATURES_DEFAULT => 'admin-default',
+    FEATURES_NEEDS_REVIEW => 'admin-needs-review',
+    FEATURES_REBUILDING => 'admin-rebuilding',
+    FEATURES_REBUILDABLE => 'admin-rebuilding',
+    FEATURES_CONFLICT => 'admin-conflict',
+    FEATURES_DISABLED => 'admin-disabled',
+    FEATURES_CHECKING => 'admin-loading',
+  );
+  $default_text = array(
+    FEATURES_OVERRIDDEN => t('Overridden'),
+    FEATURES_DEFAULT => t('Default'),
+    FEATURES_NEEDS_REVIEW => t('Needs review'),
+    FEATURES_REBUILDING => t('Rebuilding'),
+    FEATURES_REBUILDABLE => t('Rebuilding'),
+    FEATURES_CONFLICT => t('Conflict'),
+    FEATURES_DISABLED => t('Disabled'),
+    FEATURES_CHECKING => t('Checking...'),
+  );
+  $text = isset($vars['text']) ? $vars['text'] : $default_text[$vars['storage']];
+  if ($vars['path']) {
+    $vars['options']['attributes']['class'][] = $classes[$vars['storage']];
+    $vars['options']['attributes']['class'][] = 'features-storage';
+    return l($text, $vars['path'], $vars['options']);
+  }
+  else {
+    return "<span class='{$classes[$vars['storage']]} features-storage'>{$text}</span>";
+  }
+}
+
+/**
+ * Theme function for displaying form buttons
+ */
+function theme_features_form_buttons(&$vars) {
+  drupal_add_css(drupal_get_path('module', 'features') . '/features.css');
+
+  $output = drupal_render_children($vars['element']);
+  return !empty($output) ? "<div class='buttons clearfix'>{$output}</div>" : '';
+}
+
+/**
+ * Theme for features management form.
+ */
+function theme_features_form_package(&$vars) {
+  drupal_add_css(drupal_get_path('module', 'features') . '/features.css');
+  drupal_add_js(drupal_get_path('module', 'features') . '/features.js');
+
+  $output = '';
+
+  $header = array('', t('Feature'), t('Signature'));
+  if (isset($vars['form']['state'])) {
+    $header[] = t('State');
+  }
+  if (isset($vars['form']['actions'])) {
+    $header[] = t('Actions');
+  }
+
+  $rows = array();
+  foreach (element_children($vars['form']['status']) as $element) {
+    // Yank title & description fields off the form element for
+    // rendering in their own cells.
+    $name = "<div class='feature'>";
+    $name .= "<strong>{$vars['form']['status'][$element]['#title']}</strong>";
+    $name .= "<div class='description'>{$vars['form']['status'][$element]['#description']}</div>";
+    $name .= "</div>";
+    unset($vars['form']['status'][$element]['#title']);
+    unset($vars['form']['status'][$element]['#description']);
+
+
+    // Determine row & cell classes
+    $class = $vars['form']['status'][$element]['#default_value'] ? 'enabled' : 'disabled';
+
+    $row = array();
+    $row['status'] = array('data' => drupal_render($vars['form']['status'][$element]), 'class' => array('status'));
+    $row['name'] = array('data' => $name, 'class' => 'name');
+    $row['sign'] = array('data' => drupal_render($vars['form']['sign'][$element]), 'class' => array('sign'));
+
+    if (isset($vars['form']['state'])) {
+      $row['state'] = array('data' => drupal_render($vars['form']['state'][$element]), 'class' => array('state'));
+    }
+    if (isset($vars['form']['actions'])) {
+      $row['actions'] = array('data' => drupal_render($vars['form']['actions'][$element]), 'class' => array('actions'));
+    }
+    $rows[] = array('data' => $row, 'class' => array($class));
+  }
+
+  if (empty($rows)) {
+    $rows[] = array('', array('data' => t('No features available.'), 'colspan' => count($header)));
+  }
+
+  $class = count($header) > 3 ? 'features features-admin' : 'features features-manage';
+  $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'features-form-table', 'class' => array($class))));
+
+  // Prevent section from being rendered by drupal_render().
+
+  $output .= drupal_render($vars['form']['buttons']);
+  $output .= drupal_render_children($vars['form']);
+  return $output;
+}
+
+/**
+ * Theme functions ====================================================
+ */
+
+/**
+ * Export selection / display for features export form.
+ */
+function theme_features_form_export(&$vars) {
+  drupal_add_css(drupal_get_path('module', 'features') . '/features.css');
+  drupal_add_js(drupal_get_path('module', 'features') . '/features.js');
+
+  $output = '';
+  $output .= "<div class='clearfix features-components'>";
+  $output .= "<div class='column'>" . drupal_render($vars['form']['components']) . drupal_render($vars['form']['sources']) . "</div>";
+  $output .= "<div class='column'>" . drupal_render($vars['form']['preview']) . drupal_render($vars['form']['features']) . "</div>";
+  $output .= "</div>";
+  $output .= drupal_render_children($vars['form']);
+  return $output;
+}
+
+/**
+ * Theme a set of features export components.
+ */
+function theme_features_form_components(&$vars) {
+  $output = '';
+  foreach (element_children($vars['form']) as $key) {
+    unset($vars['form'][$key]['#title']);
+    $output .= "<div class='features-select features-select-{$key}'>" . drupal_render($vars['form'][$key]) . "</div>";
+  }
+  $output .= drupal_render_children($vars['form']);
+  return $output;
+}
+
+/**
+ * Theme a set of features export components.
+ */
+function theme_features_components($vars) {
+  $info = $vars['info'];
+  $sources = $vars['sources'];
+
+  $output = '';
+  $rows = array();
+  $components = features_get_components();
+  if (!empty($info['features']) || !empty($info['dependencies']) || !empty($sources)) {
+    $export = array_unique(array_merge(
+      array_keys($info['features']),
+      array_keys($sources),
+      array('dependencies')
+    ));
+    foreach ($export as $component) {
+      if ($component === 'dependencies') {
+        $feature_items = isset($info[$component]) ? $info[$component] : array();
+      }
+      else {
+        $feature_items = isset($info['features'][$component]) ? $info['features'][$component] : array();
+      }
+      $source_items = isset($sources[$component]) ? $sources[$component] : array();
+      if (!empty($feature_items) || !empty($source_items)) {
+        $rows[] = array(array(
+          'data' => isset($components[$component]['name']) ? $components[$component]['name'] : $component,
+          'header' => TRUE
+        ));
+        $rows[] = array(array(
+          'data' => theme('features_component_list', array('components' => $feature_items, 'source' => $source_items)),
+          'class' => 'component'
+        ));
+      }
+    }
+    $output .= theme('table', array('header' => array(), 'rows' => $rows));
+    $output .= theme('features_component_key', array());
+  }
+  return $output;
+}
+
+/**
+ * Theme individual components in a component list.
+ */
+function theme_features_component_list($vars) {
+  $components = $vars['components'];
+  $source = $vars['source'];
+  $conflicts = $vars['conflicts'];
+
+  $list = array();
+  foreach ($components as $component) {
+    // If component is not in source list, it was autodetected
+    if (!in_array($component, $source)) {
+      $list[] = "<span class='features-detected'>". check_plain($component) ."</span>";
+    }
+    elseif (is_array($conflicts) && in_array($component, $conflicts)) {
+      $list[] = "<span class='features-conflict'>". check_plain($component) ."</span>";
+    }
+    else {
+      $list[] = "<span class='features-source'>". check_plain($component) ."</span>";
+    }
+  }
+  foreach ($source as $component) {
+    // If a source component is no longer in the items, it was removed because
+    // it is provided by a dependency.
+    if (!in_array($component, $components)) {
+      $list[] = "<span class='features-dependency'>". check_plain($component) ."</span>";
+    }
+  }
+  return "<span class='features-component-list'>". implode(' ', $list) ."</span>";
+}
+
+/**
+ * Provide a themed key for a component list.
+ */
+function theme_features_component_key($vars) {
+  $list = array();
+  $list[] = "<span class='features-source'>" . t('Normal') . "</span>";
+  $list[] = "<span class='features-detected'>" . t('Auto-detected') . "</span>";
+  $list[] = "<span class='features-dependency'>" . t('Provided by dependency') . "</span>";
+  return "<span class='features-component-list features-component-key'>" . implode(' ', $list) . "</span>";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+
+Field collection
+-----------------
+Provides a field collection field, to which any number of fields can be attached.
+
+Each field collection item is internally represented as an entity, which is
+referenced via the field collection field in the host entity. While
+conceptually field collections are treated as part of the host entity, each
+field collection item may also be viewed and edited separately.
+ 
+
+ Usage
+ ------
+ 
+  * Add a field collection field to any entity, e.g. to a node. For that use the
+   the usual "Manage fields" interface provided by the "field ui" module of
+   Drupal, e.g. "Admin -> Structure-> Content types -> Article -> Manage fields".
+    
+  * Then go to "Admin -> Structure-> Field collection" to define some fields for
+   the created field collection.
+   
+  * By the default, the field collection is not shown during editing of the host
+    entity. However, some links for adding, editing or deleting field collection
+    items is shown when the host entity is viewed.
+  
+  * Widgets for embedding the form for creating field collections in the
+    host-entity can be provided by any module. In future the field collection
+    module might provide such widgets itself too.
+    
+
+Restrictions
+-------------
+
+  * As of now, the field collection field does not properly respect different
+    languages of the host entity. Thus, for now it is suggested to only use the
+    field for entities that are not translatable.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field-collection-item.tpl.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Default theme implementation for field collection items.
+ *
+ * Available variables:
+ * - $content: An array of comment items. Use render($content) to print them all, or
+ *   print a subset such as render($content['field_example']). Use
+ *   hide($content['field_example']) to temporarily suppress the printing of a
+ *   given element.
+ * - $title: The (sanitized) field collection item label.
+ * - $url: Direct url of the current entity if specified.
+ * - $page: Flag for the full page state.
+ * - $classes: String of classes that can be used to style contextually through
+ *   CSS. It can be manipulated through the variable $classes_array from
+ *   preprocess functions. By default the following classes are available, where
+ *   the parts enclosed by {} are replaced by the appropriate values:
+ *   - entity-field-collection-item
+ *   - field-collection-item-{field_name}
+ *
+ * Other variables:
+ * - $classes_array: Array of html class attribute values. It is flattened
+ *   into a string within the variable $classes.
+ *
+ * @see template_preprocess()
+ * @see template_preprocess_entity()
+ * @see template_process()
+ */
+?>
+<div class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
+  <div class="content"<?php print $content_attributes; ?>>
+    <?php
+      print render($content);
+    ?>
+  </div>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Provides the field_collection module admin pages.
+ */
+
+/**
+ * Menu callback; list all field collections on this site.
+ */
+function field_collections_overview() {
+  $instances = field_info_instances();
+  $field_types = field_info_field_types();
+  $bundles = field_info_bundles();
+  $header = array(t('Field name'), t('Used in'), array('data' => t('Operations'), 'colspan' => '2'));
+  $rows = array();
+  foreach ($instances as $entity_type => $type_bundles) {
+    foreach ($type_bundles as $bundle => $bundle_instances) {
+      foreach ($bundle_instances as $field_name => $instance) {
+        $field = field_info_field($field_name);
+        if ($field['type'] == 'field_collection') {
+          $admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
+          $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
+
+          $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
+          $rows[$field_name]['data'][1][] = l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields');
+        }
+      }
+    }
+  }
+  foreach ($rows as $field_name => $cell) {
+    $rows[$field_name]['data'][1] = implode(', ', $cell['data'][1]);
+
+    $field_name_url_str = strtr($field_name, array('_' => '-'));
+    $rows[$field_name]['data'][2] = l(t('manage fields'), 'admin/structure/field-collections/' . $field_name_url_str . '/fields');
+    $rows[$field_name]['data'][3] = l(t('manage display'), 'admin/structure/field-collections/' . $field_name_url_str . '/display');
+  }
+  if (empty($rows)) {
+    $output = t('No field collections have been defined yet. To do so attach a field collection field to any entity.');
+  }
+  else {
+    // Sort rows by field name.
+    ksort($rows);
+    $output = theme('table', array('header' => $header, 'rows' => $rows));
+  }
+  return $output;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,169 @@
+<?php
+
+/**
+ * @file
+ * Contains API documentation and examples for the Field collection module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Alter whether a field collection item is considered empty.
+ *
+ * This hook allows modules to determine whether a field collection is empty
+ * before it is saved.
+ *
+ * @param boolean $empty
+ *   Whether or not the field should be considered empty.
+ * @param FieldCollectionItemEntity $item
+ *   The field collection we are currently operating on.
+ */
+function hook_field_collection_is_empty_alter(&$is_empty, FieldCollectionItemEntity $item) {
+  if (isset($item->my_field) && empty($item->my_field)) {
+    $is_empty = TRUE;
+  }
+}
+
+/**
+ * Acts on field collections being loaded from the database.
+ *
+ * This hook is invoked during field collection item loading, which is handled
+ * by entity_load(), via the EntityCRUDController.
+ *
+ * @param array $entities
+ *   An array of field collection item entities being loaded, keyed by id.
+ *
+ * @see hook_entity_load()
+ */
+function hook_field_collection_item_load(array $entities) {
+  $result = db_query('SELECT pid, foo FROM {mytable} WHERE pid IN(:ids)', array(':ids' => array_keys($entities)));
+  foreach ($result as $record) {
+    $entities[$record->pid]->foo = $record->foo;
+  }
+}
+
+/**
+ * Responds when a field collection item is inserted.
+ *
+ * This hook is invoked after the field collection item is inserted into the
+ * database.
+ *
+ * @param FieldCollectionItemEntity $field_collection_item
+ *   The field collection item that is being inserted.
+ *
+ * @see hook_entity_insert()
+ */
+function hook_field_collection_item_insert(FieldCollectionItemEntity $field_collection_item) {
+  db_insert('mytable')->fields(array(
+    'id' => entity_id('field_collection_item', $field_collection_item),
+    'extra' => print_r($field_collection_item, TRUE),
+  ))->execute();
+}
+
+/**
+ * Acts on a field collection item being inserted or updated.
+ *
+ * This hook is invoked before the field collection item is saved to the database.
+ *
+ * @param FieldCollectionItemEntity $field_collection_item
+ *   The field collection item that is being inserted or updated.
+ *
+ * @see hook_entity_presave()
+ */
+function hook_field_collection_item_presave(FieldCollectionItemEntity $field_collection_item) {
+  $field_collection_item->name = 'foo';
+}
+
+/**
+ * Responds to a field collection item being updated.
+ *
+ * This hook is invoked after the field collection item has been updated in the
+ * database.
+ *
+ * @param FieldCollectionItemEntity $field_collection_item
+ *   The field collection item that is being updated.
+ *
+ * @see hook_entity_update()
+ */
+function hook_field_collection_item_update(FieldCollectionItemEntity $field_collection_item) {
+  db_update('mytable')
+    ->fields(array('extra' => print_r($field_collection_item, TRUE)))
+    ->condition('id', entity_id('field_collection_item', $field_collection_item))
+    ->execute();
+}
+
+/**
+ * Responds to field collection item deletion.
+ *
+ * This hook is invoked after the field collection item has been removed from
+ * the database.
+ *
+ * @param FieldCollectionItemEntity $field_collection_item
+ *   The field collection item that is being deleted.
+ *
+ * @see hook_entity_delete()
+ */
+function hook_field_collection_item_delete(FieldCollectionItemEntity $field_collection_item) {
+  db_delete('mytable')
+    ->condition('pid', entity_id('field_collection_item', $field_collection_item))
+    ->execute();
+}
+
+/**
+ * Act on a field collection item that is being assembled before rendering.
+ *
+ * @param $field_collection_item
+ *   The field collection item entity.
+ * @param $view_mode
+ *   The view mode the field collection item is rendered in.
+ * @param $langcode
+ *   The language code used for rendering.
+ *
+ * The module may add elements to $field_collection_item->content prior to
+ * rendering. The structure of $field_collection_item->content is a renderable
+ * array as expected by drupal_render().
+ *
+ * @see hook_entity_prepare_view()
+ * @see hook_entity_view()
+ */
+function hook_field_collection_item_view($field_collection_item, $view_mode, $langcode) {
+  $field_collection_item->content['my_additional_field'] = array(
+    '#markup' => $additional_field,
+    '#weight' => 10,
+    '#theme' => 'mymodule_my_additional_field',
+  );
+}
+
+/**
+ * Alter the results of entity_view() for field collection items.
+ *
+  * This hook is called after the content has been assembled in a structured
+ * array and may be used for doing processing which requires that the complete
+ * field collection item content structure has been built.
+ *
+ * If the module wishes to act on the rendered HTML of the field collection item
+ * rather than the structured content array, it may use this hook to add a
+ * #post_render callback. See drupal_render() and theme() documentation
+ * respectively for details.
+ *
+ * @param $build
+ *   A renderable array representing the field collection item content.
+ *
+ * @see hook_entity_view_alter()
+ */
+function hook_field_collection_item_view_alter($build) {
+  if ($build['#view_mode'] == 'full' && isset($build['an_additional_field'])) {
+    // Change its weight.
+    $build['an_additional_field']['#weight'] = -10;
+
+    // Add a #post_render callback to act on the rendered HTML of the entity.
+    $build['#post_render'][] = 'my_module_post_render';
+  }
+}
+
+/**
+ * @}
+ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,16 @@
+name = Field collection
+description = Provides a field collection field, to which any number of fields can be attached.
+core = 7.x
+dependencies[] = entity
+files[] = field_collection.test
+files[] = field_collection.info.inc
+files[] = views/field_collection_handler_relationship.inc
+configure = admin/structure/field-collections
+package = Fields
+
+; Information added by drupal.org packaging script on 2012-12-25
+version = "7.x-1.0-beta5"
+core = "7.x"
+project = "field_collection"
+datestamp = "1356475963"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.info.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Provides entity property info for field collection items.
+ */
+
+class FieldCollectionItemMetadataController extends EntityDefaultMetadataController {
+
+  public function entityPropertyInfo() {
+    $info = parent::entityPropertyInfo();
+    $properties = &$info['field_collection_item']['properties'];
+
+    $properties['field_name']['label'] = t('Field name');
+    $properties['field_name']['description'] = t('The machine-readable name of the field collection field containing this item.');
+    $properties['field_name']['required'] = TRUE;
+
+    $properties['host_entity'] = array(
+      'label' => t('Host entity'),
+      'type' => 'entity',
+      'description' => t('The entity containing the field collection field.'),
+      'getter callback' => 'field_collection_item_get_host_entity',
+      'setter callback' => 'field_collection_item_set_host_entity',
+      'required' => TRUE,
+    );
+
+    return $info;
+  }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,215 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the field_collection module.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function field_collection_schema() {
+
+  $schema['field_collection_item'] = array(
+    'description' => 'Stores information about field collection items.',
+    'fields' => array(
+      'item_id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique field collection item ID.',
+      ),
+      'revision_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'description' => 'Default revision ID.',
+      ),
+      'field_name' => array(
+        'description' => 'The name of the field on the host entity embedding this entity.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+      ),
+      'archived' => array(
+        'description' => 'Boolean indicating whether the field collection item is archived.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('item_id'),
+  );
+  $schema['field_collection_item_revision'] = array(
+    'description' => 'Stores revision information about field collection items.',
+    'fields' => array(
+      'revision_id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique revision ID.',
+      ),
+      'item_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'description' => 'Field collection item ID.',
+      ),
+    ),
+    'primary key' => array('revision_id'),
+    'indexes' => array(
+      'item_id' => array('item_id'),
+    ),
+    'foreign keys' => array(
+      'versioned_field_collection_item' => array(
+        'table' => 'field_collection_item',
+        'columns' => array('item_id' => 'item_id'),
+      ),
+    ),
+  );
+  return $schema;
+}
+
+/**
+ * Implements hook_field_schema().
+ */
+function field_collection_field_schema($field) {
+  $columns = array(
+    'value' => array(
+      'type' => 'int',
+      'not null' => FALSE,
+      'description' => 'The field collection item id.',
+    ),
+    'revision_id' => array(
+      'type' => 'int',
+      'not null' => FALSE,
+      'description' => 'The field collection item revision id.',
+    ),
+  );
+  return array(
+    'columns' => $columns,
+  );
+}
+
+/**
+ * Update the administer field collection permission machine name.
+ */
+function field_collection_update_7000() {
+  db_update('role_permission')
+    ->fields(array('permission' => 'administer field collections'))
+    ->condition('permission', 'administer field-collections')
+    ->execute();
+}
+
+/**
+ * Add revision support.
+ */
+function field_collection_update_7001() {
+
+  // Add revision_id column to field_collection_item table.
+  $revision_id_spec = array(
+    'type' => 'int',
+    'not null' => TRUE,
+    'description' => 'Default revision ID.',
+    // Set default to 0 temporarily.
+    'initial' => 0,
+  );
+  db_add_field('field_collection_item', 'revision_id', $revision_id_spec);
+
+  // Initialize the revision_id to be the same as the item_id.
+  db_update('field_collection_item')
+    ->expression('revision_id', 'item_id')
+    ->execute();
+
+  // Add the archived column
+  $archived_spec = array(
+    'description' => 'Boolean indicating whether the field collection item is archived.',
+    'type' => 'int',
+    'not null' => TRUE,
+    'default' => 0,
+  );
+  db_add_field('field_collection_item', 'archived', $archived_spec);
+
+  // Create the new table. It is important to explicitly define the schema here
+  // rather than use the hook_schema definition: http://drupal.org/node/150220.
+  $schema['field_collection_item_revision'] = array(
+    'description' => 'Stores revision information about field collection items.',
+    'fields' => array(
+      'revision_id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique revision ID.',
+      ),
+      'item_id' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'description' => 'Field collection item ID.',
+      ),
+    ),
+    'primary key' => array('revision_id'),
+    'indexes' => array(
+      'item_id' => array('item_id'),
+    ),
+    'foreign keys' => array(
+      'versioned_field_collection_item' => array(
+        'table' => 'field_collection_item',
+        'columns' => array('item_id' => 'item_id'),
+      ),
+    ),
+  );
+  db_create_table('field_collection_item_revision', $schema['field_collection_item_revision']);
+
+  // Fill the new table with the correct data.
+  $items = db_select('field_collection_item', 'fci')
+    ->fields('fci')
+    ->execute();
+  foreach ($items as $item) {
+    // Update field_collection_item_revision table.
+    db_insert('field_collection_item_revision')
+      ->fields(array(
+        'revision_id' => $item->item_id,
+        'item_id' => $item->item_id,
+      ))
+      ->execute();
+  }
+
+  // Update the field_collection_field_schema columns for all tables.
+  foreach (field_read_fields(array('type' => 'field_collection')) as $field_name => $field) {
+    $table_prefixes = array('field_data', 'field_revision');
+    foreach ($table_prefixes as $table_prefix) {
+
+      $table = sprintf('%s_%s', $table_prefix, $field_name);
+      $value_column = sprintf('%s_value', $field_name);
+      $revision_id_column = sprintf('%s_revision_id', $field_name);
+
+      // Add a revision_id column.
+      $revision_id_spec['description'] = 'The field collection item revision id.';
+      db_add_field($table, $revision_id_column, $revision_id_spec);
+
+      // Initialize the revision_id to be the same as the item_id.
+      db_update($table)
+        ->expression($revision_id_column, $value_column)
+        ->execute();
+    }
+  }
+
+  // Need to get the system up-to-date so drupal_schema_fields_sql() will work.
+  $schema = drupal_get_schema('field_collection_item_revision', TRUE);
+}
+
+/**
+ * Remove orphaned field collection item entities.
+ */
+function field_collection_update_7002() {
+  // Loop over all fields and delete any orphaned field collection items.
+  foreach (field_read_fields(array('type' => 'field_collection')) as $field_name => $field) {
+
+    $select = db_select('field_collection_item', 'fci')
+      ->fields('fci', array('item_id'))
+      ->condition('field_name', $field_name)
+      ->condition('archived', 0);
+    $select->leftJoin('field_data_' . $field_name, 'field', "field.{$field_name}_value = fci.item_id ");
+    $select->isNull('field.entity_id');
+    $ids = $select->execute()->fetchCol(0);
+
+    entity_delete_multiple('field_collection_item', $ids);
+    $count = count($ids);
+    drupal_set_message("Deleted $count orphaned field collection items.");
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1864 @@
+<?php
+
+/**
+ * @file
+ * Module implementing field collection field type.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function field_collection_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#field_collection':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The field collection module provides a field, to which any number of fields can be attached. See the <a href="@field-help">Field module help page</a> for more information about fields.', array('@field-help' => url('admin/help/field'))) . '</p>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function field_collection_entity_info() {
+  $return['field_collection_item'] = array(
+    'label' => t('Field collection item'),
+    'label callback' => 'entity_class_label',
+    'uri callback' => 'entity_class_uri',
+    'entity class' => 'FieldCollectionItemEntity',
+    'controller class' => 'EntityAPIController',
+    'base table' => 'field_collection_item',
+    'revision table' => 'field_collection_item_revision',
+    'fieldable' => TRUE,
+    // For integration with Redirect module.
+    // @see http://drupal.org/node/1263884
+    'redirect' => FALSE,
+    'entity keys' => array(
+      'id' => 'item_id',
+      'revision' => 'revision_id',
+      'bundle' => 'field_name',
+    ),
+    'module' => 'field_collection',
+    'view modes' => array(
+      'full' => array(
+        'label' => t('Full content'),
+        'custom settings' => FALSE,
+       ),
+    ),
+    'access callback' => 'field_collection_item_access',
+    'metadata controller class' => 'FieldCollectionItemMetadataController'
+  );
+
+  // Add info about the bundles. We do not use field_info_fields() but directly
+  // use field_read_fields() as field_info_fields() requires built entity info
+  // to work.
+  foreach (field_read_fields(array('type' => 'field_collection')) as $field_name => $field) {
+    $return['field_collection_item']['bundles'][$field_name] = array(
+      'label' => t('Field collection @field', array('@field' => $field_name)),
+      'admin' => array(
+        'path' => 'admin/structure/field-collections/%field_collection_field_name',
+        'real path' => 'admin/structure/field-collections/' . strtr($field_name, array('_' => '-')),
+        'bundle argument' => 3,
+        'access arguments' => array('administer field collections'),
+      ),
+    );
+  }
+
+  return $return;
+}
+
+/**
+ * Menu callback for loading the bundle names.
+ */
+function field_collection_field_name_load($arg) {
+  $field_name = strtr($arg, array('-' => '_'));
+  if (($field = field_info_field($field_name)) && $field['type'] == 'field_collection') {
+    return $field_name;
+  }
+}
+
+/**
+ * Loads a field collection item.
+ *
+ * @return field_collection_item
+ *   The field collection item entity or FALSE.
+ */
+function field_collection_item_load($item_id, $reset = FALSE) {
+  $result = field_collection_item_load_multiple(array($item_id), array(), $reset);
+  return $result ? reset($result) : FALSE;
+}
+
+/**
+ * Loads a field collection revision.
+ *
+ * @param $revision_id
+ *   The field collection revision ID.
+ */
+function field_collection_item_revision_load($revision_id) {
+  return entity_revision_load('field_collection_item', $revision_id);
+}
+
+/**
+ * Loads field collection items.
+ *
+ * @return
+ *   An array of field collection item entities.
+ */
+function field_collection_item_load_multiple($ids = array(), $conditions = array(), $reset = FALSE) {
+  return entity_load('field_collection_item', $ids, $conditions, $reset);
+}
+
+/**
+ * Class for field_collection_item entities.
+ */
+class FieldCollectionItemEntity extends Entity {
+
+  /**
+   * Field collection field info.
+   *
+   * @var array
+   */
+  protected $fieldInfo;
+
+  /**
+   * The host entity object.
+   *
+   * @var object
+   */
+  protected $hostEntity;
+
+  /**
+   * The host entity ID.
+   *
+   * @var integer
+   */
+  protected $hostEntityId;
+
+  /**
+   * The host entity revision ID if this is not the default revision.
+   *
+   * @var integer
+   */
+  protected $hostEntityRevisionId;
+
+  /**
+   * The host entity type.
+   *
+   * @var string
+   */
+  protected $hostEntityType;
+
+  /**
+   * The language under which the field collection item is stored.
+   *
+   * @var string
+   */
+  protected $langcode = LANGUAGE_NONE;
+
+  /**
+   * Entity ID.
+   *
+   * @var integer
+   */
+  public $item_id;
+
+  /**
+   * Field collection revision ID.
+   *
+   * @var integer
+   */
+  public $revision_id;
+
+  /**
+   * The name of the field-collection field this item is associated with.
+   *
+   * @var string
+   */
+  public $field_name;
+
+  /**
+   * Whether this revision is the default revision.
+   *
+   * @var bool
+   */
+  public $default_revision = TRUE;
+
+  /**
+   * Whether the field collection item is archived, i.e. not in use.
+   *
+   * @see FieldCollectionItemEntity::isInUse()
+   * @var bool
+   */
+  public $archived = FALSE;
+
+  /**
+   * Constructs the entity object.
+   */
+  public function __construct(array $values = array(), $entityType = NULL) {
+    parent::__construct($values, 'field_collection_item');
+    // Workaround issues http://drupal.org/node/1084268 and
+    // http://drupal.org/node/1264440:
+    // Check if the required property is set before checking for the field's
+    // type. If the property is not set, we are hitting a PDO or a core's bug.
+    // FIXME: Remove when #1264440 is fixed and the required PHP version is
+    //  properly identified and documented in the module documentation.
+    if (isset($this->field_name)) {
+      // Ok, we have the field name property, we can proceed and check the field's type
+      $field_info = $this->fieldInfo();
+      if (!$field_info || $field_info['type'] != 'field_collection') {
+        throw new Exception("Invalid field name given: {$this->field_name} is not a Field Collection field.");
+      }
+    }
+  }
+
+  /**
+   * Provides info about the field on the host entity, which embeds this
+   * field collection item.
+   */
+  public function fieldInfo() {
+    return field_info_field($this->field_name);
+  }
+
+  /**
+   * Provides info of the field instance containing the reference to this
+   * field collection item.
+   */
+  public function instanceInfo() {
+    if ($this->fetchHostDetails()) {
+      return field_info_instance($this->hostEntityType(), $this->field_name, $this->hostEntityBundle());
+    }
+  }
+
+  /**
+   * Returns the field instance label translated to interface language.
+   */
+  public function translatedInstanceLabel($langcode = NULL) {
+    if ($info = $this->instanceInfo()) {
+      if (module_exists('i18n_field')) {
+        return i18n_string("field:{$this->field_name}:{$info['bundle']}:label", $info['label'], array('langcode' => $langcode));
+      }
+      return $info['label'];
+    }
+  }
+
+  /**
+   * Specifies the default label, which is picked up by label() by default.
+   */
+  public function defaultLabel() {
+    // @todo make configurable.
+    if ($this->fetchHostDetails()) {
+      $field = $this->fieldInfo();
+      $label = $this->translatedInstanceLabel();
+
+      if ($field['cardinality'] == 1) {
+        return $label;
+      }
+      elseif ($this->item_id) {
+        return t('!instance_label @count', array('!instance_label' => $label, '@count' => $this->delta() + 1));
+      }
+      else {
+        return t('New !instance_label', array('!instance_label' => $label));
+      }
+    }
+    return t('Unconnected field collection item');
+  }
+
+  /**
+   * Returns the path used to view the entity.
+   */
+  public function path() {
+    if ($this->item_id) {
+      return field_collection_field_get_path($this->fieldInfo()) . '/' . $this->item_id;
+    }
+  }
+
+  /**
+   * Returns the URI as returned by entity_uri().
+   */
+  public function defaultUri() {
+    return array(
+      'path' => $this->path(),
+    );
+  }
+
+  /**
+   * Sets the host entity. Only possible during creation of a item.
+   *
+   * @param $create_link
+   *   (optional) Whether a field-item linking the host entity to the field
+   *   collection item should be created.
+   */
+  public function setHostEntity($entity_type, $entity, $langcode = LANGUAGE_NONE, $create_link = TRUE) {
+    if (!empty($this->is_new)) {
+      $this->hostEntityType = $entity_type;
+      $this->hostEntity = $entity;
+      $this->langcode = $langcode;
+
+      list($this->hostEntityId, $this->hostEntityRevisionId) = entity_extract_ids($this->hostEntityType, $this->hostEntity);
+      // If the host entity is not saved yet, set the id to FALSE. So
+      // fetchHostDetails() does not try to load the host entity details.
+      if (!isset($this->hostEntityId)) {
+        $this->hostEntityId = FALSE;
+      }
+      // We are create a new field collection for a non-default entity, thus
+      // set archived to TRUE.
+      if (!entity_revision_is_default($entity_type, $entity)) {
+        $this->hostEntityId = FALSE;
+        $this->archived = TRUE;
+      }
+      if ($create_link) {
+        $entity->{$this->field_name}[$this->langcode][] = array('entity' => $this);
+      }
+    }
+    else {
+      throw new Exception('The host entity may be set only during creation of a field collection item.');
+    }
+  }
+
+  /**
+   * Returns the host entity, which embeds this field collection item.
+   */
+  public function hostEntity() {
+    if ($this->fetchHostDetails()) {
+      if (!isset($this->hostEntity) && $this->isInUse()) {
+        $this->hostEntity = entity_load_single($this->hostEntityType, $this->hostEntityId);
+      }
+      elseif (!isset($this->hostEntity) && $this->hostEntityRevisionId) {
+        $this->hostEntity = entity_revision_load($this->hostEntityType, $this->hostEntityRevisionId);
+      }
+      return $this->hostEntity;
+    }
+  }
+
+  /**
+   * Returns the entity type of the host entity, which embeds this
+   * field collection item.
+   */
+  public function hostEntityType() {
+    if ($this->fetchHostDetails()) {
+      return $this->hostEntityType;
+    }
+  }
+
+  /**
+   * Returns the id of the host entity, which embeds this field collection item.
+   */
+  public function hostEntityId() {
+    if ($this->fetchHostDetails()) {
+      if (!$this->hostEntityId && $this->hostEntityRevisionId) {
+        $this->hostEntityId = entity_id($this->hostEntityType, $this->hostEntity());
+      }
+      return $this->hostEntityId;
+    }
+  }
+
+  /**
+   * Returns the bundle of the host entity, which embeds this field collection
+   * item.
+   */
+  public function hostEntityBundle() {
+    if ($entity = $this->hostEntity()) {
+      list($id, $rev_id, $bundle) = entity_extract_ids($this->hostEntityType, $entity);
+      return $bundle;
+    }
+  }
+
+  protected function fetchHostDetails() {
+    if (!isset($this->hostEntityId)) {
+      if ($this->item_id) {
+        // For saved field collections, query the field data to determine the
+        // right host entity.
+        $query = new EntityFieldQuery();
+        $query->fieldCondition($this->fieldInfo(), 'revision_id', $this->revision_id);
+        if (!$this->isInUse()) {
+          $query->age(FIELD_LOAD_REVISION);
+        }
+        $result = $query->execute();
+        list($this->hostEntityType, $data) = each($result);
+
+        if ($this->isInUse()) {
+          $this->hostEntityId = $data ? key($data) : FALSE;
+          $this->hostEntityRevisionId = FALSE;
+        }
+        // If we are querying for revisions, we get the revision ID.
+        else {
+          $this->hostEntityId = FALSE;
+          $this->hostEntityRevisionId = $data ? key($data) : FALSE;
+        }
+      }
+      else {
+        // No host entity available yet.
+        $this->hostEntityId = FALSE;
+      }
+    }
+    return !empty($this->hostEntityId) || !empty($this->hostEntity) || !empty($this->hostEntityRevisionId);
+  }
+
+  /**
+   * Determines the $delta of the reference pointing to this field collection
+   * item.
+   */
+  public function delta() {
+    if (($entity = $this->hostEntity()) && isset($entity->{$this->field_name})) {
+      foreach ($entity->{$this->field_name} as $langcode => &$data) {
+        foreach ($data as $delta => $item) {
+          if (isset($item['value']) && $item['value'] == $this->item_id) {
+            $this->langcode = $langcode;
+            return $delta;
+          }
+          elseif (isset($item['entity']) && $item['entity'] === $this) {
+            $this->langcode = $langcode;
+            return $delta;
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Determines the language code under which the item is stored.
+   */
+  public function langcode() {
+    if ($this->delta() != NULL) {
+      return $this->langcode;
+    }
+  }
+
+  /**
+   * Determines whether this field collection item revision is in use.
+   *
+   * Field collection items may be contained in from non-default host entity
+   * revisions. If the field collection item does not appear in the default
+   * host entity revision, the item is actually not used by default and so
+   * marked as 'archived'.
+   * If the field collection item appears in the default revision of the host
+   * entity, the default revision of the field collection item is in use there
+   * and the collection is not marked as archived.
+   */
+  public function isInUse() {
+    return $this->default_revision && !$this->archived;
+  }
+
+  /**
+   * Save the field collection item.
+   *
+   * By default, always save the host entity, so modules are able to react
+   * upon changes to the content of the host and any 'last updated' dates of
+   * entities get updated.
+   *
+   * For creating an item a host entity has to be specified via setHostEntity()
+   * before this function is invoked. For the link between the entities to be
+   * fully established, the host entity object has to be updated to include a
+   * reference on this field collection item during saving. So do not skip
+   * saving the host for creating items.
+   *
+   * @param $skip_host_save
+   *   (internal) If TRUE is passed, the host entity is not saved automatically
+   *   and therefore no link is created between the host and the item or
+   *   revision updates might be skipped. Use with care.
+   */
+  public function save($skip_host_save = FALSE) {
+    // Make sure we have a host entity during creation.
+    if (!empty($this->is_new) && !(isset($this->hostEntityId) || isset($this->hostEntity) || isset($this->hostEntityRevisionId))) {
+      throw new Exception("Unable to create a field collection item without a given host entity.");
+    }
+
+    // Only save directly if we are told to skip saving the host entity. Else,
+    // we always save via the host as saving the host might trigger saving
+    // field collection items anyway (e.g. if a new revision is created).
+    if ($skip_host_save) {
+      return entity_get_controller($this->entityType)->save($this);
+    }
+    else {
+      $host_entity = $this->hostEntity();
+      if (!$host_entity) {
+        throw new Exception("Unable to save a field collection item without a valid reference to a host entity.");
+      }
+      // If this is creating a new revision, also do so for the host entity.
+      if (!empty($this->revision) || !empty($this->is_new_revision)) {
+        $host_entity->revision = TRUE;
+        if (!empty($this->default_revision)) {
+          entity_revision_set_default($this->hostEntityType, $host_entity);
+        }
+      }
+      // Set the host entity reference, so the item will be saved with the host.
+      // @see field_collection_field_presave()
+      $delta = $this->delta();
+      if (isset($delta)) {
+        $host_entity->{$this->field_name}[$this->langcode][$delta] = array('entity' => $this);
+      }
+      else {
+        $host_entity->{$this->field_name}[$this->langcode][] =  array('entity' => $this);
+      }
+      return entity_save($this->hostEntityType, $host_entity);
+    }
+  }
+
+  /**
+   * Deletes the field collection item and the reference in the host entity.
+   */
+  public function delete() {
+    parent::delete();
+    $this->deleteHostEntityReference();
+  }
+
+  /**
+   * Deletes the host entity's reference of the field collection item.
+   */
+  protected function deleteHostEntityReference() {
+    $delta = $this->delta();
+    if ($this->item_id && isset($delta)) {
+      unset($this->hostEntity->{$this->field_name}[$this->langcode][$delta]);
+      entity_save($this->hostEntityType, $this->hostEntity);
+    }
+  }
+
+  /**
+   * Intelligently delete a field collection item revision.
+   *
+   * If a host entity is revisioned with its field collection items, deleting
+   * a field collection item on the default revision of the host should not
+   * delete the collection item from archived revisions too. Instead, we delete
+   * the current default revision and archive the field collection.
+   *
+   * If no revisions are left or the host is not revisionable, the whole item
+   * is deleted.
+   */
+  public function deleteRevision($skip_host_update = FALSE) {
+    if (!$this->revision_id) {
+      return;
+    }
+    $info = entity_get_info($this->hostEntityType());
+    if (empty($info['entity keys']['revision']) || !$this->hostEntity()) {
+      return $this->delete();
+    }
+    if (!$skip_host_update) {
+      // Just remove the item from the host, which cares about deleting the
+      // item (depending on whether the update creates a new revision).
+      $this->deleteHostEntityReference();
+    }
+    elseif (!$this->isDefaultRevision()) {
+      entity_revision_delete('field_collection_item', $this->revision_id);
+    }
+    // If deleting the default revision, take care!
+    else {
+      $row = db_select('field_collection_item_revision', 'r')
+        ->fields('r')
+        ->condition('item_id', $this->item_id)
+        ->condition('revision_id', $this->revision_id, '<>')
+        ->execute()
+        ->fetchAssoc();
+      // If no other revision is left, delete. Else archive the item.
+      if (!$row) {
+        $this->delete();
+      }
+      else {
+        // Make the other revision the default revision and archive the item.
+        db_update('field_collection_item')
+          ->fields(array('archived' => 1, 'revision_id' => $row['revision_id']))
+          ->condition('item_id', $this->item_id)
+          ->execute();
+        entity_get_controller('field_collection_item')->resetCache(array($this->item_id));
+        entity_revision_delete('field_collection_item', $this->revision_id);
+      }
+    }
+  }
+
+  /**
+   * Export the field collection item.
+   *
+   * Since field collection entities are not directly exportable (i.e., do not
+   * have 'exportable' set to TRUE in hook_entity_info()) and since Features
+   * calls this method when exporting the field collection as a field attached
+   * to another entity, we return the export in the format expected by
+   * Features, rather than in the normal Entity::export() format.
+   */
+  public function export($prefix = '') {
+    // Based on code in EntityDefaultFeaturesController::export_render().
+    $export = "entity_import('" . $this->entityType() . "', '";
+    $export .= addcslashes(parent::export(), '\\\'');
+    $export .= "')";
+    return $export;
+  }
+
+  /**
+   * Magic method to only serialize what's necessary.
+   */
+  public function __sleep() {
+    $vars = get_object_vars($this);
+    unset($vars['entityInfo'], $vars['idKey'], $vars['nameKey'], $vars['statusKey']);
+    unset($vars['fieldInfo']);
+    // Also do not serialize the host entity, but only if it has already an id.
+    if ($this->hostEntity && ($this->hostEntityId || $this->hostEntityRevisionId)) {
+      unset($vars['hostEntity']);
+    }
+
+    // Also key the returned array with the variable names so the method may
+    // be easily overridden and customized.
+    return drupal_map_assoc(array_keys($vars));
+  }
+
+  /**
+   * Magic method to invoke setUp() on unserialization.
+   *
+   * @todo: Remove this once it appears in a released entity API module version.
+   */
+  public function __wakeup() {
+    $this->setUp();
+  }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function field_collection_menu() {
+  $items = array();
+  if (module_exists('field_ui')) {
+    $items['admin/structure/field-collections'] = array(
+      'title' => 'Field collections',
+      'description' => 'Manage fields on field collections.',
+      'page callback' => 'field_collections_overview',
+      'access arguments' => array('administer field collections'),
+      'type' => MENU_NORMAL_ITEM,
+      'file' => 'field_collection.admin.inc',
+    );
+  }
+
+  // Add menu paths for viewing/editing/deleting field collection items.
+  foreach (field_info_fields() as $field) {
+    if ($field['type'] == 'field_collection') {
+      $path = field_collection_field_get_path($field);
+      $count = count(explode('/', $path));
+
+      $items[$path . '/%field_collection_item'] = array(
+        'page callback' => 'field_collection_item_page_view',
+        'page arguments' => array($count),
+        'access callback' => 'field_collection_item_access',
+        'access arguments' => array('view', $count),
+        'file' => 'field_collection.pages.inc',
+      );
+      $items[$path . '/%field_collection_item/view'] = array(
+        'title' => 'View',
+        'type' => MENU_DEFAULT_LOCAL_TASK,
+        'weight' => -10,
+      );
+      $items[$path . '/%field_collection_item/edit'] = array(
+        'page callback' => 'drupal_get_form',
+        'page arguments' => array('field_collection_item_form', $count),
+        'access callback' => 'field_collection_item_access',
+        'access arguments' => array('update', $count),
+        'title' => 'Edit',
+        'type' => MENU_LOCAL_TASK,
+        'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+        'file' => 'field_collection.pages.inc',
+      );
+      $items[$path . '/%field_collection_item/delete'] = array(
+        'page callback' => 'drupal_get_form',
+        'page arguments' => array('field_collection_item_delete_confirm', $count),
+        'access callback' => 'field_collection_item_access',
+        'access arguments' => array('delete', $count),
+        'title' => 'Delete',
+        'type' => MENU_LOCAL_TASK,
+        'context' => MENU_CONTEXT_INLINE,
+        'file' => 'field_collection.pages.inc',
+      );
+      // Add entity type and the entity id as additional arguments.
+      $items[$path . '/add/%/%'] = array(
+        'page callback' => 'field_collection_item_add',
+        'page arguments' => array($field['field_name'], $count + 1, $count + 2),
+        // The pace callback takes care of checking access itself.
+        'access callback' => TRUE,
+        'file' => 'field_collection.pages.inc',
+      );
+      // Add menu items for dealing with revisions.
+      $items[$path . '/%field_collection_item/revisions/%field_collection_item_revision'] = array(
+        'page callback' => 'field_collection_item_page_view',
+        'page arguments' => array($count + 2),
+        'access callback' => 'field_collection_item_access',
+        'access arguments' => array('view', $count + 2),
+        'file' => 'field_collection.pages.inc',
+      );
+    }
+  }
+
+  $items['field_collection/ajax'] = array(
+    'title' => 'Remove item callback',
+    'page callback' => 'field_collection_remove_js',
+    'delivery callback' => 'ajax_deliver',
+    'access callback' => TRUE,
+    'theme callback' => 'ajax_base_page_theme',
+    'type' => MENU_CALLBACK,
+    'file path' => 'includes',
+    'file' => 'form.inc',
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_menu_alter() to fix the field collections admin UI tabs.
+ */
+function field_collection_menu_alter(&$items) {
+  if (module_exists('field_ui') && isset($items['admin/structure/field-collections/%field_collection_field_name/fields'])) {
+    // Make the fields task the default local task.
+    $items['admin/structure/field-collections/%field_collection_field_name'] = $items['admin/structure/field-collections/%field_collection_field_name/fields'];
+    $item = &$items['admin/structure/field-collections/%field_collection_field_name'];
+    $item['type'] = MENU_NORMAL_ITEM;
+    $item['title'] = 'Manage fields';
+    $item['title callback'] = 'field_collection_admin_page_title';
+    $item['title arguments'] = array(3);
+
+    $items['admin/structure/field-collections/%field_collection_field_name/fields'] = array(
+      'title' => 'Manage fields',
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+      'weight' => 1,
+    );
+  }
+}
+
+/**
+ * Menu title callback.
+ */
+function field_collection_admin_page_title($field_name) {
+  return t('Field collection @field_name', array('@field_name' => $field_name));
+}
+
+/**
+ * Implements hook_admin_paths().
+ */
+function field_collection_admin_paths() {
+  if (variable_get('node_admin_theme')) {
+    return array(
+      'field-collection/*/*/edit' => TRUE,
+      'field-collection/*/*/delete' => TRUE,
+      'field-collection/*/add/*/*' => TRUE,
+    );
+  }
+}
+
+/**
+ * Implements hook_permission().
+ */
+function field_collection_permission() {
+  return array(
+    'administer field collections' =>  array(
+      'title' => t('Administer field collections'),
+      'description' => t('Create and delete fields on field collections.'),
+    ),
+  );
+}
+
+/**
+ * Determines whether the given user has access to a field collection.
+ *
+ * @param $op
+ *   The operation being performed. One of 'view', 'update', 'create', 'delete'.
+ * @param $item
+ *   Optionally a field collection item. If nothing is given, access for all
+ *   items is determined.
+ * @param $account
+ *   The user to check for. Leave it to NULL to check for the global user.
+ * @return boolean
+ *   Whether access is allowed or not.
+ */
+function field_collection_item_access($op, FieldCollectionItemEntity $item = NULL, $account = NULL) {
+  // We do not support editing field collection revisions that are not used at
+  // the hosts default revision as saving the host might result in a new default
+  // revision.
+  if (isset($item) && !$item->isInUse() && $op != 'view') {
+    return FALSE;
+  }
+  if (user_access('administer field collections', $account)) {
+    return TRUE;
+  }
+  if (!isset($item)) {
+    return FALSE;
+  }
+  $op = $op == 'view' ? 'view' : 'edit';
+  // Access is determined by the entity and field containing the reference.
+  $field = field_info_field($item->field_name);
+  $entity_access = entity_access($op == 'view' ? 'view' : 'update', $item->hostEntityType(), $item->hostEntity(), $account);
+  return $entity_access && field_access($op, $field, $item->hostEntityType(), $item->hostEntity(), $account);
+}
+
+/**
+ * Implements hook_theme().
+ */
+function field_collection_theme() {
+  return array(
+    'field_collection_item' => array(
+      'render element' => 'elements',
+      'template' => 'field-collection-item',
+    ),
+    'field_collection_view' => array(
+      'render element' => 'element',
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_info().
+ */
+function field_collection_field_info() {
+  return array(
+    'field_collection' => array(
+      'label' => t('Field collection'),
+      'description' => t('This field stores references to embedded entities, which itself may contain any number of fields.'),
+      'instance_settings' => array(),
+      'default_widget' => 'field_collection_hidden',
+      'default_formatter' => 'field_collection_view',
+      // As of now there is no UI for setting the path.
+      'settings' => array(
+        'path' => '',
+        'hide_blank_items' => TRUE,
+      ),
+      // Add entity property info.
+      'property_type' => 'field_collection_item',
+      'property_callbacks' => array('field_collection_entity_metadata_property_callback'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function field_collection_field_instance_settings_form($field, $instance) {
+
+  $element['fieldset'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Default value'),
+    '#collapsible' => FALSE,
+    // As field_ui_default_value_widget() does, we change the #parents so that
+    // the value below is writing to $instance in the right location.
+    '#parents' => array('instance'),
+  );
+  // Be sure to set the default value to NULL, e.g. to repair old fields
+  // that still have one.
+  $element['fieldset']['default_value'] = array(
+    '#type' => 'value',
+    '#value' => NULL,
+  );
+  $element['fieldset']['content'] = array(
+    '#pre' => '<p>',
+    '#markup' => t('To specify a default value, configure it via the regular default value setting of each field that is part of the field collection. To do so, go to the <a href="!url">Manage fields</a> screen of the field collection.', array('!url' => url('admin/structure/field-collections/' . strtr($field['field_name'], array('_' => '-')) . '/fields'))),
+    '#suffix' => '</p>',
+  );
+  return $element;
+}
+
+/**
+ * Returns the base path to use for field collection items.
+ */
+function field_collection_field_get_path($field) {
+  if (empty($field['settings']['path'])) {
+    return 'field-collection/' . strtr($field['field_name'], array('_' => '-'));
+  }
+  return $field['settings']['path'];
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function field_collection_field_settings_form($field, $instance) {
+
+  $form['hide_blank_items'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Hide blank items'),
+    '#default_value' => $field['settings']['hide_blank_items'],
+    '#description' => t("A blank item is always added to any multivalued field's form. If checked, any additional blank items are hidden except of the first item which is always shown."),
+    '#weight' => 10,
+    '#states' => array(
+      // Hide the setting if the cardinality is 1.
+      'invisible' => array(
+        ':input[name="field[cardinality]"]' => array('value' => '1'),
+      ),
+    ),
+  );
+  return $form;
+}
+
+/**
+ * Implements hook_field_presave().
+ *
+ * Support saving field collection items in @code $item['entity'] @endcode. This
+ * may be used to seamlessly create field collection items during host-entity
+ * creation or to save changes to the host entity and its collections at once.
+ */
+function field_collection_field_presave($host_entity_type, $host_entity, $field, $instance, $langcode, &$items) {
+  foreach ($items as &$item) {
+    // In case the entity has been changed / created, save it and set the id.
+    // If the host entity creates a new revision, save new item-revisions as
+    // well.
+    if (isset($item['entity']) || !empty($host_entity->revision)) {
+
+      if ($entity = field_collection_field_get_entity($item)) {
+
+        if (!empty($entity->is_new)) {
+          $entity->setHostEntity($host_entity_type, $host_entity, LANGUAGE_NONE, FALSE);
+        }
+
+        // If the host entity is saved as new revision, do the same for the item.
+        if (!empty($host_entity->revision)) {
+          $entity->revision = TRUE;
+          $is_default = entity_revision_is_default($host_entity_type, $host_entity);
+          // If an entity type does not support saving non-default entities,
+          // assume it will be saved as default.
+          if (!isset($is_default) || $is_default) {
+            $entity->default_revision = TRUE;
+            $entity->archived = FALSE;
+          }
+        }
+        $entity->save(TRUE);
+
+        $item = array(
+          'value' => $entity->item_id,
+          'revision_id' => $entity->revision_id,
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_update().
+ *
+ * Care about removed field collection items.
+ */
+function field_collection_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  $items_original = !empty($entity->original->{$field['field_name']}[$langcode]) ? $entity->original->{$field['field_name']}[$langcode] : array();
+  $original_by_id = array_flip(field_collection_field_item_to_ids($items_original));
+
+  foreach ($items as $item) {
+    unset($original_by_id[$item['value']]);
+  }
+
+  // If there are removed items, care about deleting the item entities.
+  if ($original_by_id) {
+    $ids = array_flip($original_by_id);
+
+    // If we are creating a new revision, the old-items should be kept but get
+    // marked as archived now.
+    if (!empty($entity->revision)) {
+      db_update('field_collection_item')
+        ->fields(array('archived' => 1))
+        ->condition('item_id', $ids, 'IN')
+        ->execute();
+    }
+    else {
+      // Delete unused field collection items now.
+      foreach (field_collection_item_load_multiple($ids) as $item) {
+        $item->deleteRevision(TRUE);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_delete().
+ */
+function field_collection_field_delete($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // Also delete all embedded entities.
+  if ($ids = field_collection_field_item_to_ids($items)) {
+    // We filter out entities that are still being referenced by other
+    // host-entities. This should never be the case, but it might happened e.g.
+    // when modules cloned a node without knowing about field-collection.
+    $entity_info = entity_get_info($entity_type);
+    $entity_id_name = $entity_info['entity keys']['id'];
+    $field_column = key($field['columns']);
+
+    foreach ($ids as $id_key => $id) {
+      $query = new EntityFieldQuery();
+      $entities = $query
+        ->fieldCondition($field['field_name'], $field_column, $id)
+        ->execute();
+      unset($entities[$entity_type][$entity->$entity_id_name]);
+
+      if (!empty($entities[$entity_type])) {
+        // Filter this $id out.
+        unset($ids[$id_key]);
+      }
+    }
+
+    entity_delete_multiple('field_collection_item', $ids);
+  }
+}
+
+/**
+ * Implements hook_field_delete_revision().
+ */
+function field_collection_field_delete_revision($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  foreach ($items as $item) {
+    if (!empty($item['revision_id'])) {
+      if ($entity = field_collection_item_revision_load($item['revision_id'])) {
+        $entity->deleteRevision(TRUE);
+      }
+    }
+  }
+}
+
+/**
+ * Get an array of field collection item IDs stored in the given field items.
+ */
+function field_collection_field_item_to_ids($items) {
+  $ids = array();
+  foreach ($items as $item) {
+    if (!empty($item['value'])) {
+      $ids[] = $item['value'];
+    }
+  }
+  return $ids;
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function field_collection_field_is_empty($item, $field) {
+  if (!empty($item['value'])) {
+    return FALSE;
+  }
+  elseif (isset($item['entity'])) {
+    return field_collection_item_is_empty($item['entity']);
+  }
+  return TRUE;
+}
+
+/**
+ * Determines whether a field collection item entity is empty based on the collection-fields.
+ */
+function field_collection_item_is_empty(FieldCollectionItemEntity $item) {
+  $instances = field_info_instances('field_collection_item', $item->field_name);
+  $is_empty = TRUE;
+
+  foreach ($instances as $instance) {
+    $field_name = $instance['field_name'];
+    $field = field_info_field($field_name);
+
+    // Determine the list of languages to iterate on.
+    $languages = field_available_languages('field_collection_item', $field);
+
+    foreach ($languages as $langcode) {
+      if (!empty($item->{$field_name}[$langcode])) {
+        // If at least one collection-field is not empty; the
+        // field collection item is not empty.
+        foreach ($item->{$field_name}[$langcode] as $field_item) {
+          if (!module_invoke($field['module'], 'field_is_empty', $field_item, $field)) {
+            $is_empty = FALSE;
+          }
+        }
+      }
+    }
+  }
+
+  // Allow other modules a chance to alter the value before returning.
+  drupal_alter('field_collection_is_empty', $is_empty, $item);
+  return $is_empty;
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function field_collection_field_formatter_info() {
+  return array(
+    'field_collection_list' => array(
+      'label' => t('Links to field collection items'),
+      'field types' => array('field_collection'),
+      'settings' =>  array(
+        'edit' => t('Edit'),
+        'delete' => t('Delete'),
+        'add' => t('Add'),
+        'description' => TRUE,
+      ),
+    ),
+    'field_collection_view' => array(
+      'label' => t('Field collection items'),
+      'field types' => array('field_collection'),
+      'settings' =>  array(
+        'edit' => t('Edit'),
+        'delete' => t('Delete'),
+        'add' => t('Add'),
+        'description' => TRUE,
+        'view_mode' => 'full',
+      ),
+    ),
+    'field_collection_fields' => array(
+      'label' => t('Fields only'),
+      'field types' => array('field_collection'),
+      'settings' =>  array(
+        'view_mode' => 'full',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function field_collection_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $elements = array();
+
+  if ($display['type'] != 'field_collection_fields') {
+    $elements['edit'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Edit link title'),
+      '#default_value' => $settings['edit'],
+      '#description' => t('Leave the title empty, to hide the link.'),
+    );
+    $elements['delete'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Delete link title'),
+      '#default_value' => $settings['delete'],
+      '#description' => t('Leave the title empty, to hide the link.'),
+    );
+    $elements['add'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Add link title'),
+      '#default_value' => $settings['add'],
+      '#description' => t('Leave the title empty, to hide the link.'),
+    );
+    $elements['description'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Show the field description beside the add link.'),
+      '#default_value' => $settings['description'],
+      '#description' => t('If enabled and the add link is shown, the field description is shown in front of the add link.'),
+    );
+  }
+
+  // Add a select form element for view_mode if viewing the rendered field_collection.
+  if ($display['type'] !== 'field_collection_list') {
+
+    $entity_type = entity_get_info('field_collection_item');
+    $options = array();
+    foreach ($entity_type['view modes'] as $mode => $info) {
+      $options[$mode] = $info['label'];
+    }
+
+    $elements['view_mode'] = array(
+      '#type' => 'select',
+      '#title' => t('View mode'),
+      '#options' => $options,
+      '#default_value' => $settings['view_mode'],
+      '#description' => t('Select the view mode'),
+    );
+  }
+
+  return $elements;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function field_collection_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $output = array();
+
+  if ($display['type'] !== 'field_collection_fields') {
+    $links = array_filter(array_intersect_key($settings, array_flip(array('add', 'edit', 'delete'))));
+    if ($links) {
+      $output[] = t('Links: @links', array('@links' => check_plain(implode(', ', $links))));
+    }
+    else {
+      $output[] = t('Links: none');
+    }
+  }
+
+  if ($display['type'] !== 'field_collection_list') {
+    $entity_type = entity_get_info('field_collection_item');
+    if (!empty($entity_type['view modes'][$settings['view_mode']]['label'])) {
+      $output[] =  t('View mode: @mode', array('@mode' => $entity_type['view modes'][$settings['view_mode']]['label']));
+    }
+  }
+
+  return implode('<br>', $output);
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function field_collection_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $element = array();
+  $settings = $display['settings'];
+
+  switch ($display['type']) {
+    case 'field_collection_list':
+
+      foreach ($items as $delta => $item) {
+        if ($field_collection = field_collection_field_get_entity($item)) {
+          $output = l($field_collection->label(), $field_collection->path());
+          $links = array();
+          foreach (array('edit', 'delete') as $op) {
+            if ($settings[$op] && field_collection_item_access($op == 'edit' ? 'update' : $op, $field_collection)) {
+              $title = entity_i18n_string("field:{$field['field_name']}:{$instance['bundle']}:setting_$op", $settings[$op]);
+              $links[] = l($title, $field_collection->path() . '/' . $op, array('query' => drupal_get_destination()));
+            }
+          }
+          if ($links) {
+            $output .= ' (' . implode('|', $links) . ')';
+          }
+          $element[$delta] = array('#markup' => $output);
+        }
+      }
+      field_collection_field_formatter_links($element, $entity_type, $entity, $field, $instance, $langcode, $items, $display);
+      break;
+
+    case 'field_collection_view':
+
+      $element['#attached']['css'][] = drupal_get_path('module', 'field_collection') . '/field_collection.theme.css';
+      $view_mode = !empty($display['settings']['view_mode']) ? $display['settings']['view_mode'] : 'full';
+      foreach ($items as $delta => $item) {
+        if ($field_collection = field_collection_field_get_entity($item)) {
+          $element[$delta]['entity'] = $field_collection->view($view_mode);
+          $element[$delta]['#theme_wrappers'] = array('field_collection_view');
+          $element[$delta]['#attributes']['class'][] = 'field-collection-view';
+          $element[$delta]['#attributes']['class'][] = 'clearfix';
+          $element[$delta]['#attributes']['class'][] = drupal_clean_css_identifier('view-mode-' . $view_mode);
+
+          $links = array(
+            '#theme' => 'links__field_collection_view',
+          );
+          $links['#attributes']['class'][] = 'field-collection-view-links';
+          foreach (array('edit', 'delete') as $op) {
+            if ($settings[$op] && field_collection_item_access($op == 'edit' ? 'update' : $op, $field_collection)) {
+              $links['#links'][$op] = array(
+                'title' => entity_i18n_string("field:{$field['field_name']}:{$instance['bundle']}:setting_$op", $settings[$op]),
+                'href' => $field_collection->path() . '/' . $op,
+                'query' => drupal_get_destination(),
+              );
+            }
+          }
+          $element[$delta]['links'] = $links;
+        }
+      }
+      field_collection_field_formatter_links($element, $entity_type, $entity, $field, $instance, $langcode, $items, $display);
+      break;
+
+    case 'field_collection_fields':
+
+      $view_mode = !empty($display['settings']['view_mode']) ? $display['settings']['view_mode'] : 'full';
+      foreach ($items as $delta => $item) {
+        if ($field_collection = field_collection_field_get_entity($item)) {
+          $element[$delta]['entity'] = $field_collection->view($view_mode);
+        }
+      }
+      break;
+  }
+
+  return $element;
+}
+
+/**
+ * Helper function to add links to a field collection field.
+ */
+function field_collection_field_formatter_links(&$element, $entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $settings = $display['settings'];
+
+  if ($settings['add'] && ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || count($items) < $field['cardinality'])) {
+    // Check whether the current is allowed to create a new item.
+    $field_collection_item = entity_create('field_collection_item', array('field_name' => $field['field_name']));
+    $field_collection_item->setHostEntity($entity_type, $entity, LANGUAGE_NONE, FALSE);
+
+    if (field_collection_item_access('create', $field_collection_item)) {
+      $path = field_collection_field_get_path($field);
+      list($id) = entity_extract_ids($entity_type, $entity);
+      $element['#suffix'] = '';
+      if (!empty($settings['description'])) {
+        $element['#suffix'] .= '<div class="description field-collection-description">' . field_filter_xss($instance['description']) . '</div>';
+      }
+      $title = entity_i18n_string("field:{$field['field_name']}:{$instance['bundle']}:setting_add", $settings['add']);
+      $add_path = $path . '/add/' . $entity_type . '/' . $id;
+      $element['#suffix'] .= '<ul class="action-links action-links-field-collection-add"><li>';
+      $element['#suffix'] .= l($title, $add_path, array('query' => drupal_get_destination()));
+      $element['#suffix'] .= '</li></ul>';
+    }
+  }
+  // If there is no add link, add a special class to the last item.
+  if (empty($element['#suffix'])) {
+    $index = count(element_children($element)) - 1;
+    $element[$index]['#attributes']['class'][] = 'field-collection-view-final';
+  }
+
+  $element += array('#prefix' => '', '#suffix' => '');
+  $element['#prefix'] .= '<div class="field-collection-container clearfix">';
+  $element['#suffix'] .= '</div>';
+
+  return $element;
+}
+
+/**
+ * Themes field collection items printed using the field_collection_view formatter.
+ */
+function theme_field_collection_view($variables) {
+  $element = $variables['element'];
+  return '<div' . drupal_attributes($element['#attributes']) . '>' . $element['#children'] . '</div>';
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function field_collection_field_widget_info() {
+  return array(
+    'field_collection_hidden' => array(
+      'label' => t('Hidden'),
+      'field types' => array('field_collection'),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+        'default value' => FIELD_BEHAVIOR_NONE,
+      ),
+    ),
+    'field_collection_embed' => array(
+      'label' => t('Embedded'),
+      'field types' => array('field_collection'),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+        'default value' => FIELD_BEHAVIOR_NONE,
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function field_collection_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  static $recursion = 0;
+
+  switch ($instance['widget']['type']) {
+    case 'field_collection_hidden':
+      return $element;
+
+    case 'field_collection_embed':
+      // If the field collection item form contains another field collection,
+      // we might ran into a recursive loop. Prevent that.
+      if ($recursion++ > 3) {
+        drupal_set_message(t('The field collection item form has not been embedded to avoid recursive loops.'), 'error');
+        return $element;
+      }
+      $field_parents = $element['#field_parents'];
+      $field_name = $element['#field_name'];
+      $language = $element['#language'];
+
+      // Nest the field collection item entity form in a dedicated parent space,
+      // by appending [field_name, langcode, delta] to the current parent space.
+      // That way the form values of the field collection item are separated.
+      $parents = array_merge($field_parents, array($field_name, $language, $delta));
+
+      $element += array(
+        '#element_validate' => array('field_collection_field_widget_embed_validate'),
+        '#parents' => $parents,
+      );
+
+      if ($field['cardinality'] == 1) {
+        $element['#type'] = 'fieldset';
+      }
+
+      $field_state = field_form_get_state($field_parents, $field_name, $language, $form_state);
+
+      if (!empty($field['settings']['hide_blank_items']) && $delta == $field_state['items_count'] && $delta > 0) {
+        // Do not add a blank item. Also see
+        // field_collection_field_attach_form() for correcting #max_delta.
+        $recursion--;
+        return FALSE;
+      }
+      elseif (!empty($field['settings']['hide_blank_items']) && $field_state['items_count'] == 0) {
+        // We show one item, so also specify that as item count. So when the
+        // add button is pressed the item count will be 2 and we show to items.
+        $field_state['items_count'] = 1;
+      }
+
+      if (isset($field_state['entity'][$delta])) {
+        $field_collection_item = $field_state['entity'][$delta];
+      }
+      else {
+        if (isset($items[$delta])) {
+          $field_collection_item = field_collection_field_get_entity($items[$delta], $field_name);
+        }
+        // Show an empty collection if we have no existing one or it does not
+        // load.
+        if (empty($field_collection_item)) {
+          $field_collection_item = entity_create('field_collection_item', array('field_name' => $field_name));
+        }
+
+        // Put our entity in the form state, so FAPI callbacks can access it.
+        $field_state['entity'][$delta] = $field_collection_item;
+      }
+
+      field_form_set_state($field_parents, $field_name, $language, $form_state, $field_state);
+      field_attach_form('field_collection_item', $field_collection_item, $element, $form_state, $language);
+
+      if (empty($element['#required'])) {
+        $element['#after_build'][] = 'field_collection_field_widget_embed_delay_required_validation';
+      }
+
+      if ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) {
+        $element['remove_button'] = array(
+          '#delta' => $delta,
+          '#name' => implode('_', $parents) . '_remove_button',
+          '#type' => 'submit',
+          '#value' => t('Remove'),
+          '#validate' => array(),
+          '#submit' => array('field_collection_remove_submit'),
+          '#limit_validation_errors' => array(),
+          '#ajax' => array(
+            'path' => 'field_collection/ajax',
+            'effect' => 'fade',
+          ),
+          '#weight' => 1000,
+        );
+      }
+
+      $recursion--;
+      return $element;
+  }
+}
+
+/**
+ * Implements hook_field_attach_form().
+ *
+ * Corrects #max_delta when we hide the blank field collection item.
+ *
+ * @see field_add_more_js()
+ * @see field_collection_field_widget_form()
+ */
+function field_collection_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
+
+  foreach (field_info_instances($entity_type, $form['#bundle']) as $field_name => $instance) {
+    $field = field_info_field($field_name);
+
+    if ($field['type'] == 'field_collection' && $field['settings']['hide_blank_items']
+        && field_access('edit', $field, $entity_type) && $instance['widget']['type'] == 'field_collection_embed') {
+
+      $element_langcode = $form[$field_name]['#language'];
+      if ($form[$field_name][$element_langcode]['#max_delta'] > 0) {
+        $form[$field_name][$element_langcode]['#max_delta']--;
+      }
+    }
+  }
+}
+
+/**
+ * Page callback to handle AJAX for removing a field collection item.
+ *
+ * This is a direct page callback. The actual job of deleting the item is
+ * done in the submit handler for the button, so all we really need to
+ * do is process the form and then generate output. We generate this
+ * output by doing a replace command on the id of the entire form element.
+ */
+function field_collection_remove_js() {
+  // drupal_html_id() very helpfully ensures that all html IDS are unique
+  // on a page. Unfortunately what it doesn't realize is that the IDs
+  // we are generating are going to replace IDs that already exist, so
+  // this actually works against us.
+  if (isset($_POST['ajax_html_ids'])) {
+    unset($_POST['ajax_html_ids']);
+  }
+
+  list($form, $form_state) = ajax_get_form();
+  drupal_process_form($form['#form_id'], $form, $form_state);
+
+  // Get the information on what we're removing.
+  $button = $form_state['triggering_element'];
+  // Go two levels up in the form, to the whole widget.
+  $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -3));
+  // Now send back the proper AJAX command to replace it.
+  $return = array(
+    '#type' => 'ajax',
+    '#commands' => array(
+      ajax_command_replace('#' . $element['#id'], drupal_render($element))
+    ),
+  );
+
+  // Because we're doing this ourselves, messages aren't automatic. We have
+  // to add them.
+  $messages = theme('status_messages');
+  if ($messages) {
+    $return['#commands'][] = ajax_command_prepend('#' . $element['#id'], $messages);
+  }
+
+  return $return;
+}
+
+/**
+ * Submit callback to remove an item from the field UI multiple wrapper.
+ *
+ * When a remove button is submitted, we need to find the item that it
+ * referenced and delete it. Since field UI has the deltas as a straight
+ * unbroken array key, we have to renumber everything down. Since we do this
+ * we *also* need to move all the deltas around in the $form_state['values']
+ * and $form_state['input'] so that user changed values follow. This is a bit
+ * of a complicated process.
+ */
+function field_collection_remove_submit($form, &$form_state) {
+  $button = $form_state['triggering_element'];
+  $delta = $button['#delta'];
+
+  // Where in the form we'll find the parent element.
+  $address = array_slice($button['#array_parents'], 0, -2);
+
+  // Go one level up in the form, to the widgets container.
+  $parent_element = drupal_array_get_nested_value($form, $address);
+  $field_name = $parent_element['#field_name'];
+  $langcode = $parent_element['#language'];
+  $parents = $parent_element['#field_parents'];
+
+  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
+
+  // Go ahead and renumber everything from our delta to the last
+  // item down one. This will overwrite the item being removed.
+  for ($i = $delta; $i <= $field_state['items_count']; $i++) {
+    $old_element_address = array_merge($address, array($i + 1));
+    $new_element_address = array_merge($address, array($i));
+
+    $moving_element = drupal_array_get_nested_value($form, $old_element_address);
+    $moving_element_value = drupal_array_get_nested_value($form_state['values'], $old_element_address);
+    $moving_element_input = drupal_array_get_nested_value($form_state['input'], $old_element_address);
+
+    // Tell the element where it's being moved to.
+    $moving_element['#parents'] = $new_element_address;
+
+    // Move the element around.
+    form_set_value($moving_element, $moving_element_value, $form_state);
+    drupal_array_set_nested_value($form_state['input'], $moving_element['#parents'], $moving_element_input);
+
+    // Move the entity in our saved state.
+    if (isset($field_state['entity'][$i + 1])) {
+      $field_state['entity'][$i] = $field_state['entity'][$i + 1];
+    }
+    else {
+      unset($field_state['entity'][$i]);
+    }
+  }
+
+  // Replace the deleted entity with an empty one. This helps to ensure that
+  // trying to add a new entity won't ressurect a deleted entity from the
+  // trash bin.
+  $count = count($field_state['entity']);
+  $field_state['entity'][$count] = entity_create('field_collection_item', array('field_name' => $field_name));
+
+  // Then remove the last item. But we must not go negative.
+  if ($field_state['items_count'] > 0) {
+    $field_state['items_count']--;
+  }
+
+  // Fix the weights. Field UI lets the weights be in a range of
+  // (-1 * item_count) to (item_count). This means that when we remove one,
+  // the range shrinks; weights outside of that range then get set to
+  // the first item in the select by the browser, floating them to the top.
+  // We use a brute force method because we lost weights on both ends
+  // and if the user has moved things around, we have to cascade because
+  // if I have items weight weights 3 and 4, and I change 4 to 3 but leave
+  // the 3, the order of the two 3s now is undefined and may not match what
+  // the user had selected.
+  $input = drupal_array_get_nested_value($form_state['input'], $address);
+  // Sort by weight
+  uasort($input, '_field_sort_items_helper');
+
+  // Reweight everything in the correct order.
+  $weight = -1 * $field_state['items_count'];
+  foreach ($input as $key => $item) {
+    if ($item) {
+      $input[$key]['_weight'] = $weight++;
+    }
+  }
+
+  drupal_array_set_nested_value($form_state['input'], $address, $input);
+  field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
+
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Gets a field collection item entity for a given field item.
+ *
+ * @param $field_name
+ *   (optional) If given and there is no entity yet, a new entity object is
+ *   created for the given item.
+ *
+ * @return
+ *   The entity object or FALSE.
+ */
+function field_collection_field_get_entity(&$item, $field_name = NULL) {
+  if (isset($item['entity'])) {
+    return $item['entity'];
+  }
+  elseif (isset($item['value'])) {
+    // By default always load the default revision, so caches get used.
+    $entity = field_collection_item_load($item['value']);
+    if ($entity->revision_id != $item['revision_id']) {
+      // A non-default revision is a referenced, so load this one.
+      $entity = field_collection_item_revision_load($item['revision_id']);
+    }
+    return $entity;
+  }
+  elseif (!isset($item['entity']) && isset($field_name)) {
+    $item['entity'] = entity_create('field_collection_item', array('field_name' => $field_name));
+    return $item['entity'];
+  }
+  return FALSE;
+}
+
+/**
+ * FAPI #after_build of an individual field collection element to delay the validation of #required.
+ */
+function field_collection_field_widget_embed_delay_required_validation(&$element, &$form_state) {
+  // If the process_input flag is set, the form and its input is going to be
+  // validated. Prevent #required (sub)fields from throwing errors while
+  // their non-#required field collection item is empty.
+  if ($form_state['process_input']) {
+    _field_collection_collect_required_elements($element, $element['#field_collection_required_elements']);
+  }
+  return $element;
+}
+
+function _field_collection_collect_required_elements(&$element, &$required_elements) {
+  // Recurse through all children.
+  foreach (element_children($element) as $key) {
+    if (isset($element[$key]) && $element[$key]) {
+      _field_collection_collect_required_elements($element[$key], $required_elements);
+    }
+  }
+  if (!empty($element['#required'])) {
+    $element['#required'] = FALSE;
+    $required_elements[] = &$element;
+    $element += array('#pre_render' => array());
+    array_unshift($element['#pre_render'], 'field_collection_field_widget_render_required');
+  }
+}
+
+/**
+ * #pre_render callback that ensures the element is rendered as being required.
+ */
+function field_collection_field_widget_render_required($element) {
+  $element['#required'] = TRUE;
+  return $element;
+}
+
+/**
+ * FAPI validation of an individual field collection element.
+ */
+function field_collection_field_widget_embed_validate($element, &$form_state, $complete_form) {
+  $instance = field_widget_instance($element, $form_state);
+  $field = field_widget_field($element, $form_state);
+  $field_parents = $element['#field_parents'];
+  $field_name = $element['#field_name'];
+  $language = $element['#language'];
+
+  $field_state = field_form_get_state($field_parents, $field_name, $language, $form_state);
+  $field_collection_item = $field_state['entity'][$element['#delta']];
+
+  // Attach field API validation of the embedded form.
+  field_attach_form_validate('field_collection_item', $field_collection_item, $element, $form_state);
+
+  // Now validate required elements if the entity is not empty.
+  if (!field_collection_item_is_empty($field_collection_item) && !empty($element['#field_collection_required_elements'])) {
+    foreach ($element['#field_collection_required_elements'] as &$elements) {
+
+      // Copied from _form_validate().
+      if (isset($elements['#needs_validation'])) {
+        $is_empty_multiple = (!count($elements['#value']));
+        $is_empty_string = (is_string($elements['#value']) && drupal_strlen(trim($elements['#value'])) == 0);
+        $is_empty_value = ($elements['#value'] === 0);
+        if ($is_empty_multiple || $is_empty_string || $is_empty_value) {
+          if (isset($elements['#title'])) {
+            form_error($elements, t('!name field is required.', array('!name' => $elements['#title'])));
+          }
+          else {
+            form_error($elements);
+          }
+        }
+      }
+    }
+  }
+
+  // Only if the form is being submitted, finish the collection entity and
+  // prepare it for saving.
+  if ($form_state['submitted'] && !form_get_errors()) {
+
+    field_attach_submit('field_collection_item', $field_collection_item, $element, $form_state);
+
+    // Load initial form values into $item, so any other form values below the
+    // same parents are kept.
+    $item = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
+
+    // Set the _weight if it is a multiple field.
+    if (isset($element['_weight']) && ($field['cardinality'] > 1 || $field['cardinality'] == FIELD_CARDINALITY_UNLIMITED)) {
+      $item['_weight'] = $element['_weight']['#value'];
+    }
+
+    // Put the field collection item in $item['entity'], so it is saved with
+    // the host entity via hook_field_presave() / field API if it is not empty.
+    // @see field_collection_field_presave()
+    $item['entity'] = $field_collection_item;
+    form_set_value($element, $item, $form_state);
+  }
+}
+
+/**
+ * Implements hook_field_create_field().
+ */
+function field_collection_field_create_field($field) {
+  if ($field['type'] == 'field_collection') {
+    field_attach_create_bundle('field_collection_item', $field['field_name']);
+
+    // Clear caches.
+    entity_info_cache_clear();
+    // Do not directly issue menu rebuilds here to avoid potentially multiple
+    // rebuilds. Instead, let menu_get_item() issue the rebuild on the next
+    // request.
+    variable_set('menu_rebuild_needed', TRUE);
+  }
+}
+
+/**
+ * Implements hook_field_delete_field().
+ */
+function field_collection_field_delete_field($field) {
+  if ($field['type'] == 'field_collection') {
+    // Notify field.module that field collection was deleted.
+    field_attach_delete_bundle('field_collection_item', $field['field_name']);
+
+    // Clear caches.
+    entity_info_cache_clear();
+    // Do not directly issue menu rebuilds here to avoid potentially multiple
+    // rebuilds. Instead, let menu_get_item() issue the rebuild on the next
+    // request.
+    variable_set('menu_rebuild_needed', TRUE);
+  }
+}
+
+/**
+ * Implements hook_i18n_string_list_{textgroup}_alter().
+ */
+function field_collection_i18n_string_list_field_alter(&$properties, $type, $instance) {
+  if ($type == 'field_instance') {
+    $field = field_info_field($instance['field_name']);
+
+    if ($field['type'] == 'field_collection' && !empty($instance['display'])) {
+
+      foreach ($instance['display'] as $view_mode => $display) {
+        if ($display['type'] != 'field_collection_fields') {
+          $display['settings'] += array('edit' => 'edit', 'delete' => 'delete', 'add' => 'add');
+
+          $properties['field'][$instance['field_name']][$instance['bundle']]['setting_edit'] = array(
+            'title' => t('Edit link title'),
+            'string' => $display['settings']['edit'],
+          );
+          $properties['field'][$instance['field_name']][$instance['bundle']]['setting_delete'] = array(
+            'title' => t('Delete link title'),
+            'string' => $display['settings']['delete'],
+          );
+          $properties['field'][$instance['field_name']][$instance['bundle']]['setting_add'] = array(
+            'title' => t('Add link title'),
+            'string' => $display['settings']['add'],
+          );
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function field_collection_views_api() {
+  return array(
+    'api' => '3.0-alpha1',
+    'path' => drupal_get_path('module', 'field_collection') . '/views',
+  );
+}
+
+/**
+ * Implements hook_features_pipe_component_alter() for fields.
+ */
+function field_collection_features_pipe_field_alter(&$pipe, $data, $export) {
+  // Add the fields of the field collection entity to the pipe.
+  foreach ($data as $identifier) {
+    if (($field = features_field_load($identifier)) && $field['field_config']['type'] == 'field_collection') {
+      $fields = field_info_instances('field_collection_item', $field['field_config']['field_name']);
+      foreach ($fields as $name => $field) {
+        $pipe['field'][] = "{$field['entity_type']}-{$field['bundle']}-{$field['field_name']}";
+      }
+    }
+  }
+}
+
+/**
+ * Callback for generating entity metadata property info for our field instances.
+ *
+ * @see field_collection_field_info()
+ */
+function field_collection_entity_metadata_property_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  // Set the bundle as we know it is the name of the field.
+  $property['bundle'] = $field['field_name'];
+  $property['getter callback'] = 'field_collection_field_property_get';
+}
+
+/**
+ * Entity property info setter callback for the host entity property.
+ *
+ * As the property is of type entity, the value will be passed as a wrapped
+ * entity.
+ */
+function field_collection_item_set_host_entity($item, $property_name, $wrapper) {
+  if (empty($item->is_new)) {
+    throw new EntityMetadataWrapperException('The host entity may be set only during creation of a field collection item.');
+  }
+  if (!isset($wrapper->{$item->field_name})) {
+    throw new EntityMetadataWrapperException('The specified entity has no such field collection field.');
+  }
+  $item->setHostEntity($wrapper->type(), $wrapper->value());
+}
+
+/**
+ * Entity property info getter callback for the host entity property.
+ */
+function field_collection_item_get_host_entity($item) {
+  // As the property is defined as 'entity', we have to return a wrapped entity.
+  return entity_metadata_wrapper($item->hostEntityType(), $item->hostEntity());
+}
+
+/**
+ * Entity property info getter callback for the field collection items.
+ *
+ * Like entity_metadata_field_property_get(), but additionally supports getting
+ * not-yet saved collection items from @code $item['entity'] @endcode.
+ */
+function field_collection_field_property_get($entity, array $options, $name, $entity_type, $info) {
+  $field = field_info_field($name);
+  $langcode = field_language($entity_type, $entity, $name, isset($options['language']) ? $options['language']->language : NULL);
+  $values = array();
+  if (isset($entity->{$name}[$langcode])) {
+    foreach ($entity->{$name}[$langcode] as $delta => $data) {
+      // Wrappers do not support multiple entity references being revisions or
+      // not yet saved entities. In the case of a single reference we can return
+      // the entity object though.
+      if ($field['cardinality'] == 1) {
+        $values[$delta] = field_collection_field_get_entity($data);
+      }
+      elseif (isset($data['value'])) {
+        $values[$delta] = $data['value'];
+      }
+    }
+  }
+  // For an empty single-valued field, we have to return NULL.
+  return $field['cardinality'] == 1 ? ($values ? reset($values) : NULL) : $values;
+}
+
+/**
+ * Implements hook_devel_generate().
+ */
+function field_collection_devel_generate($object, $field, $instance, $bundle) {
+  // Create a new field collection object and add fake data to its fields.
+  $field_collection = entity_create('field_collection_item', array('field_name' => $field['field_name']));
+  $field_collection->language = $object->language;
+  $field_collection->setHostEntity($instance['entity_type'], $object, $object->language, FALSE);
+
+  devel_generate_fields($field_collection, 'field_collection_item', $field['field_name']);
+
+  $field_collection->save(TRUE);
+
+  return array('value' => $field_collection->item_id);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.pages.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * @file
+ * Provides the field collection item view / edit / delete pages.
+ */
+
+// TODO: fix being embedded in a host with revisions.
+
+/**
+ * Field collection item view page.
+ */
+function field_collection_item_page_view($field_collection_item) {
+  // @todo: Set breadcrumb including the host.
+  drupal_set_title($field_collection_item->label());
+  return $field_collection_item->view('full', NULL, TRUE);
+}
+
+/**
+ * Form for editing a field collection item.
+ * @todo implement hook_forms().
+ */
+function field_collection_item_form($form, &$form_state, $field_collection_item) {
+  if (!isset($field_collection_item->is_new)) {
+    drupal_set_title($field_collection_item->label());
+  }
+  $form_state += array('field_collection_item' => $field_collection_item);
+
+  // Hack: entity_form_field_validate() needs the bundle to be set.
+  // @todo: Fix core and remove the hack.
+  $form['field_name'] = array('#type' => 'value', '#value' => $field_collection_item->field_name);
+
+  field_attach_form('field_collection_item', $field_collection_item, $form, $form_state);
+
+  $form['actions'] = array('#type' => 'actions', '#weight' => 50);
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#weight' => 5,
+  );
+  return $form;
+}
+
+/**
+ * Validation callback.
+ */
+function field_collection_item_form_validate($form, &$form_state) {
+  entity_form_field_validate('field_collection_item', $form, $form_state);
+}
+
+/**
+ * Submit builder. Extracts the form values and updates the entity.
+ */
+function field_collection_item_form_submit_build_field_collection($form, $form_state) {
+  entity_form_submit_build_entity('field_collection_item', $form_state['field_collection_item'], $form, $form_state);
+  return $form_state['field_collection_item'];
+}
+
+/**
+ * Submit callback that permanently saves the changes to the entity.
+ */
+function field_collection_item_form_submit($form, &$form_state) {
+  $field_collection_item = field_collection_item_form_submit_build_field_collection($form, $form_state);
+  $field_collection_item->save();
+  drupal_set_message(t('The changes have been saved.'));
+  $form_state['redirect'] = $field_collection_item->path();
+}
+
+/**
+ * Form for deleting a field collection item.
+ */
+function field_collection_item_delete_confirm($form, &$form_state, $field_collection_item) {
+  $form_state += array('field_collection_item' => $field_collection_item);
+  return confirm_form($form,
+    t('Are you sure you want to delete %label?', array('%label' => $field_collection_item->label())),
+    $field_collection_item->path(),
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Submit callback for deleting a field collection item.
+ */
+function field_collection_item_delete_confirm_submit($form, &$form_state) {
+  $field_collection_item = $form_state['field_collection_item'];
+  $field_collection_item->deleteRevision();
+  drupal_set_message(t('%label has been deleted.', array('%label' => drupal_ucfirst($field_collection_item->label()))));
+  $form_state['redirect'] = '<front>';
+}
+
+/**
+ * Add a new field collection item.
+ *
+ * @todo: Support optionally passing in the revision_id and langcode parameters.
+ */
+function field_collection_item_add($field_name, $entity_type, $entity_id, $revision_id = NULL, $langcode = NULL) {
+  $info = entity_get_info();
+  if (!isset($info[$entity_type])) {
+    return MENU_NOT_FOUND;
+  }
+  $result = entity_load($entity_type, array($entity_id));
+  $entity = reset($result);
+  if (!$entity) {
+    return MENU_NOT_FOUND;
+  }
+  // Ensure the given entity is of a bundle that has an instance of the field.
+  list($id, $rev_id, $bundle) = entity_extract_ids($entity_type, $entity);
+  $instance = field_info_instance($entity_type, $field_name, $bundle);
+  if (!$instance) {
+    return MENU_NOT_FOUND;
+  }
+
+  // Check field cardinality.
+  $field = field_info_field($field_name);
+  $langcode = LANGUAGE_NONE;
+  if (!($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || !isset($entity->{$field_name}[$langcode]) || count($entity->{$field_name}[$langcode]) < $field['cardinality'])) {
+    drupal_set_message(t('Too many items.'), 'error');
+    return '';
+  }
+
+  $field_collection_item = entity_create('field_collection_item', array('field_name' => $field_name));
+  // Do not link the field collection item with the host entity at this point,
+  // as during the form-workflow we have multiple field collection item entity
+  // instances, which we don't want link all with the host.
+  // That way the link is going to be created when the item is saved.
+  $field_collection_item->setHostEntity($entity_type, $entity, LANGUAGE_NONE, FALSE);
+
+  $title = ($field['cardinality'] == 1) ? $instance['label'] : t('Add new !instance_label', array('!instance_label' => $field_collection_item->translatedInstanceLabel()));
+  drupal_set_title($title);
+
+  // Make sure the current user has access to create a field collection item.
+  if (!field_collection_item_access('create', $field_collection_item)) {
+    return MENU_ACCESS_DENIED;
+  }
+  return drupal_get_form('field_collection_item_form', $field_collection_item);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,422 @@
+<?php
+
+/**
+ * @file
+ * field_collections tests.
+ */
+
+/**
+ * Test basics.
+ */
+class FieldCollectionBasicTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Field collection',
+      'description' => 'Tests creating and using field collections.',
+      'group' => 'Field types',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('field_collection');
+
+    // Create a field_collection field to use for the tests.
+    $this->field_name = 'field_test_collection';
+    $this->field = array('field_name' => $this->field_name, 'type' => 'field_collection', 'cardinality' => 4);
+    $this->field = field_create_field($this->field);
+    $this->field_id = $this->field['id'];
+
+    $this->instance = array(
+      'field_name' => $this->field_name,
+      'entity_type' => 'node',
+      'bundle' => 'article',
+      'label' => $this->randomName() . '_label',
+      'description' => $this->randomName() . '_description',
+      'weight' => mt_rand(0, 127),
+      'settings' => array(),
+      'widget' => array(
+        'type' => 'hidden',
+        'label' => 'Test',
+        'settings' => array(),
+      ),
+    );
+    $this->instance = field_create_instance($this->instance);
+  }
+
+  /**
+   * Helper for creating a new node with a field collection item.
+   */
+  protected function createNodeWithFieldCollection() {
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    // Manually create a field_collection.
+    $entity = entity_create('field_collection_item', array('field_name' => $this->field_name));
+    $entity->setHostEntity('node', $node);
+    $entity->save();
+
+    return array($node, $entity);
+  }
+
+  /**
+   * Tests CRUD.
+   */
+  function testCRUD() {
+    list ($node, $entity) = $this->createNodeWithFieldCollection();
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertEqual($entity->item_id, $node->{$this->field_name}[LANGUAGE_NONE][0]['value'], 'A field_collection has been successfully created and referenced.');
+    $this->assertEqual($entity->revision_id, $node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id'], 'A field_collection has been successfully created and referenced.');
+
+    // Test adding an additional field_collection during node edit.
+    $entity2 = entity_create('field_collection_item', array('field_name' => $this->field_name));
+    $node->{$this->field_name}[LANGUAGE_NONE][] = array('entity' => $entity2);
+    node_save($node);
+
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertTrue(!empty($entity2->item_id) && !empty($entity2->revision_id), 'Field_collection has been saved.');
+    $this->assertEqual($entity->item_id, $node->{$this->field_name}[LANGUAGE_NONE][0]['value'], 'Existing reference has been kept during update.');
+    $this->assertEqual($entity->revision_id, $node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id'], 'Existing reference has been kept during update (revision).');
+    $this->assertEqual($entity2->item_id, $node->{$this->field_name}[LANGUAGE_NONE][1]['value'], 'New field_collection has been properly referenced');
+    $this->assertEqual($entity2->revision_id, $node->{$this->field_name}[LANGUAGE_NONE][1]['revision_id'], 'New field_collection has been properly referenced (revision)');
+
+    // Make sure deleting the field_collection removes the reference.
+    $entity2->delete();
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertTrue(!isset($node->{$this->field_name}[LANGUAGE_NONE][1]), 'Reference correctly deleted.');
+
+    // Make sure field_collections are removed during deletion of the host.
+    node_delete($node->nid);
+    $this->assertTrue(entity_load('field_collection_item', FALSE) === array(), 'Field collections are deleted when the host is deleted.');
+
+    // Try deleting nodes with collections without any values.
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    node_delete($node->nid);
+    $this->assertTrue(node_load($node->nid, NULL, TRUE) == FALSE, 'Node without collection values deleted.');
+
+    // Test creating a field collection entity with a not-yet saved host entity.
+    $node = entity_create('node', array('type' => 'article'));
+    $entity = entity_create('field_collection_item', array('field_name' => $this->field_name));
+    $entity->setHostEntity('node', $node);
+    $entity->save();
+    // Now the node should have been saved with the collection and the link
+    // should have been established.
+    $this->assertTrue(!empty($node->nid), 'Node has been saved with the collection.');
+    $this->assertTrue(count($node->{$this->field_name}[LANGUAGE_NONE]) == 1 && !empty($node->{$this->field_name}[LANGUAGE_NONE][0]['value']) && !empty($node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id']), 'Link has been established.');
+
+    // Again, test creating a field collection with a not-yet saved host entity,
+    // but this time save both entities via the host.
+    $node = entity_create('node', array('type' => 'article'));
+    $entity = entity_create('field_collection_item', array('field_name' => $this->field_name));
+    $entity->setHostEntity('node', $node);
+    node_save($node);
+    $this->assertTrue(!empty($entity->item_id) && !empty($entity->revision_id), 'Collection has been saved with the host.');
+    $this->assertTrue(count($node->{$this->field_name}[LANGUAGE_NONE]) == 1 && !empty($node->{$this->field_name}[LANGUAGE_NONE][0]['value']) && !empty($node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id']), 'Link has been established.');
+
+    // Test Revisions.
+    list ($node, $item) = $this->createNodeWithFieldCollection();
+
+    // Test saving a new revision of a node.
+    $node->revision = TRUE;
+    node_save($node);
+    $item_updated = field_collection_item_load($node->{$this->field_name}[LANGUAGE_NONE][0]['value']);
+    $this->assertNotEqual($item->revision_id, $item_updated->revision_id, 'Creating a new host entity revision creates a new field collection revision.');
+
+    // Test saving the node without creating a new revision.
+    $item = $item_updated;
+    $node->revision = FALSE;
+    node_save($node);
+    $item_updated = field_collection_item_load($node->{$this->field_name}[LANGUAGE_NONE][0]['value']);
+    $this->assertEqual($item->revision_id, $item_updated->revision_id, 'Updating a new host entity  without creating a new revision does not create a new field collection revision.');
+
+    // Create a new revision of the node, such we have a non default node and
+    // field collection revision. Then test using it.
+    $vid = $node->vid;
+    $item_revision_id = $item_updated->revision_id;
+    $node->revision = TRUE;
+    node_save($node);
+
+    $item_updated = field_collection_item_load($node->{$this->field_name}[LANGUAGE_NONE][0]['value']);
+    $this->assertNotEqual($item_revision_id, $item_updated->revision_id, 'Creating a new host entity revision creates a new field collection revision.');
+    $this->assertTrue($item_updated->isDefaultRevision(), 'Field collection of default host entity revision is default too.');
+    $this->assertEqual($item_updated->hostEntityId(), $node->nid, 'Can access host entity ID of default field collection revision.');
+    $this->assertEqual($item_updated->hostEntity()->vid, $node->vid, 'Loaded default host entity revision.');
+
+    $item = entity_revision_load('field_collection_item', $item_revision_id);
+    $this->assertFalse($item->isDefaultRevision(), 'Field collection of non-default host entity is non-default too.');
+    $this->assertEqual($item->hostEntityId(), $node->nid, 'Can access host entity ID of non-default field collection revision.');
+    $this->assertEqual($item->hostEntity()->vid, $vid, 'Loaded non-default host entity revision.');
+
+    // Delete the non-default revision and make sure the field collection item
+    // revision has been deleted too.
+    entity_revision_delete('node', $vid);
+    $this->assertFalse(entity_revision_load('node', $vid), 'Host entity revision deleted.');
+    $this->assertFalse(entity_revision_load('field_collection_item', $item_revision_id), 'Field collection item revision deleted.');
+
+    // Test having archived field collections, i.e. collections referenced only
+    // in non-default revisions.
+    list ($node, $item) = $this->createNodeWithFieldCollection();
+    // Create two revisions.
+    $node_vid = $node->vid;
+    $node->revision = TRUE;
+    node_save($node);
+
+    $node_vid2 = $node->vid;
+    $node->revision = TRUE;
+    node_save($node);
+
+    // Now delete the field collection item for the default revision.
+    $item = field_collection_item_load($node->{$this->field_name}[LANGUAGE_NONE][0]['value']);
+    $item_revision_id = $item->revision_id;
+    $item->deleteRevision();
+    $node = node_load($node->nid);
+    $this->assertTrue(!isset($node->{$this->field_name}[LANGUAGE_NONE][0]), 'Field collection item revision removed from host.');
+    $this->assertFalse(field_collection_item_revision_load($item->revision_id), 'Field collection item default revision deleted.');
+
+    $item = field_collection_item_load($item->item_id);
+    $this->assertNotEqual($item->revision_id, $item_revision_id, 'Field collection default revision has been updated.');
+    $this->assertTrue($item->archived, 'Field collection item has been archived.');
+    $this->assertFalse($item->isInUse(), 'Field collection item specified as not in use.');
+    $this->assertTrue($item->isDefaultRevision(), 'Field collection of non-default host entity is default (but archived).');
+    $this->assertEqual($item->hostEntityId(), $node->nid, 'Can access host entity ID of non-default field collection revision.');
+    $this->assertEqual($item->hostEntity()->nid, $node->nid, 'Loaded non-default host entity revision.');
+
+    // Test deleting a revision of an archived field collection.
+    $node_revision2 = node_load($node->nid, $node_vid2);
+    $item = field_collection_item_revision_load($node_revision2->{$this->field_name}[LANGUAGE_NONE][0]['revision_id']);
+    $item->deleteRevision();
+    // There should be one revision left, so the item should still exist.
+    $item = field_collection_item_load($item->item_id);
+    $this->assertTrue($item->archived, 'Field collection item is still archived.');
+    $this->assertFalse($item->isInUse(), 'Field collection item specified as not in use.');
+
+    // Test that deleting the first node revision deletes the whole field
+    // collection item as it contains its last revision.
+    node_revision_delete($node_vid);
+    $this->assertFalse(field_collection_item_load($item->item_id), 'Archived field collection deleted when last revision deleted.');
+
+    // Test that removing a field-collection item also deletes it.
+    list ($node, $item) = $this->createNodeWithFieldCollection();
+
+    $node->{$this->field_name}[LANGUAGE_NONE] = array();
+    $node->revision = FALSE;
+    node_save($node);
+    $this->assertFalse(field_collection_item_load($item->item_id), 'Removed field collection item has been deleted.');
+
+    // Test removing a field-collection item while creating a new host revision.
+    list ($node, $item) = $this->createNodeWithFieldCollection();
+    $node->{$this->field_name}[LANGUAGE_NONE] = array();
+    $node->revision = TRUE;
+    node_save($node);
+    // Item should not be deleted but archived now.
+    $item = field_collection_item_load($item->item_id);
+    $this->assertTrue($item, 'Removed field collection item still exists.');
+    $this->assertTrue($item->archived, 'Removed field collection item is archived.');
+  }
+
+  /**
+   * Make sure the basic UI and access checks are working.
+   */
+  function testBasicUI() {
+    // Add a field to the collection.
+    $field = array(
+      'field_name' => 'field_text',
+      'type' => 'text',
+      'cardinality' => 1,
+      'translatable' => FALSE,
+    );
+    field_create_field($field);
+    $instance = array(
+      'entity_type' => 'field_collection_item',
+      'field_name' => 'field_text',
+      'bundle' => $this->field_name,
+      'label' => 'Test text field',
+      'widget' => array(
+        'type' => 'text_textfield',
+      ),
+    );
+    field_create_instance($instance);
+
+    $user = $this->drupalCreateUser();
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+
+    $this->drupalLogin($user);
+    // Make sure access is denied.
+    $path = 'field-collection/field-test-collection/add/node/' . $node->nid;
+    $this->drupalGet($path);
+    $this->assertText(t('Access denied'), 'Access has been denied.');
+
+    $user_privileged = $this->drupalCreateUser(array('access content', 'edit any article content'));
+    $this->drupalLogin($user_privileged);
+    $this->drupalGet("node/$node->nid");
+    $this->assertLinkByHref($path, 0, 'Add link is shown.');
+    $this->drupalGet($path);
+    $this->assertText(t('Test text field'), 'Add form is shown.');
+
+    $edit['field_text[und][0][value]'] = $this->randomName();
+    $this->drupalPost($path, $edit, t('Save'));
+    $this->assertText(t('The changes have been saved.'), 'Field collection saved.');
+
+    $this->assertText($edit['field_text[und][0][value]'], "Added field value is shown.");
+
+    $edit['field_text[und][0][value]'] = $this->randomName();
+    $this->drupalPost('field-collection/field-test-collection/1/edit', $edit, t('Save'));
+    $this->assertText(t('The changes have been saved.'), 'Field collection saved.');
+    $this->assertText($edit['field_text[und][0][value]'], "Field collection has been edited.");
+
+    $this->drupalGet('field-collection/field-test-collection/1');
+    $this->assertText($edit['field_text[und][0][value]'], "Field collection can be viewed.");
+
+    // Add further 3 items, so we have reached 4 == maxium cardinality.
+    $this->drupalPost($path, $edit, t('Save'));
+    $this->drupalPost($path, $edit, t('Save'));
+    $this->drupalPost($path, $edit, t('Save'));
+    // Make sure adding doesn't work any more as we have restricted cardinality
+    // to 1.
+    $this->drupalGet($path);
+    $this->assertText(t('Too many items.'), 'Maxium cardinality has been reached.');
+
+    $this->drupalPost('field-collection/field-test-collection/1/delete', array(), t('Delete'));
+    $this->drupalGet($path);
+    // Add form is shown again.
+    $this->assertText(t('Test text field'), 'Field collection item has been deleted.');
+
+    // Test the viewing a revision. There should be no links to change it.
+    $vid = $node->vid;
+    $node = node_load($node->nid, NULL, TRUE);
+    $node->revision = TRUE;
+    node_save($node);
+
+    $this->drupalGet("node/$node->nid/revisions/$vid/view");
+    $this->assertResponse(403, 'Access to view revision denied');
+    // Login in as admin and try again.
+    $user = $this->drupalCreateUser(array('administer nodes', 'bypass node access'));
+    $this->drupalLogin($user);
+    $this->drupalGet("node/$node->nid/revisions/$vid/view");
+    $this->assertNoResponse(403, 'Access to view revision granted');
+
+    $this->assertNoLinkByHref($path, 'No links on revision view.');
+    $this->assertNoLinkByHref('field-collection/field-test-collection/2/edit', 'No links on revision view.');
+    $this->assertNoLinkByHref('field-collection/field-test-collection/2/delete', 'No links on revision view.');
+
+    $this->drupalGet("node/$node->nid/revisions");
+  }
+}
+
+
+/**
+ * Test using field collection with Rules.
+ */
+class FieldCollectionRulesIntegrationTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Field collection Rules integration',
+      'description' => 'Tests using field collections with rules.',
+      'group' => 'Field types',
+      'dependencies' => array('rules'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('field_collection', 'rules'));
+    variable_set('rules_debug_log', 1);
+  }
+
+  protected function createFields($cardinality = 4) {
+    // Create a field_collection field to use for the tests.
+    $this->field_name = 'field_test_collection';
+    $this->field = array('field_name' => $this->field_name, 'type' => 'field_collection', 'cardinality' => $cardinality);
+    $this->field = field_create_field($this->field);
+    $this->field_id = $this->field['id'];
+
+    $this->instance = array(
+      'field_name' => $this->field_name,
+      'entity_type' => 'node',
+      'bundle' => 'article',
+      'label' => $this->randomName() . '_label',
+      'description' => $this->randomName() . '_description',
+      'weight' => mt_rand(0, 127),
+      'settings' => array(),
+      'widget' => array(
+        'type' => 'hidden',
+        'label' => 'Test',
+        'settings' => array(),
+      ),
+    );
+    $this->instance = field_create_instance($this->instance);
+    // Add a field to the collection.
+    $field = array(
+      'field_name' => 'field_text',
+      'type' => 'text',
+      'cardinality' => 1,
+      'translatable' => FALSE,
+    );
+    field_create_field($field);
+    $instance = array(
+      'entity_type' => 'field_collection_item',
+      'field_name' => 'field_text',
+      'bundle' => $this->field_name,
+      'label' => 'Test text field',
+      'widget' => array(
+        'type' => 'text_textfield',
+      ),
+    );
+    field_create_instance($instance);
+  }
+
+  /**
+   * Test creation field collection items.
+   */
+  function testCreation() {
+    $this->createFields();
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    // Create a field collection.
+    $action_set = rules_action_set(array('node' => array('type' => 'node', 'bundle' => 'article')));
+    $action_set->action('entity_create', array(
+      'type' => 'field_collection_item',
+      'param_field_name' => $this->field_name,
+      'param_host_entity:select' => 'node',
+    ));
+    $action_set->action('data_set', array('data:select' => 'entity-created:field-text', 'value' => 'foo'));
+    $action_set->execute($node);
+
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertTrue(!empty($node->{$this->field_name}[LANGUAGE_NONE][0]['value']), 'A field_collection has been successfully created.');
+    $this->assertTrue(!empty($node->{$this->field_name}[LANGUAGE_NONE][0]['revision_id']), 'A field_collection has been successfully created (revision).');
+
+    // Now try making use of the field collection in rules.
+    $action_set = rules_action_set(array('node' => array('type' => 'node', 'bundle' => 'article')));
+    $action_set->action('drupal_message', array('message:select' => 'node:field-test-collection:0:field-text'));
+    $action_set->execute($node);
+
+    $msg = drupal_get_messages();
+    $this->assertEqual(array_pop($msg['status']), 'foo', 'Field collection can be used.');
+    RulesLog::logger()->checkLog();
+  }
+
+  /**
+   * Test using field collection items via the host while they are being created.
+   */
+  function testUsageDuringCreation() {
+    // Test using a single-cardinality field collection.
+    $this->createFields(1);
+
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $entity = entity_create('field_collection_item', array('field_name' => $this->field_name));
+    $entity->setHostEntity('node', $node);
+    // Now the field collection is linked to the host, but not yet saved.
+
+    // Test using the wrapper on it.
+    $wrapper = entity_metadata_wrapper('node', $node);
+    $wrapper->get($this->field_name)->field_text->set('foo');
+    $this->assertEqual($entity->field_text[LANGUAGE_NONE][0]['value'], 'foo', 'Field collection item used during creation via the wrapper.');
+
+    // Now test it via Rules, which should save our changes.
+    $set = rules_action_set(array('node' => array('type' => 'node', 'bundle' => 'article')));
+    $set->action('data_set', array('data:select' => 'node:' . $this->field_name . ':field-text', 'value' => 'bar'));
+    $set->execute($node);
+    $this->assertEqual($entity->field_text[LANGUAGE_NONE][0]['value'], 'bar', 'Field collection item used during creation via Rules.');
+    $this->assertTrue(!empty($entity->item_id) && !empty($entity->revision_id), 'Field collection item has been saved by Rules and the host entity.');
+    RulesLog::logger()->checkLog();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/field_collection.theme.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,66 @@
+@CHARSET "UTF-8";
+
+.field-collection-container {
+  border-bottom: 1px solid #D3D7D9;
+  margin-bottom: 1em;
+}
+
+.field-collection-container .field-items .field-item {
+  margin-bottom: 10px;
+}
+
+.field-collection-container .field-items .field-items .field-item {
+  margin-bottom: 0;
+}
+
+.field-collection-view {
+  padding: 1em 0 0.3em 0;
+  margin: 0 1em 0 1em;
+  border-bottom: 1px dotted #D3D7D9;
+}
+
+/* If there is no add link, don't show the final border. */
+.field-collection-view-final {
+  border-bottom: none;
+}
+
+.field-collection-view .entity-field-collection-item {
+  float: left;
+}
+
+.field-collection-view ul.field-collection-view-links {
+  float: right;
+  font-size: 0.821em;
+  list-style-type: none;
+  width: auto;
+  margin: 0 1em;
+  padding: 0;
+}
+
+.field-collection-view .field-label {
+  width: 25%;
+}
+
+.field-collection-view .content {
+  margin-top: 0;
+  width: 100%;
+}
+
+.field-collection-view .entity-field-collection-item {
+  width: 100%;
+}
+
+ul.field-collection-view-links li {
+  float: left;
+}
+
+ul.field-collection-view-links li a {
+  margin-right: 1em;
+}
+
+.field-collection-container ul.action-links-field-collection-add {
+  float: right;
+  padding: 0 0.5em 0 0;
+  margin: 0 0 1em 2em;
+  font-size: 0.821em;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/views/field_collection.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * Implements hook_field_views_data().
+ *
+ * Views integration for field collection fields. Adds a relationship to the
+ * default field data.
+ *
+ * @see field_views_field_default_views_data()
+ */
+function field_collection_field_views_data($field) {
+  $data = field_views_field_default_views_data($field);
+
+  foreach ($data as $table_name => $table_data) {
+    foreach ($table_data as $field_name => $field_data) {
+      // Only operate on the "field_api_field_name"_value column.
+      if (strrpos($field_name, '_value') === (strlen($field_name) - strlen('_value'))) {
+        $data[$table_name][$field_name]['relationship'] = array(
+          'handler' => 'field_collection_handler_relationship',
+          'base' => 'field_collection_item',
+          'base field' => 'item_id',
+          'label' => t('field collection item from !field_name', array('!field_name' => $field['field_name'])),
+          'field_name' => $field['field_name'],
+        );
+      }
+    }
+  }
+
+  foreach ($field['bundles'] as $entity_type => $bundles) {
+    $entity_info = entity_get_info($entity_type);
+    $pseudo_field_name = $field['field_name'] . '_' . $entity_type;
+
+    list($label, $all_labels) = field_views_field_label($field['field_name']);
+    $entity = $entity_info['label'];
+    if ($entity == t('Node')) {
+      $entity = t('Content');
+    }
+
+    $data['field_collection_item'][$pseudo_field_name]['relationship'] = array(
+      'title' => t('Entity with the @field (@field_name)', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name'])),
+      'help' => t('Relate each @entity using @field.', array('@entity' => $entity, '@field' => $label)),
+      'handler' => 'views_handler_relationship_entity_reverse',
+      'field_name' => $field['field_name'],
+      'field table' => _field_sql_storage_tablename($field),
+      'field field' => $field['field_name'] . '_value',
+      'base' => $entity_info['base table'],
+      'base field' => $entity_info['entity keys']['id'],
+      'label' => t('!field_name', array('!field_name' => $field['field_name'])),
+    );
+  }
+
+  return $data;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_collection/views/field_collection_handler_relationship.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Provide relationship handler for field collection fields.
+ */
+class field_collection_handler_relationship extends views_handler_relationship {
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['delta'] = array('default' => -1);
+
+    return $options;
+  }
+
+  /**
+   * Add a delta selector for multiple fields.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $field = field_info_field($this->definition['field_name']);
+
+    // Only add the delta selector if the field is multiple.
+    if ($field['cardinality']) {
+      $max_delta = ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) ? 10 : $field['cardinality'];
+
+      $options = array('-1' => t('All'));
+      for ($i = 0; $i < $max_delta; $i++) {
+        $options[$i] = $i + 1;
+      }
+      $form['delta'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#default_value' => $this->options['delta'],
+        '#title' => t('Delta'),
+        '#description' => t('The delta allows you to select which item in a multiple value field to key the relationship off of. Select "1" to use the first item, "2" for the second item, and so on. If you select "All", each item in the field will create a new row, which may appear to cause duplicates.'),
+      );
+    }
+  }
+
+  function ensure_my_table() {
+    $field = field_info_field($this->definition['field_name']);
+
+    if (!isset($this->table_alias)) {
+      $join = $this->get_join();
+      if ($this->options['delta'] != -1 && $field['cardinality']) {
+        $join->extra[] = array(
+          'field' => 'delta',
+          'value' => $this->options['delta'],
+          'numeric' => TRUE,
+        );
+      }
+      $this->table_alias = $this->query->add_table($this->table, $this->relationship, $join);
+    }
+    return $this->table_alias;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/CHANGELOG.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,40 @@
+/* $Id*/
+CHANGELOG for field_group for Drupal 7
+
+Field_group 7.x-1.x-dev
+    o Issue #1095316: Field Groups disappear when Content Type is renamed.
+    o Issue #1095316 by swentel: Support for Entity API.
+    o Issue #1095002 by animelion: Upgrading removes all existing field groups.
+    o Issue #1095130 by willvincent: Features export not working with rc2.
+    
+Field_group 7.x-1.0-rc2
+    o Ran through coder, minor.
+    o Issue #1033036 by Stalski, swentel: Create a field_group.api.php.
+    o Made the summary descriptions more human readable.
+    o Issue #1086450: Cannot see red star on some field groups even required fields are set to 1.
+    o #1072292 by shadow_jh, stalski: Using on user settings page but need to hid on registration page.
+    o #1092360 by dww: Move field_group_update_7000 functionality to hook_install().
+    o #1061228 Rewrite the field_group_field_group_is_empty function.
+    o Added ID's to fieldgroups.
+    o Removed unused field_group.admin.inc + menu item. Required asterix moving to field_group setting.
+    o #1045526 by stalski: Make formatter options more user-friendly and logical.
+    o #1041880 by robertgarrigos: duplicated entries in field_group table.
+    o #1043834 by amsri: Field Group module just does not work with profiles 2.
+    
+Field_group 7.x-1.0-rc1
+    o #1006464 Change #groups to #fieldgroups because of name collapsing with form_process_fieldset
+    o #1024184 fix collapsible when mode is set to open
+    o #1020278 by mori: Update fails.
+    o #1020116 by mikegfx: Confusing verbage across group types.
+    o #1018012 by mikegfx: Adding required asterisk to group tabs that have required fields.
+    o #960916 fixed reference warnings.
+    o No label anymore with div>open.
+    o #969258 Added check for fields and extra_fields.
+    o #960916 Fixed notice on for reference on group in field_group_settings.
+    o #961106 Fixed notice on entity type and bundle check.
+    o #962072 by mori: Improve CSS for horizontal tabs & accordion.
+    o Changed Fieldgroup API: defaults and instance_settings are now merged.
+    o Changed save action so everything is gathered during form_state to 
+      postpone saving until the save button is hit.
+    o Changed some important variable name, so it makes more sense and easier to read.
+    o Add basic crud functions.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,47 @@
+
+History:
+  Field_group was written for Drupal 7. For drupal 6, the module is
+  located in the CCK module (http://drupal.org/project/cck).
+  As drupal core has a fields API drupal > 6, the field_group module
+  is considered a contribution.
+
+Description:
+  field_group is a module that will group a set of fields. In Drupal7,
+  with fields, one means all fields that come from fieldable entities.
+  You can add fieldgroups in several types with their own format settings.
+  field_group has API functions to add your own formatter and rendering for
+  it.
+  One of the biggest improvements to previous versions, is that fieldgroups
+  have unlimited nesting, better display control.
+  Note that field_group will only group fields, it can not be used to hide
+  certain fields since this a permission matter.
+
+Module project page:
+  http://drupal.org/project/field_group
+
+Documentation page:
+  http://drupal.org/node/1017838
+  http://drupal.org/node/1017962
+
+Available group types:
+  - Fieldsets
+  - Horizontal tabs
+  - Vertical tabs
+  - Accordions
+  - Divs
+  - Multipage steps: <strong>Note: This is only client side.
+  - HTML5 group type
+  - Html element
+
+To submit bug reports and feature suggestions, or to track changes:
+  http://drupal.org/project/issues/field_group
+
+-- MAINTAINERS --
+
+stalski - http://drupal.org/user/322618
+swentel - http://drupal.org/user/107403
+zuuperman - http://drupal.org/user/361625
+
+-- INSPIRATORS --
+
+yched - http://drupal.org/user/39567
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group-rtl.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,7 @@
+/**
+ * Override the accordion default style for view_modes.
+ */
+form .ui-accordion h3, form .ui-accordion h3.ui-state-active {
+  padding-left: 0;
+  padding-right: 2em;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,460 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the Field group module.
+ *
+ * Fieldgroup is a module that will wrap fields and other fieldgroups. Nothing more, nothing less.
+ * For this there are formatters we can create on forms and view modes.
+ *
+ * Some of the elements defined in fieldgroup will be ported to the elements module.
+ *
+ * DEVELOPERS NOTES
+ *
+ * - Fieldgroup uses a ''#fieldgroups' property to know what fieldgroups are to be pre_rendered and
+ *   rendered by the field_group module. This means we need to be sure our groups are in #fieldgroups.
+ *   #fieldgroups is later merged with the normal #groups that can be used by any other module.
+ *   This is done to be sure fieldgroup is not taking fieldsets from profile2, commerce line items,
+ *   commerce user profiles, ... .
+ *   When trying to merge a programmatically created field wrapper (div, markup, fieldset, ...) into
+ *   groups, you might consider adding it in #field_groups as well if you want the element processed
+ *   by fieldgroup.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+
+/**
+ * Javascript hooks
+ *
+ * Drupal.FieldGroup.Effects.processHook.execute()
+ * See field_group.js for the examples for all implemented formatters.
+ */
+
+
+/**
+ * Implements hook_field_group_formatter_info().
+ *
+ * Define the information on formatters. The formatters are
+ * separated by view mode type. We have "form" for all form elements
+ * and "display" will be the real view modes (full, teaser, sticky, ...)
+ *
+ * structure:
+ * @code
+ * array(
+ *   'form' => array(
+ *     'fieldset' => array(
+ *       // required, String with the name of the formatter type.
+ *       'label' => t('Fieldset'),
+ *       // optional, String description of the formatter type.
+ *       'description' => t('This is field group that ...'),
+ *       // required, Array of available formatter options.
+ *       'format_types' => array('open', 'collapsible', 'collapsed'),
+ *       // required, String with default value of the style.
+        'default_formatter' => 'collapsible',
+ *       // optional, Array with key => default_value pairs.
+ *       'instance_settings' => array('key' => 'value'),
+ *     ),
+ *   ),
+ *   'display' => array(
+ *     'fieldset' => array(
+ *       // required, String with the name of the formatter type.
+ *       'label' => t('Fieldset'),
+ *       // optional, String description of the formatter type.
+ *       'description' => t('This is field group that ...'),
+ *       // required, Array of available formatter options.
+ *       'format_types' => array('open', 'collapsible', 'collapsed'),
+ *       // required, String with default value of the style.
+        'default_formatter' => 'collapsible',
+ *       // optional, Array with key => default_value pairs.
+ *       'instance_settings' => array('key' => 'value'),
+ *     ),
+ *   ),
+ * ),
+ * @endcode
+ *
+ * @return $formatters
+ *   A collection of available formatting html controls for form
+ *   and display overview type.
+ *
+ * @see field_group_field_group_formatter_info()
+ */
+function hook_field_group_formatter_info() {
+  return array(
+    'form' => array(
+      'fieldset' => array(
+        'label' => t('Fieldset'),
+        'description' => t('This fieldgroup renders the inner content in a fieldset with the title as legend.'),
+        'format_types' => array('open', 'collapsible', 'collapsed'),
+        'instance_settings' => array('classes' => ''),
+        'default_formatter' => 'collapsible',
+      ),
+    ),
+    'display' => array(
+      'div' => array(
+        'label' => t('Div'),
+        'description' => t('This fieldgroup renders the inner content in a simple div with the title as legend.'),
+        'format_types' => array('open', 'collapsible', 'collapsed'),
+        'instance_settings' => array('effect' => 'none', 'speed' => 'fast', 'classes' => ''),
+        'default_formatter' => 'collapsible',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_group_format_settings().
+ *
+ * Defines configuration widget for the settings on a field group
+ * formatter. Eache formatter can have different elements and storage.
+ *
+ * @params Object $group The group object.
+ * @return Array $form The form element for the format settings.
+ */
+function hook_field_group_format_settings($group) {
+  // Add a wrapper for extra settings to use by others.
+  $form = array(
+    'instance_settings' => array(
+      '#tree' => TRUE,
+      '#weight' => 2,
+    ),
+  );
+
+  $field_group_types = field_group_formatter_info();
+  $mode = $group->mode == 'form' ? 'form' : 'display';
+  $formatter = $field_group_types[$mode][$group->format_type];
+
+  // Add the required formatter type selector.
+  if (isset($formatter['format_types'])) {
+    $form['formatter'] = array(
+      '#title' => t('Fieldgroup settings'),
+      '#type' => 'select',
+      '#options' => drupal_map_assoc($formatter['format_types']),
+      '#default_value' => isset($group->format_settings['formatter']) ? $group->format_settings['formatter'] : $formatter['default_formatter'],
+      '#weight' => 1,
+    );
+  }
+  if ($mode == 'form') {
+    $form['instance_settings']['required_fields'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Mark group for required fields.'),
+      '#default_value' => isset($group->format_settings['instance_settings']['required_fields']) ? $group->format_settings['instance_settings']['required_fields'] : (isset($formatter['instance_settings']['required_fields']) ? $formatter['instance_settings']['required_fields'] : ''),
+      '#weight' => 2,
+    );
+  }
+  $form['instance_settings']['classes'] = array(
+    '#title' => t('Extra CSS classes'),
+    '#type' => 'textfield',
+    '#default_value' => isset($group->format_settings['instance_settings']['classes']) ? $group->format_settings['instance_settings']['classes'] : (isset($formatter['instance_settings']['classes']) ? $formatter['instance_settings']['classes'] : ''),
+    '#weight' => 3,
+    '#element_validate' => array('field_group_validate_css_class'),
+  );
+  $form['instance_settings']['description'] = array(
+    '#title' => t('Description'),
+    '#type' => 'textarea',
+    '#default_value' => isset($group->format_settings['instance_settings']['description']) ? $group->format_settings['instance_settings']['description'] : (isset($formatter['instance_settings']['description']) ? $formatter['instance_settings']['description'] : ''),
+    '#weight' => 0,
+  );
+
+  // Add optional instance_settings.
+  switch ($group->format_type) {
+    case 'div':
+      $form['instance_settings']['effect'] = array(
+        '#title' => t('Effect'),
+        '#type' => 'select',
+        '#options' => array('none' => t('None'), 'blind' => t('Blind')),
+        '#default_value' => isset($group->format_settings['instance_settings']['effect']) ? $group->format_settings['instance_settings']['effect'] : $formatter['instance_settings']['effect'],
+        '#weight' => 2,
+      );
+      $form['instance_settings']['speed'] = array(
+        '#title' => t('Speed'),
+        '#type' => 'select',
+        '#options' => array('none' => t('None'), 'slow' => t('Slow'), 'fast' => t('Fast')),
+        '#default_value' => isset($group->format_settings['instance_settings']['speed']) ? $group->format_settings['instance_settings']['speed'] : $formatter['instance_settings']['speed'],
+        '#weight' => 3,
+      );
+      break;
+    case 'fieldset':
+      $form['instance_settings']['classes'] = array(
+        '#title' => t('Extra CSS classes'),
+        '#type' => 'textfield',
+        '#default_value' => isset($group->format_settings['instance_settings']['classes']) ? $group->format_settings['instance_settings']['classes'] : $formatter['instance_settings']['classes'],
+        '#weight' => 3,
+        '#element_validate' => array('field_group_validate_css_class'),
+      );
+      break;
+    case 'tabs':
+    case 'htabs':
+    case 'accordion':
+      unset($form['instance_settings']['description']);
+      if (isset($form['instance_settings']['required_fields'])) {
+        unset($form['instance_settings']['required_fields']);
+      }
+      break;
+    case 'tab':
+    case 'htab':
+    case 'accordion-item':
+    default:
+  }
+
+  return $form;
+}
+
+/**
+ * Implements hook_field_group_pre_render().
+ *
+ * This function gives you the oppertunity to create the given
+ * wrapper element that can contain the fields.
+ * In the example beneath, some variables are prepared and used when building the
+ * actual wrapper element. All elements in drupal fapi can be used.
+ *
+ * Note that at this point, the field group has no notion of the fields in it.
+ *
+ * There is also an alternative way of handling this. The default implementation
+ * within field_group calls "field_group_pre_render_<format_type>".
+ * @see field_group_pre_render_fieldset.
+ *
+ * @param Array $elements by address.
+ * @param Object $group The Field group info.
+ */
+function hook_field_group_pre_render(& $element, $group, & $form) {
+
+  // You can prepare some variables to use in the logic.
+  $view_mode = isset($form['#view_mode']) ? $form['#view_mode'] : 'form';
+  $id = $form['#entity_type'] . '_' . $form['#bundle'] . '_' . $view_mode . '_' . $group->group_name;
+
+  // Each formatter type can have whole different set of element properties.
+  switch ($group->format_type) {
+
+    // Normal or collapsible div.
+    case 'div':
+      $effect = isset($group->format_settings['instance_settings']['effect']) ? $group->format_settings['instance_settings']['effect'] : 'none';
+      $speed = isset($group->format_settings['instance_settings']['speed']) ? $group->format_settings['instance_settings']['speed'] : 'none';
+      $add = array(
+        '#type' => 'markup',
+        '#weight' => $group->weight,
+        '#id' => $id,
+      );
+      $classes .= " speed-$speed effect-$effect";
+      if ($group->format_settings['formatter'] != 'open') {
+        $add['#prefix'] = '<div class="field-group-format ' . $classes . '">
+          <span class="field-group-format-toggler">' . check_plain(t($group->label)) . '</span>
+          <div class="field-group-format-wrapper" style="display: none;">';
+        $add['#suffix'] = '</div></div>';
+      }
+      else {
+        $add['#prefix'] = '<div class="field-group-format ' . $group->group_name . ' ' . $classes . '">';
+        $add['#suffix'] = '</div>';
+      }
+      if (!empty($description)) {
+        $add['#prefix'] .= '<div class="description">' . $description . '</div>';
+      }
+      $element += $add;
+
+      if ($effect == 'blind') {
+        drupal_add_library('system', 'effects.blind');
+      }
+
+      break;
+    break;
+  }
+}
+
+/**
+ * Implements hook_field_group_pre_render().
+ *
+ * Function that fungates as last resort to alter the pre_render build.
+ */
+function hook_field_group_pre_render_alter(&$element, $group, & $form) {
+
+  if ($group->format_type == 'htab') {
+    $element['#theme_wrappers'] = array('my_horizontal_tab');
+  }
+
+}
+
+/**
+ * Implements hook_field_group_build_pre_render_alter().
+ *
+ * Function that fungates as last resort where you can alter things. It is
+ * expected that when you need this function, you have most likely a very custom
+ * case or it is a fix that can be put in field_group core.
+ *
+ * @param Array $elements by address.
+ */
+function hook_field_group_build_pre_render_alter(& $element) {
+
+  // Prepare variables.
+  $display = isset($element['#view_mode']);
+  $groups = array_keys($element['#groups']);
+
+  // Example from field_group itself to unset empty elements.
+  if ($display) {
+    foreach (element_children($element) as $name) {
+      if (in_array($name, $groups)) {
+        if (field_group_field_group_is_empty($element[$name], $groups)) {
+          unset($element[$name]);
+        }
+      }
+    }
+  }
+
+  // You might include additional javascript files and stylesheets.
+  $element['#attached']['js'][] = drupal_get_path('module', 'field_group') . '/field_group.js';
+  $element['#attached']['css'][] = drupal_get_path('module', 'field_group') . '/field_group.css';
+
+}
+
+/**
+ * Implements hook_field_group_format_summary().
+ *
+ * Place to override or change default summary behavior. In most
+ * cases the implementation of field group itself will be enough.
+ *
+ * TODO It might be better to change this hook with already created summaries,
+ * giving the ability to alter or add it later on.
+ */
+function hook_field_group_format_summary($group) {
+  $output = '';
+  // Create additional summary or change the default setting.
+  return $output;
+}
+
+/**
+ * Implement hook_ctools_plugin_api().
+ * This hook is needed to let ctools know about exportables.
+ * If you create field groups by using hook_field_group_info, you
+ * will need to include the ctools api hook as well.
+ */
+function hook_ctools_plugin_api($module, $api) {
+  if ($module == 'field_group' && $api == 'field_group') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_field_group_info().
+ * Don't forget to include the ctools hook to notify that
+ * your modules has field group exports.
+ * @see hook_ctools_plugin_api.
+ */
+function hook_field_group_info() {
+
+}
+
+/**
+ * Alter the field group definitions provided by other modules.
+ *
+ * @param array $groups
+ *   Reference to an array of field group definition objects.
+ */
+function hook_field_group_info_alter(&$groups) {
+  if (!empty($groups['group_issue_metadata|node|project_issue|form'])) {
+    $groups['group_issue_metadata|node|project_issue|form']->data['children'][] = 'taxonomy_vocabulary_9';
+  }
+}
+
+/**
+ * Implements hook_field_group_update_field_group().
+ *
+ * This hook is invoked by ctools export API.
+ * Note that this is used by ctools and the group could occasional be
+ * the group ID.
+ *
+ * @param $object $group
+ *   The FieldGroup object.
+ */
+function hook_field_group_update_field_group($group) {
+  // Delete extra data depending on the group.
+}
+
+/**
+ * Implements hook_field_group_delete_field_group().
+ *
+ * This hook is invoked by ctools export API.
+ *
+ * @param $object $group
+ *   The FieldGroup object.
+ */
+function hook_field_group_delete_field_group($group) {
+  // Delete extra data depending on the group.
+}
+
+/**
+ * Implements hook_field_group_create_field_group().
+ *
+ * This hook is invoked by ctools export API.
+ *
+ * @param $object $group
+ *   The FieldGroup object.
+ */
+function hook_field_group_create_field_group($group) {
+  // Create extra data depending on the group.
+}
+
+
+
+/**
+ * @} End of "addtogroup hooks".
+ */
+
+
+
+/**
+ * @addtogroup utility functions
+ * @{
+ */
+
+/**
+ * Get the groups for a given entity type, bundle and view mode.
+ *
+ * @param String $entity_type
+ *   The Entity type where field groups are requested.
+ * @param String $bundle
+ *   The entity bundle for the field groups.
+ * @param String $view_mode
+ *   The view mode scope for the field groups.
+ *
+ * @see field_group_read_groups()
+ * @see ctools_export_crud_load()
+ * @see ctools_export_crud_load_all()
+ * @see ctools_export_crud_delete()
+ * @see ctools_export_crud_save()
+ */
+function field_group_info_groups($entity_type = NULL, $bundle = NULL, $view_mode = NULL, $reset = FALSE) {
+  // This function caches the result and delegates to field_group_read_groups.
+}
+
+/**
+ * Get the groups for the given parameters, uncached.
+ *
+ * @param Array $params
+ *   The Entity type where field groups are requested.
+ * @param $enabled
+ *   Return enabled or disabled groups.*
+ *
+ * @see field_group_info_groups()
+ * @see ctools_export_load_object()
+ */
+function field_group_read_groups($conditions = array(), $enabled = TRUE) {
+  // This function loads the requested groups through ctools export api.
+}
+
+/**
+ * Hides field groups including children in a render array.
+ *
+ * @param array $element
+ *   A render array. Can be a form, node, user, ...
+ * @param array $group_names
+ *   An array of field group names that should be hidden.
+ */
+function field_group_hide_field_groups(&$element, $group_names) {
+}
+
+/**
+ * @} End of "addtogroup utility functions".
+ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+/* $Id: field_group.css,v 1.1.2.12 2010/12/22 22:22:35 stalski Exp $ */
+
+/**
+ * Fix for fieldsets in vertical tabs.
+ * Note that this can only be hardcoded to the Seven theme
+ * where people who override this, are in trouble.
+ * This can be removed in next d7 release.
+ */
+.vertical-tabs fieldset.default-fallback,
+div.field-group-tabs-wrapper div.field-type-image fieldset,
+div.field-group-tabs-wrapper div.field-type-file fieldset,
+div.field-group-tabs-wrapper div.field-type-datetime fieldset {
+   border: 1px solid #CCCCCC;
+   margin: 1em 0;
+   padding: 2.5em 0 0;
+   position: relative;
+}
+
+div.field-group-tabs-wrapper div.field-type-image legend,
+div.field-group-tabs-wrapper div.field-type-file legend,
+div.field-group-tabs-wrapper div.field-type-datetime legend {
+  display: block;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,58 @@
+<?php
+
+
+/**
+ * Implements hook_features_export_alter().
+ *
+ * For a given feature, add field groups that contain any fields that
+ * are a part of this feature.  Also, add parent groups of any groups
+ * that are a part of this feature.
+ */
+function field_group_features_export_alter(&$export, $module_name) {
+  // Make sure we have fresh data by loading directly.
+  ctools_include('export');
+  $field_groups = ctools_export_load_object('field_group');
+
+  // Add fieldgroups based on the fields that are present.
+  if (!empty($export['features']['field'])) {
+    foreach ($export['features']['field'] as $field) {
+      list($entity_type, $bundle, $field_name) = explode('-', $field);
+
+      foreach ($field_groups as $group_id => $group) {
+        if ($group->entity_type == $entity_type && $group->bundle == $bundle
+          && in_array($field_name, $group->data['children']) && in_array($group->identifier, $export['features']['field_group'])) {
+          if (isset($group->export_module) && $group->export_module != $module_name) {
+            $export['dependencies'][$group->export_module] = $group->export_module;
+          }
+          else {
+            $export['features']['field_group'][$group_id] = $group_id;
+          }
+        }
+      }
+    }
+  }
+
+  // Add any parent field groups that haven't been selected.
+  if (!empty($export['features']['field_group'])) {
+    foreach ($export['features']['field_group'] as $id) {
+      $group = isset($field_groups[$id]) ? $field_groups[$id] : FALSE;
+
+      if ($group && !empty($group->parent_name)) {
+        $parent_id = $group->parent_name . '|' . $group->entity_type . '|' . $group->bundle . '|' . $group->mode;
+        $parent_group = isset($field_groups[$parent_id]) ? $field_groups[$parent_id] : FALSE;
+
+        if ($parent_group && !isset($export['features']['field_group'][$parent_id])) {
+          if (isset($parent_group->export_module) && $parent_group->export_module != $module_name) {
+            $export['dependencies'][$parent_group->export_module] = $parent_group->export_module;
+          }
+          else {
+            $export['features']['field_group'][$parent_id] = $parent_id;
+          }
+        }
+      }
+    }
+    if(empty($export['dependencies']['field_group'])) {
+      $export['dependencies']['field_group'] = 'field_group';
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.field_ui.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+
+#field-overview tr.field-group .group-label,
+#field-display-overview tr.field-group .group-label {
+  font-weight: bold;
+}
+
+#field-overview tr.static-region,
+#field-display-overview tr.static-region {
+	background-color: #ddd;
+}
+
+#edit-refresh {
+  display:none;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.field_ui.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1008 @@
+<?php
+
+/**
+ * @file
+ * Field_group.field_ui.inc is a file that contains most functions
+ * needed on the Fields UI Manage forms (display and fields).
+ */
+
+/**
+ * Helper function to get the form parameters to use while
+ * building the fields and display overview form.
+ */
+function field_group_field_ui_form_params($form, $display_overview) {
+
+  $params = new stdClass();
+  $params->entity_type = $form['#entity_type'];
+  $params->bundle = $form['#bundle'];
+  $params->admin_path = _field_ui_bundle_admin_path($params->entity_type, $params->bundle);
+  $params->display_overview = $display_overview;
+
+  if ($display_overview) {
+    $params->region_callback = 'field_group_display_overview_row_region';
+    $params->mode = $form['#view_mode'];
+  }
+  else {
+    $params->region_callback = 'field_group_field_overview_row_region';
+    $params->mode = 'form';
+  }
+
+  $params->groups = field_group_info_groups($params->entity_type, $params->bundle, $params->mode, TRUE);
+
+  // Gather parenting data.
+  $params->parents = array();
+  foreach ($params->groups as $name => $group) {
+    foreach ($group->children as $child) {
+      $params->parents[$child] = $name;
+    }
+  }
+
+  return $params;
+}
+
+/**
+ * Function to alter the fields overview and display overview screen.
+ */
+function field_group_field_ui_overview_form_alter(&$form, &$form_state, $display_overview = FALSE) {
+
+  // Only start altering the form if we need to.
+  if (empty($form['#fields']) && empty($form['#extra'])) {
+    return;
+  }
+
+  $params = field_group_field_ui_form_params($form, $display_overview);
+
+  // Add some things to be able to preserve synced usage of field_ui.
+  if (!$display_overview) {
+    // This key is used to store the current updated field.
+    $form_state += array(
+      'formatter_settings_edit' => NULL,
+    );
+    // Add AJAX wrapper.
+    $form['fields']['#prefix'] = '<div id="field-display-overview-wrapper">';
+    $form['fields']['#suffix'] = '</div>';
+  }
+  $form['#groups'] = array_keys($params->groups);
+
+  $table = &$form['fields'];
+
+  // Add a region for 'add_new' rows, but only when fields are
+  // available and thus regions.
+  if (isset($table['#regions'])) {
+    $table['#regions'] += array(
+      'add_new' => array('title' => '&nbsp;'),
+    );
+  }
+
+  // Extend available parenting options.
+  foreach ($params->groups as $name => $group) {
+    $table['#parent_options'][$name] = $group->label;
+  }
+  $table['#parent_options']['_add_new_group'] = t('Add new group');
+
+  // Update existing rows accordingly to the parents.
+  foreach (element_children($table) as $name) {
+    $table[$name]['parent_wrapper']['parent']['#options'] = $table['#parent_options'];
+    // Inherit the value of the parent when default value is empty.
+    if (empty($table[$name]['parent_wrapper']['parent']['#default_value'])) {
+      $table[$name]['parent_wrapper']['parent']['#default_value'] = isset($params->parents[$name]) ? $params->parents[$name] : '';
+    }
+  }
+
+  $formatter_options = field_group_field_formatter_options($display_overview ? 'display' : 'form');
+
+  $refresh_rows = isset($form_state['values']['refresh_rows']) ? $form_state['values']['refresh_rows'] : (isset($form_state['input']['refresh_rows']) ? $form_state['input']['refresh_rows'] : NULL);
+
+  // Create the group rows and check actions.
+  foreach (array_keys($params->groups) as $name) {
+
+    // Play around with form_state so we only need to hold things
+    // between requests, until the save button was hit.
+    if (isset($form_state['field_group'][$name])) {
+      $group = & $form_state['field_group'][$name];
+    }
+    else {
+      $group = & $params->groups[$name];
+    }
+
+    // Check the currently selected formatter, and merge persisted values for
+    // formatter settings for the group.
+    // This needs to be done first, so all fields are updated before creating form elements.
+    if (isset($refresh_rows) && $refresh_rows == $name) {
+      $settings = isset($form_state['values']['fields'][$name]) ? $form_state['values']['fields'][$name] : (isset($form_state['input']['fields'][$name]) ? $form_state['input']['fields'][$name] : NULL);
+      if (array_key_exists('settings_edit', $settings)) {
+        //$group->format_type = $form_state['field_group'][$name]->format_type;
+        $group = $form_state['field_group'][$name];
+      }
+      field_group_formatter_row_update($group, $settings);
+    }
+
+    // Save the group when the configuration is submitted.
+    if (!empty($form_state['values'][$name . '_formatter_settings_update'])) {
+      field_group_formatter_settings_update($group, $form_state['values']['fields'][$name]);
+    }
+    // After all updates are finished, let the form_state know.
+    $form_state['field_group'][$name] = $group;
+
+    $settings = field_group_format_settings_form($group);
+
+    $id = strtr($name, '_', '-');
+    $js_rows_data[$id] = array('type' => 'group', 'name' => $name);
+    // A group cannot be selected as its own parent.
+    $parent_options = $table['#parent_options'];
+    unset($parent_options[$name]);
+    $table[$name] = array(
+      '#attributes' => array('class' => array('draggable', 'field-group'), 'id' => $id),
+      '#row_type' => 'group',
+      '#region_callback' => $params->region_callback,
+      '#js_settings' => array('rowHandler' => 'group'),
+      'human_name' => array(
+        '#markup' => check_plain(t($group->label)),
+        '#prefix' => '<span class="group-label">',
+        '#suffix' => '</span>',
+      ),
+      'weight' => array(
+        '#type' => 'textfield',
+        '#default_value' => $group->weight,
+        '#size' => 3,
+        '#attributes' => array('class' => array('field-weight')),
+      ),
+      'parent_wrapper' => array(
+        'parent' => array(
+          '#type' => 'select',
+          '#options' =>  $parent_options,
+          '#empty_value' => '',
+          '#default_value' => isset($params->parents[$name]) ? $params->parents[$name] : '',
+          '#attributes' => array('class' => array('field-parent')),
+          '#parents' => array('fields', $name, 'parent'),
+        ),
+        'hidden_name' => array(
+          '#type' => 'hidden',
+          '#default_value' => $name,
+          '#attributes' => array('class' => array('field-name')),
+        ),
+      ),
+    );
+
+    $table[$name] += array(
+      'group_name' => array(
+        '#markup' => check_plain($name),
+      ),
+      'format' => array(
+        'type' => array(
+          '#type' => 'select',
+          '#options' => $formatter_options,
+          '#default_value' => $group->format_type,
+          '#attributes' => array('class' => array('field-group-type')),
+        ),
+      ),
+    );
+
+    $base_button = array(
+      '#submit' => array('field_ui_display_overview_multistep_submit'),
+      '#ajax' => array(
+        'callback' => 'field_ui_display_overview_multistep_js',
+        'wrapper' => 'field-display-overview-wrapper',
+        'effect' => 'fade',
+      ),
+      '#field_name' => $name,
+    );
+
+    if ($form_state['formatter_settings_edit'] == $name) {
+      $table[$name]['format']['#cell_attributes'] = array('colspan' => $display_overview ? 3 : 3);
+      $table[$name]['format']['format_settings'] = array(
+        '#type' => 'container',
+        '#attributes' => array('class' => array('field-formatter-settings-edit-form')),
+        '#parents' => array('fields', $name, 'format_settings'),
+        '#weight' => -5,
+        'label' => array(
+          '#markup' => t('Field group format:') . ' <span class="formatter-name">' . $group->format_type . '</span>',
+        ),
+        // Create a settings form where hooks can pick in.
+        'settings' => $settings,
+        'actions' => array(
+          '#type' => 'actions',
+          'save_settings' => $base_button + array(
+            '#type' => 'submit',
+            '#name' => $name . '_formatter_settings_update',
+            '#value' => t('Update'),
+            '#op' => 'update',
+          ),
+          'cancel_settings' => $base_button + array(
+            '#type' => 'submit',
+            '#name' => $name . '_formatter_settings_cancel',
+            '#value' => t('Cancel'),
+            '#op' => 'cancel',
+            // Do not check errors for the 'Cancel' button.
+            '#limit_validation_errors' => array(),
+          ),
+        ),
+      );
+      $table[$name]['#attributes']['class'][] = 'field-formatter-settings-editing';
+      $table[$name]['format']['type']['#attributes']['class'] = array('element-invisible');
+    }
+    else {
+      // After saving, the settings are updated here aswell. First we create
+      // the element for the table cell.
+      $table[$name]['settings_summary'] = array('#markup' => '');
+      if (!empty($group->format_settings)) {
+        $table[$name]['settings_summary'] = field_group_format_settings_summary($name, $group);
+      }
+      // Add the configure button.
+      $table[$name]['settings_edit'] = $base_button + array(
+        '#type' => 'image_button',
+        '#name' => $name . '_group_settings_edit',
+        '#src' => 'misc/configure.png',
+        '#attributes' => array('class' => array('field-formatter-settings-edit'), 'alt' => t('Edit')),
+        '#op' => 'edit',
+        // Do not check errors for the 'Edit' button.
+        '#limit_validation_errors' => array(),
+        '#prefix' => '<div class="field-formatter-settings-edit-wrapper">',
+        '#suffix' => '</div>',
+      );
+      if ($display_overview) {
+        $table[$name]['settings_edit']['#suffix'] .= l(t('delete'), $params->admin_path . '/groups/' . $name . '/delete/' . $params->mode);
+      }
+    }
+
+    if (!$display_overview) {
+      $table[$name] += array(
+        'delete' => array(
+          '#markup' => l(t('delete'), $params->admin_path . '/groups/' . $name . '/delete/form'),
+        ),
+      );
+    }
+  }
+
+  // Additional row: add new group.
+  $parent_options = $table['#parent_options'];
+  unset($parent_options['_add_new_group']);
+  $table['_add_new_group'] = field_group_add_row('_add_new_group', $parent_options, $params);
+
+  $table['_add_new_group'] += array(
+    'format' => array(
+      'type' => array(
+        '#type' => 'select',
+        '#options' => $formatter_options,
+        '#default_value' => 'fieldset',
+        '#prefix' => '<div class="add-new-placeholder">&nbsp;</div>',
+      ),
+      '#cell_attributes' => array('colspan' => 3),
+    ),
+  );
+
+  if (!$display_overview) {
+    // See field_ui.admin.inc for more details on refresh rows.
+    $form['refresh_rows'] = array('#type' => 'hidden');
+    $form['refresh'] = array(
+      '#type' => 'submit',
+      '#value' => t('Refresh'),
+      '#op' => 'refresh_table',
+      '#submit' => array('field_ui_display_overview_multistep_submit'),
+      '#ajax' => array(
+        'callback' => 'field_ui_display_overview_multistep_js',
+        'wrapper' => 'field-display-overview-wrapper',
+        'effect' => 'fade',
+        // The button stays hidden, so we hide the AJAX spinner too. Ad-hoc
+        // spinners will be added manually by the client-side script.
+        'progress' => 'none',
+      ),
+    );
+  }
+
+  $form['#attached']['css'][] = drupal_get_path('module', 'field_group') . '/field_group.field_ui.css';
+  $form['#attached']['js'][] = drupal_get_path('module', 'field_group') . '/field_group.field_ui.js';
+
+  $form['#validate'][] = 'field_group_field_overview_validate';
+  $form['#submit'][] = 'field_group_field_overview_submit';
+
+  // Create the settings for fieldgroup as vertical tabs (merged with DS).
+  field_group_field_ui_create_vertical_tabs($form, $form_state, $params);
+
+  // Show a warning if the user has not set up required containers
+  if ($form['#groups']) {
+
+    $parent_requirements = array(
+      'multipage' => array(
+        'parent' => 'multipage-group',
+        'message' => 'Each Multipage element needs to have a parent Multipage group element.',
+      ),
+      'htab' => array(
+        'parent' => 'htabs',
+        'message' => 'Each Horizontal tab element needs to have a parent Horizontal tabs group element.',
+      ),
+      'accordion-item' => array(
+        'parent' => 'accordion',
+        'message' => 'Each Accordion item element needs to have a parent Accordion group element.',
+      ),
+    );
+
+    // On display overview tabs need to be checked.
+    if ($display_overview) {
+      $parent_requirements['tab'] = array(
+        'parent' => 'tabs',
+        'message' => 'Each Vertical tab element needs to have a parent Vertical tabs group element.',
+      );
+    }
+
+    foreach ($form['#groups'] as $group_name) {
+      $group_check = field_group_load_field_group($group_name, $params->entity_type, $params->bundle, $params->mode);
+      if (isset($parent_requirements[$group_check->format_type])) {
+        if (!$group_check->parent_name || field_group_load_field_group($group_check->parent_name, $params->entity_type, $params->bundle, $params->mode)->format_type != $parent_requirements[$group_check->format_type]['parent']) {
+          drupal_set_message(t($parent_requirements[$group_check->format_type]['message']), 'warning', FALSE);
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Return an array of field_group_formatter options.
+ */
+function field_group_field_formatter_options($type) {
+  $options = &drupal_static(__FUNCTION__);
+
+  if (!isset($options)) {
+    $options = array();
+    $field_group_types = field_group_formatter_info();
+    foreach ($field_group_types[$type] as $name => $field_group_type) {
+      $options[$name] = $field_group_type['label'];
+    }
+  }
+  return $options;
+}
+
+/**
+ * Helper function to add a row in the overview forms.
+ */
+function field_group_add_row($name, $parent_options, $params) {
+  return array(
+    '#attributes' => array('class' => array('draggable', 'field-group', 'add-new')),
+    '#row_type' => 'add_new_group',
+    '#js_settings' => array('rowHandler' => 'group'),
+    '#region_callback' => $params->region_callback,
+    'label' => array(
+      '#title_display' => 'invisible',
+      '#title' => t('Label for new group'),
+      '#type' => 'textfield',
+      '#size' => 15,
+      '#description' => t('Label'),
+      '#prefix' => '<div class="label-input"><div class="add-new-placeholder">' . t('Add new group') . '</div>',
+      '#suffix' => '</div>',
+    ),
+    'weight' => array(
+      '#type' => 'textfield',
+      '#default_value' => field_info_max_weight($params->entity_type, $params->bundle, $params->mode) + 3,
+      '#size' => 3,
+      '#title_display' => 'invisible',
+      '#title' => t('Weight for new group'),
+      '#attributes' => array('class' => array('field-weight')),
+      '#prefix' => '<div class="add-new-placeholder">&nbsp;</div>',
+    ),
+    'parent_wrapper' => array(
+      'parent' => array(
+        '#title_display' => 'invisible',
+        '#title' => t('Parent for new group'),
+        '#type' => 'select',
+        '#options' => $parent_options,
+        '#empty_value' => '',
+        '#attributes' => array('class' => array('field-parent')),
+        '#prefix' => '<div class="add-new-placeholder">&nbsp;</div>',
+        '#parents' => array('fields', $name, 'parent'),
+      ),
+      'hidden_name' => array(
+        '#type' => 'hidden',
+        '#default_value' => $name,
+        '#attributes' => array('class' => array('field-name')),
+      ),
+    ),
+    'group_name' => array(
+      '#type' => 'textfield',
+      '#title_display' => 'invisible',
+      '#title' => t('Machine name for new group'),
+      // This field should stay LTR even for RTL languages.
+      '#field_prefix' => '<span dir="ltr">group_',
+      '#field_suffix' => '</span>&lrm;',
+      '#attributes' => array('dir' => 'ltr'),
+      '#size' => 15,
+      '#description' => t('Group name (a-z, 0-9, _)'),
+      '#prefix' => '<div class="add-new-placeholder">&nbsp;</div>',
+      '#cell_attributes' => array('colspan' => $params->display_overview ? 1 : 2),
+    ),
+  );
+}
+
+/**
+ * Creates a form for field_group formatters.
+ * @param Object $group The FieldGroup object.
+ */
+function field_group_format_settings_form(&$group) {
+  $form = array();
+  $form['label'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Field group label'),
+    '#default_value' => $group->label,
+    '#weight' => -5,
+    '#element_validate' => array('field_group_format_settings_label_validate'),
+  );
+  $form += module_invoke_all('field_group_format_settings', $group);
+  $form['#validate'] = array('field_group_format_settings_form_validate');
+  return $form;
+}
+
+/**
+ * Validate the label. Label is required for fieldsets that are collapsible.
+ */
+function field_group_format_settings_label_validate($element, &$form_state) {
+
+  $group = $form_state['values']['fields'][$element['#parents'][1]];
+  $settings = $group['format_settings']['settings'];
+  $name = $form_state['formatter_settings_edit'];
+  $form_state['values']['fields'][$name]['settings_edit_form']['settings'] = $settings;
+  if ($group['format']['type'] == 'fieldset' && ($settings['formatter'] == 'collapsed' || $settings['formatter'] == 'collapsible') && empty($settings['label'])) {
+    form_error($element, t('The label is required when formatter is collapsible or collapsed'));
+  }
+
+}
+
+/**
+ * Update the row so that the group variables are updated.
+ * The rendering of the elements needs the updated defaults.
+ * @param Object $group
+ * @param array $settings
+ */
+function field_group_formatter_row_update(& $group, $settings) {
+  // if the row has changed formatter type, update the group object
+  if (!empty($settings['format']['type']) && $settings['format']['type'] != $group->format_type) {
+    $group->format_type = $settings['format']['type'];
+    field_group_formatter_settings_update($group, $settings);
+  }
+}
+
+/**
+ * Update handler for field_group configuration settings.
+ * @param Object $group The group object
+ * @param Array $settings Configuration settings
+ */
+function field_group_formatter_settings_update(& $group, $settings) {
+
+  // for format changes we load the defaults.
+  if (empty($settings['format_settings']['settings'])) {
+    $mode = $group->mode == 'form' ? 'form' : 'display';
+    $group->format_settings = _field_group_get_default_formatter_settings($group->format_type, $mode);
+  }
+  else {
+    $group->format_type = $settings['format']['type'];
+    $group->label = $settings['format_settings']['settings']['label'];
+    $group->format_settings = $settings['format_settings']['settings'];
+  }
+}
+
+/**
+ * Creates a summary for the field format configuration summary.
+ * @param String $group_name The name of the group
+ * @param Object $group The group object
+ * @return Array ready to be rendered.
+ */
+function field_group_format_settings_summary($group_name, $group) {
+  $summary = implode('<br />', module_invoke_all('field_group_format_summary', $group));
+  return array(
+    '#markup' => '<div class="field-formatter-summary">' . $summary . '</div>',
+    '#cell_attributes' => array('class' => array('field-formatter-summary-cell')),
+  );
+}
+
+/**
+ * Returns the region to which a row in the 'Manage fields' screen belongs.
+ * @param Array $row A field or field_group row
+ * @return String the current region.
+ */
+function field_group_field_overview_row_region($row) {
+  switch ($row['#row_type']) {
+    case 'group':
+      return 'main';
+    case 'add_new_group':
+      // If no input in 'label', assume the row has not been dragged out of the
+      // 'add new' section.
+      if (empty($row['label']['#value'])) {
+        return 'add_new';
+      }
+      return 'main';
+  }
+}
+
+/**
+ * Returns the region to which a row in the 'Manage display' screen belongs.
+ * @param Array $row A field or field_group row
+ * @return String the current region.
+ */
+function field_group_display_overview_row_region($row) {
+  switch ($row['#row_type']) {
+    case 'group':
+      return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'visible');
+    case 'add_new_group':
+      // If no input in 'label', assume the row has not been dragged out of the
+      // 'add new' section.
+      if (empty($row['label']['#value'])) {
+        return 'add_new';
+      }
+      return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'visible');
+  }
+}
+
+/**
+ * Validate handler for the overview screens.
+ * @param Array $form The complete form.
+ * @param Array $form_state The state of the form.
+ */
+function field_group_field_overview_validate($form, &$form_state) {
+  $form_values = $form_state['values']['fields'];
+  $entity_type = $form['#entity_type'];
+  $bundle = $form['#bundle'];
+  $mode = (isset($form['#view_mode']) ? $form['#view_mode'] : 'form');
+
+  $group = $form_values['_add_new_group'];
+
+  // Validate if any information was provided in the 'add new group' row.
+  if (array_filter(array($group['label'], $group['group_name']))) {
+
+    // Missing group name.
+    if (!$group['group_name']) {
+      form_set_error('fields][_add_new_group][group_name', t('Add new group: you need to provide a group name.'));
+    }
+    // Group name validation.
+    else {
+      $group_name = $group['group_name'];
+
+      // Add the 'group_' prefix.
+      if (drupal_substr($group_name, 0, 6) != 'group_') {
+        $group_name = 'group_' . $group_name;
+        form_set_value($form['fields']['_add_new_group']['group_name'], $group_name, $form_state);
+      }
+
+      // Invalid group name.
+      if (!preg_match('!^group_[a-z0-9_]+$!', $group_name)) {
+        form_set_error('fields][_add_new_group][group_name', t('Add new group: the group name %group_name is invalid. The name must include only lowercase unaccentuated letters, numbers, and underscores.', array('%group_name' => $group_name)));
+      }
+      if (drupal_strlen($group_name) > 32) {
+        form_set_error('fields][_add_new_group][group_name', t("Add new group: the group name %group_name is too long. The name is limited to 32 characters, including the 'group_' prefix.", array('%group_name' => $group_name)));
+      }
+
+      // Group name already exists.
+      if (field_group_exists($group_name, $entity_type, $bundle, $mode)) {
+        form_set_error('fields][_add_new_group][group_name', t('Add new group: the group name %group_name already exists.', array('%group_name' => $group_name)));
+      }
+    }
+  }
+}
+
+/**
+ * Submit handler for the overview screens.
+ * @param Array $form The complete form.
+ * @param Array $form_state The state of the form.
+ */
+function field_group_field_overview_submit($form, &$form_state) {
+
+  $form_values = $form_state['values']['fields'];
+  $entity_type = $form['#entity_type'];
+  $bundle = $form['#bundle'];
+  $mode = (isset($form['#view_mode']) ? $form['#view_mode'] : 'form');
+
+  // Collect children.
+  $children = array_fill_keys($form['#groups'], array());
+  foreach ($form_values as $name => $value) {
+    if (!empty($value['parent'])) {
+      // Substitute newly added fields, in case they were dragged
+      // directly in a group.
+      if ($name == '_add_new_field' && isset($form_state['fields_added']['_add_new_field'])) {
+        $name = $form_state['fields_added']['_add_new_field'];
+      }
+      elseif ($name == '_add_existing_field' && isset($form_state['fields_added']['_add_existing_field'])) {
+        $name = $form_state['fields_added']['_add_existing_field'];
+      }
+      $children[$value['parent']][$name] = $name;
+    }
+  }
+
+  // Prepare storage with ctools.
+  ctools_include('export');
+
+  // Create new group.
+  if (!empty($form_values['_add_new_group']['group_name'])) {
+    $values = $form_values['_add_new_group'];
+
+    $field_group_types = field_group_formatter_info();
+    $formatter = $field_group_types[($mode == 'form' ? 'form' : 'display')][$values['format']['type']];
+
+    $new_group = (object) array(
+      'identifier' => $values['group_name'] . '|' . $entity_type . '|' . $bundle . '|' . $mode,
+      'group_name' => $values['group_name'],
+      'entity_type' => $entity_type,
+      'bundle' => $bundle,
+      'mode' => $mode,
+      'children' => isset($children['_add_new_group']) ? array_keys($children['_add_new_group']) : array(),
+      'parent_name' => $values['parent'],
+      'weight' => $values['weight'],
+      'label' => $values['label'],
+      'format_type' => $values['format']['type'],
+      'disabled' => FALSE,
+    );
+    $new_group->format_settings = array('formatter' => isset($formatter['default_formatter']) ? $formatter['default_formatter'] : '');
+    if (isset($formatter['instance_settings'])) {
+      $new_group->format_settings['instance_settings'] = $formatter['instance_settings'];
+    }
+
+    $classes = _field_group_get_html_classes($new_group);
+    $new_group->format_settings['instance_settings']['classes'] = implode(' ', $classes->optional);
+
+    // Save and enable it in ctools.
+    ctools_export_crud_save('field_group', $new_group);
+    ctools_export_crud_enable('field_group', $new_group->identifier);
+
+    // Store new group information for any additional submit handlers.
+    $form_state['groups_added']['_add_new_group'] = $new_group->group_name;
+    drupal_set_message(t('New group %label successfully created.', array('%label' => $new_group->label)));
+
+    // Replace the newly created group in the $children array, in case it was
+    // dragged directly in an existing field.
+    foreach (array_keys($children) as $parent) {
+      if (isset($children[$parent]['_add_new_group'])) {
+        unset($children[$parent]['_add_new_group']);
+        $children[$parent][$new_group->group_name] = $new_group->group_name;
+      }
+    }
+  }
+
+  // Update existing groups.
+  $groups = field_group_info_groups($entity_type, $bundle, $mode, TRUE);
+  foreach ($form['#groups'] as $group_name) {
+    $group = $groups[$group_name];
+    $group->label = $form_state['field_group'][$group_name]->label;
+    $group->children = array_keys($children[$group_name]);
+    $group->parent_name = $form_values[$group_name]['parent'];
+    $group->weight = $form_values[$group_name]['weight'];
+
+    $old_format_type = $group->format_type;
+    $group->format_type = isset($form_values[$group_name]['format']['type']) ? $form_values[$group_name]['format']['type'] : 'visible';
+    if (isset($form_state['field_group'][$group_name]->format_settings)) {
+      $group->format_settings = $form_state['field_group'][$group_name]->format_settings;
+    }
+
+    // If the format type is changed, make sure we have all required format settings.
+    if ($group->format_type != $old_format_type) {
+      $mode = $group->mode == 'form' ? 'form' : 'display';
+      $default_formatter_settings = _field_group_get_default_formatter_settings($group->format_type, $mode);
+      $group->format_settings += $default_formatter_settings;
+      $group->format_settings['instance_settings'] += $default_formatter_settings['instance_settings'];
+    }
+
+    ctools_export_crud_save('field_group', $group);
+  }
+
+  cache_clear_all('field_groups', 'cache_field');
+}
+
+/**
+ * Validate the entered css class from the submitted format settings.
+ * @param Array $element The validated element
+ * @param Array $form_state The state of the form.
+ */
+function field_group_validate_css_class($element, &$form_state) {
+  if (!empty($form_state['values']['fields'][$form_state['formatter_settings_edit']]['format_settings']['settings']['instance_settings']['classes']) && !preg_match('!^[A-Za-z0-9-_ ]+$!', $form_state['values']['fields'][$form_state['formatter_settings_edit']]['format_settings']['settings']['instance_settings']['classes'])) {
+    form_error($element, t('The css class must include only letters, numbers, underscores and dashes.'));
+  }
+}
+
+/**
+ * Validate the entered id attribute from the submitted format settings.
+ * @param Array $element The validated element
+ * @param Array $form_state The state of the form.
+ */
+function field_group_validate_id($element, &$form_state) {
+  if (!empty($form_state['values']['fields'][$form_state['formatter_settings_edit']]['format_settings']['settings']['instance_settings']['id']) && !preg_match('!^[A-Za-z0-9-_]+$!', $form_state['values']['fields'][$form_state['formatter_settings_edit']]['format_settings']['settings']['instance_settings']['id'])) {
+    form_error($element, t('The id must include only letters, numbers, underscores and dashes.'));
+  }
+}
+
+/**
+ * Implements hook_field_info_max_weight().
+ */
+function field_group_field_info_max_weight($entity_type, $bundle, $context) {
+  $weights = array();
+  foreach (field_group_info_groups($entity_type, $bundle, $context) as $group) {
+    $weights[] = $group->weight;
+  }
+  return $weights ? max($weights) : NULL;
+}
+
+/**
+ * Menu callback; present a form for removing a group.
+ */
+function field_group_delete_form($form, &$form_state, $group, $view_mode = 'form') {
+
+  $form['#group'] = $group;
+  $admin_path = _field_ui_bundle_admin_path($group->entity_type, $group->bundle);
+  if ($view_mode == 'form') {
+    $admin_path .= '/fields';
+  }
+  else {
+    $admin_path .= '/display/' . $view_mode;
+  }
+  $form['#redirect'] = array($admin_path);
+  $output = confirm_form($form,
+    t('Are you sure you want to delete the group %group?', array('%group' => t($group->label))),
+    $admin_path,
+    t('This action cannot be undone.'),
+    t('Delete'), t('Cancel'),
+    'confirm'
+  );
+  return $output;
+}
+
+/**
+ * Remove group from bundle.
+ *
+ * @todo we'll have to reset all view mode settings - that will be fun :)
+ */
+function field_group_delete_form_submit($form, &$form_state) {
+
+  $group = $form['#group'];
+  $bundle = $group->bundle;
+  $entity_type = $group->entity_type;
+  $group->mode = $form_state['build_info']['args'][1];
+
+  $bundles = field_info_bundles();
+  $bundle_label = $bundles[$entity_type][$bundle]['label'];
+
+  ctools_include('export');
+  field_group_group_export_delete($group, FALSE);
+
+  drupal_set_message(t('The group %group has been deleted from the %type content type.', array('%group' => t($group->label), '%type' => $bundle_label)));
+
+  // Redirect.
+  $form_state['redirect'] = $form['#redirect'];
+}
+
+/**
+ * Menu callback; present a form for re-enabling a group.
+ */
+function field_group_enable_form($form, &$form_state, $group, $view_mode = 'form') {
+
+  $form['#group'] = $group;
+  $admin_path = _field_ui_bundle_admin_path($group->entity_type, $group->bundle);
+  if ($view_mode == 'form') {
+    $admin_path .= '/fields';
+  }
+  else {
+    $admin_path .= '/display/' . $view_mode;
+  }
+  $form['#redirect'] = array($admin_path);
+  $output = confirm_form($form,
+    t('Are you sure you want to enable the group %group?', array('%group' => t($group->label))),
+    $admin_path,
+    '',
+    t('Enable'), t('Cancel'),
+    'confirm'
+  );
+  return $output;
+}
+
+/**
+ * Re-enable the group on a bundle.
+ */
+function field_group_enable_form_submit($form, &$form_state) {
+
+  $group = $form['#group'];
+  $bundle = $group->bundle;
+  $entity_type = $group->entity_type;
+  $group->mode = $form_state['build_info']['args'][1];
+
+  $bundles = field_info_bundles();
+  $bundle_label = $bundles[$entity_type][$bundle]['label'];
+
+  ctools_include('export');
+  ctools_export_crud_enable('field_group', $group->identifier);
+
+  drupal_set_message(t('The group %group has been enabled on the %type content type.', array('%group' => t($group->label), '%type' => $bundle_label)));
+
+  // Redirect.
+  $form_state['redirect'] = $form['#redirect'];
+}
+
+/**
+ * Create vertical tabs.
+ */
+function field_group_field_ui_create_vertical_tabs(&$form, &$form_state, $params) {
+
+  $form_state['field_group_params'] = $params;
+
+  $entity_info = entity_get_info($params->entity_type);
+  $view_modes = array();
+  if ($params->mode != 'default') {
+    $view_modes['default'] = t('Default');
+  }
+  if ($params->mode != 'form') {
+    $view_modes['0'] = t('Form');
+  }
+  foreach ($entity_info['view modes'] as $view_mode => $data) {
+    if ($data['custom settings'] && $params->mode != $view_mode) {
+      $view_modes[$view_mode] = $data['label'];
+    }
+  }
+
+  // Add additional settings vertical tab.
+  if (!isset($form['additional_settings'])) {
+    $form['additional_settings'] = array(
+      '#type' => 'vertical_tabs',
+      '#theme_wrappers' => array('vertical_tabs'),
+      '#prefix' => '<div>',
+      '#suffix' => '</div>',
+      '#tree' => TRUE,
+    );
+    $form['#attached']['js'][] = 'misc/form.js';
+    $form['#attached']['js'][] = 'misc/collapse.js';
+  }
+
+  // Add extra guidelines for webmaster.
+  $form['additional_settings']['field_group'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Fieldgroups'),
+    '#description' => t('<p class="fieldgroup-help">Fields can be dragged into groups with unlimited nesting. Each fieldgroup format comes with a configuration form, specific for that format type.<br />Note that some formats come in pair. These types have a html wrapper to nest its fieldgroup children. E.g. Place accordion items into the accordion, vertical tabs in vertical tab group and horizontal tabs in the horizontal tab group. There is one exception to this rule, you can use a vertical tab without a wrapper when the additional settings tabs are available. E.g. node forms.</p>'),
+    '#collapsible' => TRUE,
+    '#collapsed' => FALSE,
+    '#parents' => array('additional_settings'),
+  );
+  $form['additional_settings']['field_group']['fieldgroup_clone'] = array(
+    '#title' => t('Select source view mode or form'),
+    '#description' => t('Clone fieldgroups from selected view mode to the current display'),
+    '#type' => 'select',
+    '#options' => $view_modes,
+    '#default_value' => 'none'
+  );
+  $form['additional_settings']['field_group']['fieldgroup_submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Clone'),
+    '#validate' => array('field_group_field_ui_clone_field_groups_validate'),
+    '#submit' => array('field_group_field_ui_clone_field_groups')
+  );
+
+  $disabled_groups = field_group_read_groups(array(), FALSE);
+
+  // Show disabled fieldgroups, and make it possible to enable them again.
+  if ($disabled_groups && isset($disabled_groups[$params->entity_type][$params->bundle][$params->mode])) {
+    $form['additional_settings']['disabled_field_groups'] = array(
+
+      '#type' => 'fieldset',
+
+      '#title' => t('Disabled fieldgroups'),
+
+      '#collapsible' => TRUE,
+
+      '#collapsed' => FALSE,
+
+      '#parents' => array('additional_settings'),
+
+    );
+    $form['additional_settings']['disabled_field_groups']['overview'] = field_group_disabled_groups_overview($disabled_groups[$params->entity_type][$params->bundle][$params->mode], $entity_info, $params);
+  }
+
+}
+
+/**
+ * Validate handler to validate saving existing fieldgroups from one view mode or form to another.
+ */
+function field_group_field_ui_clone_field_groups_validate($form, &$form_state) {
+
+  $source_mode = $form_state['#source_mode'] = $form_state['values']['additional_settings']['fieldgroup_clone'] == '0' ? 'form' : $form_state['values']['additional_settings']['fieldgroup_clone'];
+  $groups_to_clone = $form_state['#groups_to_clone'] = field_group_read_groups(array('bundle' => $form_state['field_group_params']->bundle, 'entity_type' => $form_state['field_group_params']->entity_type));
+
+  $form_state['#source_groups'] = array();
+  if (!empty($groups_to_clone) && isset($groups_to_clone[$form_state['field_group_params']->entity_type], $groups_to_clone[$form_state['field_group_params']->entity_type][$form_state['field_group_params']->bundle], $groups_to_clone[$form_state['field_group_params']->entity_type][$form_state['field_group_params']->bundle][$source_mode])) {
+    $form_state['#source_groups'] = $groups_to_clone[$form_state['field_group_params']->entity_type][$form_state['field_group_params']->bundle][$source_mode];
+  }
+
+  // Check for types are not known in current mode.
+  if ($form_state['field_group_params']->mode != 'form') {
+    $non_existing_types = array('multipage', 'multipage-group');
+  }
+  else {
+    $non_existing_types = array('div');
+  }
+
+  foreach ($form_state['#source_groups'] as $key => $group) {
+    if (in_array($group->format_type, $non_existing_types)) {
+      unset($form_state['#source_groups'][$key]);
+      drupal_set_message(t('Skipping @group because this type does not exist in current mode', array('@group' => $group->label)), 'warning');
+    }
+  }
+
+  if (empty($form_state['#source_groups'])) {
+    // Report error found with selection.
+    form_set_error('additional_settings][fieldgroup_clone', t('No field groups were found in selected view mode.'));
+    return;
+  }
+
+}
+
+/**
+ * Submit handler to save existing fieldgroups from one view mode or form to another.
+ */
+function field_group_field_ui_clone_field_groups($form, &$form_state) {
+
+  $source_mode = $form_state['#source_mode'];
+  $groups_to_clone = $form_state['#groups_to_clone'];
+
+  $fields = array_keys($form_state['values']['fields']);
+  if (!empty($form_state['#source_groups'])) {
+
+    foreach ($form_state['#source_groups'] as $source_group) {
+      if (in_array($source_group->group_name, $fields)) {
+        drupal_set_message(t('Fieldgroup @group is not cloned since a group already exists with the same name.', array('@group' => $source_group->group_name)), 'warning');
+        continue;
+      }
+
+      // Recreate the identifier and reset the id.
+      $source_group->id = NULL;
+      $source_group->mode = $form_state['field_group_params']->mode;
+      $source_group->identifier = $source_group->group_name . '|' . $source_group->entity_type . '|' . $source_group->bundle . '|' . $form_state['field_group_params']->mode;
+      $source_group->disabled = FALSE;
+      $source_group->children = array();
+      unset($source_group->export_type, $source_group->type, $source_group->table);
+
+      // Save and enable it in ctools.
+      ctools_include('export');
+      ctools_export_crud_save('field_group', $source_group);
+      ctools_export_crud_enable('field_group', $source_group->identifier);
+
+      drupal_set_message(t('Fieldgroup @group cloned successfully.', array('@group' => $source_group->group_name)));
+
+    }
+  }
+
+}
+
+/**
+ * Show an overview of all the disabled fieldgroups, and make it possible to activate them again.
+ * @param $disabled_groups Array with all disabled groups.
+ */
+function field_group_disabled_groups_overview($disabled_groups, $entity_info, $params) {
+
+  $formatter_options = field_group_field_formatter_options($params->mode != 'form' ? 'display' : 'form');
+
+  $table = array(
+    '#theme' => 'table',
+    '#header' => array(
+      t('Label'),
+      t('Machine name'),
+      t('Field'),
+      t('Widget'),
+      t('Operations'),
+    ),
+    '#attributes' => array(
+      'class' => array('field-ui-overview'),
+    ),
+    '#rows' => array(),
+  );
+
+  // Add all of the disabled groups as a row on the table.
+  foreach ($disabled_groups as $group) {
+
+    $summary = field_group_format_settings_summary($group->group_name, $group);
+
+    $row = array();
+    $row[] = $group->label;
+    $row[] = $group->group_name;
+    $row[] = $formatter_options[$group->format_type];
+    $row[] = render($summary);
+    $path = (isset($entity_info['bundles'][$params->bundle]['admin']['real path']) ? $entity_info['bundles'][$params->bundle]['admin']['real path'] : $entity_info['bundles'][$params->bundle]['admin']['path']);
+    $row[] = l(t('Enable'), $path . '/groups/' . $group->group_name . '/enable/' . $group->mode);
+
+    $table['#rows'][] = $row;
+  }
+
+  return $table;
+
+}
+/**
+ * eof().
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.field_ui.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,137 @@
+
+(function($) {
+
+Drupal.behaviors.fieldUIFieldsOverview = {
+  attach: function (context, settings) {
+    $('table#field-overview', context).once('field-field-overview', function() {
+      Drupal.fieldUIOverview.attach(this, settings.fieldUIRowsData, Drupal.fieldUIFieldOverview);
+    });
+  }
+};
+  
+/**
+ * Row handlers for the 'Manage fields' screen.
+ */
+Drupal.fieldUIFieldOverview = Drupal.fieldUIFieldOverview || {};
+
+Drupal.fieldUIFieldOverview.group = function(row, data) {
+  this.row = row;
+  this.name = data.name;
+  this.region = data.region;
+  this.tableDrag = data.tableDrag;
+
+  // Attach change listener to the 'group format' select.
+  this.$formatSelect = $('select.field-group-type', row);
+  this.$formatSelect.change(Drupal.fieldUIOverview.onChange);
+
+  return this;
+};
+
+Drupal.fieldUIFieldOverview.group.prototype = {
+  getRegion: function () {
+    return 'main';
+  },
+  
+  regionChange: function (region, recurse) {
+    return {};
+  },
+
+  regionChangeFields: function (region, element, refreshRows) {
+
+    // Create a new tabledrag rowObject, that will compute the group's child
+    // rows for us.
+    var tableDrag = element.tableDrag;
+    rowObject = new tableDrag.row(element.row, 'mouse', true);
+    // Skip the main row, we handled it above.
+    rowObject.group.shift();
+
+    // Let child rows handlers deal with the region change - without recursing
+    // on nested group rows, we are handling them all here.
+    $.each(rowObject.group, function() {
+      var childRow = this;
+      var childRowHandler = $(childRow).data('fieldUIRowHandler');
+      $.extend(refreshRows, childRowHandler.regionChange(region, false));
+    });
+  }  
+};
+  
+  
+/**
+ * Row handlers for the 'Manage display' screen.
+ */
+Drupal.fieldUIDisplayOverview = Drupal.fieldUIDisplayOverview || {};
+
+Drupal.fieldUIDisplayOverview.group = function(row, data) {
+  this.row = row;
+  this.name = data.name;
+  this.region = data.region;
+  this.tableDrag = data.tableDrag;
+
+  // Attach change listener to the 'group format' select.
+  this.$formatSelect = $('select.field-group-type', row);
+  this.$formatSelect.change(Drupal.fieldUIOverview.onChange);
+
+  return this;
+};
+
+Drupal.fieldUIDisplayOverview.group.prototype = {
+  getRegion: function () {
+    return (this.$formatSelect.val() == 'hidden') ? 'hidden' : 'visible';
+  },
+
+  regionChange: function (region, recurse) {
+
+    // Default recurse to true.
+    recurse = (recurse == undefined) || recurse;
+
+    // When triggered by a row drag, the 'format' select needs to be adjusted to
+    // the new region.
+    var currentValue = this.$formatSelect.val();
+    switch (region) {
+      case 'visible':
+        if (currentValue == 'hidden') {
+          // Restore the group format back to 'fieldset'.
+          var value = 'fieldset';
+        }
+        break;
+
+      default:
+        var value = 'hidden';
+        break;
+    }
+    if (value != undefined) {
+      this.$formatSelect.val(value);
+    }
+
+    var refreshRows = {};
+    refreshRows[this.name] = this.$formatSelect.get(0);
+
+    if (recurse) {
+      this.regionChangeFields(region, this, refreshRows);
+    }
+
+    return refreshRows;
+  },
+
+  regionChangeFields: function (region, element, refreshRows) {
+
+    // Create a new tabledrag rowObject, that will compute the group's child
+    // rows for us.
+    var tableDrag = element.tableDrag;
+    rowObject = new tableDrag.row(element.row, 'mouse', true);
+    // Skip the main row, we handled it above.
+    rowObject.group.shift();
+
+    // Let child rows handlers deal with the region change - without recursing
+    // on nested group rows, we are handling them all here.
+    $.each(rowObject.group, function() {
+      var childRow = this;
+      var childRowHandler = $(childRow).data('fieldUIRowHandler');
+      $.extend(refreshRows, childRowHandler.regionChange(region, false));
+    });
+    
+  }
+  
+};
+
+})(jQuery);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+name = Fieldgroup
+description = Fieldgroup
+package = Fields
+dependencies[] = field
+dependencies[] = ctools
+core = 7.x
+files[] = field_group.install
+files[] = field_group.module
+files[] = field_group.field_ui.inc
+files[] = field_group.form.inc
+files[] = field_group.features.inc
+files[] = field_group.test
+; Information added by drupal.org packaging script on 2013-08-29
+version = "7.x-1.2"
+core = "7.x"
+project = "field_group"
+datestamp = "1377806209"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,296 @@
+<?php
+
+/**
+ * @file
+ * Fieldgroup module install file.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function field_group_schema() {
+  $schema['field_group'] = array(
+    'description' => t('Table that contains field group entries and settings.'),
+
+    // CTools export definitions.
+    'export' => array(
+      'key' => 'identifier',
+      'identifier' => 'field_group',
+      'default hook' => 'field_group_info',
+      'save callback' => 'field_group_group_save',
+      'delete callback' => 'field_group_group_export_delete',
+      'can disable' => TRUE,
+      'api' => array(
+        'owner' => 'field_group',
+        'api' => 'field_group',
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+    ),
+
+    'fields' => array(
+      'id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'The primary identifier for a group',
+        'no export' => TRUE,
+      ),
+      'identifier' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The unique string identifier for a group.',
+      ),
+      'group_name' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The name of this group.',
+      ),
+      'entity_type' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'bundle' => array(
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => ''
+        ),
+      'mode' => array(
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      // @todo 'parent_name' is redundant with the data in the 'children'
+      // entry, brings a risk of inconsistent data. This should be removed from
+      // the schema and pre-computed it if needed in field_group_get_groups().
+      'parent_name' => array(
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The parent name for a group',
+      ),
+      'data' => array(
+        'type' => 'blob',
+        'size' => 'big',
+        'not null' => TRUE,
+        'serialize' => TRUE,
+        'description' => 'Serialized data containing the group properties that do not warrant a dedicated column.',
+      ),
+    ),
+    'primary key' => array('id'),
+    'indexes' => array(
+      'group_name' => array('group_name'),
+    ),
+    'unique keys' => array(
+      'identifier' => array('identifier'),
+    ),
+  );
+  return $schema;
+}
+
+/**
+ * Utility function: fetch all the field_group definitions from the database.
+ */
+function _field_group_install_read_groups() {
+  $groups = array();
+  if (db_table_exists('content_group')) {
+    $query = db_select('content_group', 'cg', array('fetch' => PDO::FETCH_ASSOC))
+      ->fields('cg')
+      // We only want non-multigroups.
+      ->condition('group_type', 'standard');
+    foreach ($query->execute() as $record) {
+      $record['settings'] = unserialize($record['settings']);
+      $groups[$record['group_name'] . '-' . $record['type_name']] = $record;
+    }
+    foreach ($groups as $key => $group) {
+      $query2 = db_select('content_group_fields', 'cgf', array('fetch' => PDO::FETCH_ASSOC))
+        ->fields('cgf')
+        ->condition('group_name', $group['group_name']);
+      foreach ($query2->execute() as $field) {
+        $groups[$field['group_name'] . '-' . $field['type_name']]['children'][] = $field;
+      }
+    }
+  }
+  return $groups;
+}
+
+/**
+ * Implements of hook_install().
+ *
+ * Because this is a new module in D7, hook_update_N() doesn't help D6
+ * users who upgrade to run the migration path. So, we try that here as
+ * the module is being installed.
+ */
+function field_group_install() {
+
+  $groups = _field_group_install_read_groups();
+  module_load_include('module', 'field_group');
+
+  if (!empty($groups)) {
+
+    module_load_include('module', 'ctools');
+    ctools_include('export');
+
+    foreach ($groups as $group) {
+
+      $group = (object) $group;
+
+      $new = new stdClass();
+      $new->group_name = $group->group_name;
+      $new->entity_type = 'node';
+      $new->bundle = $group->type_name;
+      $new->label = $group->label;
+      $new->parent_name = '';
+      $new->children = array();
+      foreach ($group->children as $child) {
+        $new->children[] = $child['field_name'];
+      }
+
+      // The form.
+      $new->id = NULL;
+      $new->weight = $group->weight;
+      $new->mode = 'form';
+      $new->format_type = 'fieldset';
+      $new->format_settings = array(
+        'formatter' => preg_match("/fieldset/", $group->settings['form']['style']) ? 'collapsible' : 'collapsed',
+        'instance_settings' => array(),
+      );
+      $new->identifier = $new->group_name . '|' . $new->entity_type . '|' . $new->bundle . '|' . $new->mode;
+      ctools_export_crud_save('field_group', $new);
+
+      // The full node.
+      $new->id = NULL;
+      $new->weight = $group->weight;
+      $new->mode = 'default';
+      $new->format_type = $group->settings['display']['full']['format'];
+      $new->format_settings = array(
+        'formatter' => 'collapsible',
+        'instance_settings' => array(),
+      );
+      $new->identifier = $new->group_name . '|' . $new->entity_type . '|' . $new->bundle . '|' . $new->mode;
+      ctools_export_crud_save('field_group', $new);
+
+      // The teaser node.
+      $new->id = NULL;
+      $new->weight = $group->weight;
+      $new->mode = 'teaser';
+      $new->format_type = $group->settings['display']['teaser']['format'];
+      $new->format_settings = array(
+        'formatter' => 'collapsible',
+        'instance_settings' => array(),
+      );
+      $new->identifier = $new->group_name . '|' . $new->entity_type . '|' . $new->bundle . '|' . $new->mode;
+      ctools_export_crud_save('field_group', $new);
+
+    }
+
+  }
+
+  // Set weight to 1.
+  db_update('system')
+    ->fields(array('weight' => 1))
+    ->condition('name', 'field_group')
+    ->execute();
+
+}
+
+/**
+ * Update hook on the field_group table to add an unique identifier.
+ */
+function field_group_update_7001() {
+
+  if (!db_field_exists('field_group', 'identifier')) {
+    // Add the new string identifier field for ctools.
+    db_add_field('field_group', 'identifier', array(
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => TRUE,
+      'default' => '',
+      'description' => 'The unique string identifier for a group.',
+    ));
+
+    module_load_include('module', 'field_group');
+    _field_group_recreate_identifiers();
+
+  }
+
+  db_update('system')
+    ->fields(array('weight' => 1))
+    ->condition('name', 'field_group')
+    ->execute();
+
+}
+
+/**
+ * Update hook to clear cache for new changes to take effect.
+ */
+function field_group_update_7002() {
+
+  module_load_include('module', 'field_group');
+
+  // This hook is called to satify people with older version of field_group.
+  // This will recreate all identifiers for the field_groups known in database.
+  // At the moment, we only trigger field_groups that are stored in the database, where
+  // we should maybe get all field_groups as ctools has registered them.
+  // See http://drupal.org/node/1169146.
+  // See http://drupal.org/node/1018550.
+  _field_group_recreate_identifiers();
+
+}
+
+/**
+ * Update hook to recreate identifiers.
+ * @see function field_group_update_7002.
+ */
+function field_group_update_7003() {
+
+  module_load_include('module', 'field_group');
+  _field_group_recreate_identifiers();
+
+}
+
+/**
+ * Update hook to make sure identifier is set as unique key.
+ */
+function field_group_update_7004() {
+  db_drop_unique_key('field_group', 'identifier');
+  db_add_unique_key('field_group', 'identifier', array('identifier'));
+}
+
+/**
+ * Checks all existing groups and removes optional HTML classes
+ * while adding them as extra classes.
+ */
+function field_group_update_7005() {
+
+  // Migrate the field groups so they have a unique identifier.
+  $result = db_select('field_group', 'fg')
+    ->fields('fg')
+    ->execute();
+  $rows = array();
+  foreach($result as $row) {
+    //$row->identifier = $row->group_name . '|' . $row->entity_type . '|' . $row->bundle . '|' . $row->mode;
+    $row->data = unserialize($row->data);
+    $classes = explode(" ", $row->data['format_settings']['instance_settings']['classes']);
+    $optional_classes = array(str_replace("_", "-", $row->group_name), 'field-group-' . $row->data['format_type']);
+    foreach ($optional_classes as $optional_class) {
+      if (!in_array($optional_class, $classes)) {
+        $classes[] = $optional_class;
+      }
+    }
+    $row->data['format_settings']['instance_settings']['classes'] = implode(" ", $classes);
+    $rows[] = $row;
+  }
+  foreach ($rows as $row) {
+    drupal_write_record('field_group', $row, array('id'));
+  }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,224 @@
+
+(function($) {
+
+/**
+ * Drupal FieldGroup object.
+ */
+Drupal.FieldGroup = Drupal.FieldGroup || {};
+Drupal.FieldGroup.Effects = Drupal.FieldGroup.Effects || {};
+Drupal.FieldGroup.groupWithfocus = null;
+
+Drupal.FieldGroup.setGroupWithfocus = function(element) {
+  element.css({display: 'block'});
+  Drupal.FieldGroup.groupWithfocus = element;
+}
+
+/**
+ * Implements Drupal.FieldGroup.processHook().
+ */
+Drupal.FieldGroup.Effects.processFieldset = {
+  execute: function (context, settings, type) {
+    if (type == 'form') {
+      // Add required fields mark to any fieldsets containing required fields
+      $('fieldset.fieldset', context).once('fieldgroup-effects', function(i) {
+        if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
+          $('legend span.fieldset-legend', $(this)).eq(0).append(' ').append($('.form-required').eq(0).clone());
+        }
+        if ($('.error', $(this)).length) {
+          $('legend span.fieldset-legend', $(this)).eq(0).addClass('error');
+          Drupal.FieldGroup.setGroupWithfocus($(this));
+        }
+      });
+    }
+  }
+}
+
+/**
+ * Implements Drupal.FieldGroup.processHook().
+ */
+Drupal.FieldGroup.Effects.processAccordion = {
+  execute: function (context, settings, type) {
+    $('div.field-group-accordion-wrapper', context).once('fieldgroup-effects', function () {
+      var wrapper = $(this);
+
+      wrapper.accordion({
+        autoHeight: false,
+        active: '.field-group-accordion-active',
+        collapsible: true,
+        changestart: function(event, ui) {
+          if ($(this).hasClass('effect-none')) {
+            ui.options.animated = false;
+          }
+          else {
+            ui.options.animated = 'slide';
+          }
+        }
+      });
+
+      if (type == 'form') {
+
+        var $firstErrorItem = false;
+
+        // Add required fields mark to any element containing required fields
+        wrapper.find('div.field-group-accordion-item').each(function(i) {
+
+          if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
+            $('h3.ui-accordion-header a').eq(i).append(' ').append($('.form-required').eq(0).clone());
+          }
+          if ($('.error', $(this)).length) {
+            // Save first error item, for focussing it.
+            if (!$firstErrorItem) {
+              $firstErrorItem = $(this).parent().accordion("activate" , i);
+            }
+            $('h3.ui-accordion-header').eq(i).addClass('error');
+          }
+        });
+
+        // Save first error item, for focussing it.
+        if (!$firstErrorItem) {
+          $('.ui-accordion-content-active', $firstErrorItem).css({height: 'auto', width: 'auto', display: 'block'});
+        }
+
+      }
+    });
+  }
+}
+
+/**
+ * Implements Drupal.FieldGroup.processHook().
+ */
+Drupal.FieldGroup.Effects.processHtabs = {
+  execute: function (context, settings, type) {
+    if (type == 'form') {
+      // Add required fields mark to any element containing required fields
+      $('fieldset.horizontal-tabs-pane', context).once('fieldgroup-effects', function(i) {
+        if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
+          $(this).data('horizontalTab').link.find('strong:first').after($('.form-required').eq(0).clone()).after(' ');
+        }
+        if ($('.error', $(this)).length) {
+          $(this).data('horizontalTab').link.parent().addClass('error');
+          Drupal.FieldGroup.setGroupWithfocus($(this));
+          $(this).data('horizontalTab').focus();
+        }
+      });
+    }
+  }
+}
+
+/**
+ * Implements Drupal.FieldGroup.processHook().
+ */
+Drupal.FieldGroup.Effects.processTabs = {
+  execute: function (context, settings, type) {
+    if (type == 'form') {
+      // Add required fields mark to any fieldsets containing required fields
+      $('fieldset.vertical-tabs-pane', context).once('fieldgroup-effects', function(i) {
+        if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
+          $(this).data('verticalTab').link.find('strong:first').after($('.form-required').eq(0).clone()).after(' ');
+        }
+        if ($('.error', $(this)).length) {
+          $(this).data('verticalTab').link.parent().addClass('error');
+          Drupal.FieldGroup.setGroupWithfocus($(this));
+          $(this).data('verticalTab').focus();
+        }
+      });
+    }
+  }
+}
+
+/**
+ * Implements Drupal.FieldGroup.processHook().
+ *
+ * TODO clean this up meaning check if this is really
+ *      necessary.
+ */
+Drupal.FieldGroup.Effects.processDiv = {
+  execute: function (context, settings, type) {
+
+    $('div.collapsible', context).once('fieldgroup-effects', function() {
+      var $wrapper = $(this);
+
+      // Turn the legend into a clickable link, but retain span.field-group-format-toggler
+      // for CSS positioning.
+
+      var $toggler = $('span.field-group-format-toggler:first', $wrapper);
+      var $link = $('<a class="field-group-format-title" href="#"></a>');
+      $link.prepend($toggler.contents());
+
+      // Add required field markers if needed
+      if ($(this).is('.required-fields') && $(this).find('.form-required').length > 0) {
+        $link.append(' ').append($('.form-required').eq(0).clone());
+      }
+
+      $link.appendTo($toggler);
+
+      // .wrapInner() does not retain bound events.
+      $link.click(function () {
+        var wrapper = $wrapper.get(0);
+        // Don't animate multiple times.
+        if (!wrapper.animating) {
+          wrapper.animating = true;
+          var speed = $wrapper.hasClass('speed-fast') ? 300 : 1000;
+          if ($wrapper.hasClass('effect-none') && $wrapper.hasClass('speed-none')) {
+            $('> .field-group-format-wrapper', wrapper).toggle();
+          }
+          else if ($wrapper.hasClass('effect-blind')) {
+            $('> .field-group-format-wrapper', wrapper).toggle('blind', {}, speed);
+          }
+          else {
+            $('> .field-group-format-wrapper', wrapper).toggle(speed);
+          }
+          wrapper.animating = false;
+        }
+        $wrapper.toggleClass('collapsed');
+        return false;
+      });
+
+    });
+  }
+};
+
+/**
+ * Behaviors.
+ */
+Drupal.behaviors.fieldGroup = {
+  attach: function (context, settings) {
+    if (settings.field_group == undefined) {
+      return;
+    }
+
+    // Execute all of them.
+    $.each(Drupal.FieldGroup.Effects, function (func) {
+      // We check for a wrapper function in Drupal.field_group as
+      // alternative for dynamic string function calls.
+      var type = func.toLowerCase().replace("process", "");
+      if (settings.field_group[type] != undefined && $.isFunction(this.execute)) {
+        this.execute(context, settings, settings.field_group[type]);
+      }
+    });
+
+    // Fixes css for fieldgroups under vertical tabs.
+    $('.fieldset-wrapper .fieldset > legend').css({display: 'block'});
+    $('.vertical-tabs fieldset.fieldset').addClass('default-fallback');
+
+
+    // Add a new ID to each fieldset.
+    $('.group-wrapper fieldset').each(function() {
+      // Tats bad, but we have to keep the actual id to prevent layouts to break.
+      var fieldgorupID = 'field_group-' + $(this).attr('id') + ' ' + $(this).attr('id');
+      $(this).attr('id', fieldgorupID);
+    })
+    // Set the hash in url to remember last userselection.
+    $('.group-wrapper ul li').each(function() {
+      var fieldGroupNavigationListIndex = $(this).index();
+      $(this).children('a').click(function() {
+        var fieldset = $('.group-wrapper fieldset').get(fieldGroupNavigationListIndex);
+        // Grab the first id, holding the wanted hashurl.
+        var hashUrl = $(fieldset).attr('id').replace(/^field_group-/, '').split(' ')[0];
+        window.location.hash = hashUrl;
+      });
+    });
+  }
+};
+
+})(jQuery);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,2126 @@
+<?php
+
+/**
+ * @file
+ * Fieldgroup module.
+ *
+ * For an overview of all php and javascript hooks, see field_group.api.php.
+ *
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function field_group_menu() {
+  $items = array();
+
+  // Ensure the following is not executed until field_bundles is working and
+  // tables are updated. Needed to avoid errors on initial installation.
+  if (defined('MAINTENANCE_MODE')) {
+    return $items;
+  }
+
+  // Create tabs for all possible bundles.
+  foreach (entity_get_info() as $entity_type => $entity_info) {
+    if (isset($entity_info['fieldable']) && $entity_info['fieldable']) {
+      foreach ($entity_info['bundles'] as $bundle_name => $bundle_info) {
+        if (isset($bundle_info['admin'])) {
+          // Extract path information from the bundle.
+          $path = $bundle_info['admin']['path'];
+          // Different bundles can appear on the same path (e.g. %node_type and
+          // %comment_node_type). To allow field_group_menu_load() to extract the
+          // actual bundle object from the translated menu router path
+          // arguments, we need to identify the argument position of the bundle
+          // name string ('bundle argument') and pass that position to the menu
+          // loader. The position needs to be casted into a string; otherwise it
+          // would be replaced with the bundle name string.
+          if (isset($bundle_info['admin']['bundle argument'])) {
+            $bundle_arg = $bundle_info['admin']['bundle argument'];
+            $bundle_pos = (string) $bundle_arg;
+          }
+          else {
+            $bundle_arg = $bundle_name;
+            $bundle_pos = '0';
+          }
+
+          // This is the position of the %field_group_menu placeholder in the
+          // items below.
+          $group_position = count(explode('/', $path)) + 1;
+
+          // Extract access information, providing defaults.
+          $access = array_intersect_key($bundle_info['admin'], drupal_map_assoc(array('access callback', 'access arguments')));
+          $access += array(
+            'access callback' => 'user_access',
+            'access arguments' => array('administer site configuration'),
+          );
+
+          $items["$path/groups/%field_group_menu/delete"] = array(
+            'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'),
+            'title' => 'Delete',
+            'page callback' => 'drupal_get_form',
+            'page arguments' => array('field_group_delete_form', $group_position),
+            'type' => MENU_CALLBACK,
+            'file' => 'field_group.field_ui.inc',
+          ) + $access;
+
+          $items["$path/groups/%field_group_menu/enable"] = array(
+            'load arguments' => array($entity_type, $bundle_arg, $bundle_pos, '%map'),
+            'title' => 'Enable',
+            'page callback' => 'drupal_get_form',
+            'page arguments' => array('field_group_enable_form', $group_position),
+            'type' => MENU_CALLBACK,
+            'file' => 'field_group.field_ui.inc',
+          ) + $access;
+
+        }
+      }
+    }
+  }
+
+  return $items;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function field_group_permission() {
+  return array(
+    'administer fieldgroups' => array(
+      'title' => t('Administer fieldgroups'),
+      'description' => t('Display the administration for fieldgroups.'),
+    ),
+  );
+}
+
+/**
+ * Menu Wildcard loader function to load group definitions.
+ *
+ * @param $group_name
+ *   The name of the group, as contained in the path.
+ * @param $entity_type
+ *   The name of the entity.
+ * @param $bundle_name
+ *   The name of the bundle, as contained in the path.
+ * @param $bundle_pos
+ *   The position of $bundle_name in $map.
+ * @param $map
+ *   The translated menu router path argument map.
+ */
+function field_group_menu_load($group_name, $entity_type, $bundle_name, $bundle_pos, $map) {
+
+  if ($bundle_pos > 0) {
+    $bundle = $map[$bundle_pos];
+    $bundle_name = field_extract_bundle($entity_type, $bundle);
+  }
+
+  $args = func_get_args();
+  $args_pop = array_pop($args);
+  $mode = array_pop($args_pop);
+
+  $group = field_group_load_field_group($group_name, $entity_type, $bundle_name, $mode);
+
+  return empty($group) ? FALSE : $group;
+}
+
+/**
+ * Loads a group definition.
+ *
+ * @param $group_name
+ *   The name of the group.
+ * @param $entity_type
+ *   The name of the entity.
+ * @param $bundle_name
+ *   The name of the bundle.
+ * @param $mode
+ *   The view mode to load.
+ */
+function field_group_load_field_group($group_name, $entity_type, $bundle_name, $mode) {
+
+  ctools_include('export');
+  $objects = ctools_export_load_object('field_group', 'conditions', array(
+    'group_name' => $group_name,
+    'entity_type' => $entity_type,
+    'bundle' => $bundle_name,
+    'mode' => $mode,
+  ));
+  $object = array_shift($objects);
+
+  if ($object && isset($object->data)) {
+    return field_group_unpack($object);
+  }
+
+  return $object;
+}
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function field_group_ctools_plugin_api($owner, $api) {
+  if ($owner == 'field_group' && $api == 'field_group') {
+    return array('version' => 1);
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function field_group_theme() {
+  return array(
+    'horizontal_tabs' => array(
+      'render element' => 'element',
+    ),
+    'multipage' => array(
+      'render element' => 'element',
+    ),
+    'multipage_pane' => array(
+      'render element' => 'element',
+    ),
+  );
+}
+
+/**
+ * Implements hook_theme_registry_alter().
+ */
+function field_group_theme_registry_alter(&$theme_registry) {
+
+  // Inject field_group_build_entity_groups in all entity theming functions.
+  $entity_info = entity_get_info();
+  $entities = array();
+  foreach ($entity_info as $entity => $info) {
+    if (isset($entity_info[$entity]['fieldable']) && $entity_info[$entity]['fieldable']) {
+      // User uses user_profile for theming.
+      if ($entity == 'user') $entity = 'user_profile';
+      $entities[] = $entity;
+    }
+  }
+
+  // Support for File Entity.
+  if (isset($theme_registry['file_entity'])) {
+    $entities[] = 'file_entity';
+  }
+
+  // Support for Entity API.
+  if (isset($theme_registry['entity'])) {
+    $entities[] = 'entity';
+  }
+
+  foreach ($entities as $entity) {
+    if (isset($theme_registry[$entity])) {
+      $theme_registry[$entity]['preprocess functions'][] = 'field_group_build_entity_groups';
+      // DS support, make sure it comes after field_group.
+      if ($key = array_search('ds_entity_variables', $theme_registry[$entity]['preprocess functions'])) {
+        unset($theme_registry[$entity]['preprocess functions'][$key]);
+        $theme_registry[$entity]['preprocess functions'][] = 'ds_entity_variables';
+      }
+    }
+  }
+
+}
+
+/**
+ * Implements hook_field_attach_delete_bundle().
+ *
+ * @param String $entity_type
+ * @param String $bundle
+ */
+function field_group_field_attach_delete_bundle($entity_type, $bundle) {
+
+  ctools_include('export');
+  $list = field_group_read_groups(array('bundle' => $bundle, 'entity_type' => $entity_type));
+
+  // Delete the entity's entry from field_group of all entities.
+  // We fetch the field groups first to assign the removal task to ctools.
+  if (isset($list[$entity_type], $list[$entity_type][$bundle])) {
+    foreach ($list[$entity_type][$bundle] as $group_mode => $groups) {
+      foreach ($groups as $group) {
+        ctools_export_crud_delete('field_group', $group);
+      }
+    }
+  }
+
+}
+
+/**
+ * Implements hook_field_attach_form().
+ */
+function field_group_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
+  $form['#attached']['css'][] = drupal_get_path('module', 'field_group') . '/field_group.field_ui.css';
+  field_group_attach_groups($form, 'form', $form_state);
+  $form['#pre_render'][] = 'field_group_form_pre_render';
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ * Using hook_form_field_ui_field_overview_form_alter.
+ */
+function field_group_form_field_ui_field_overview_form_alter(&$form, &$form_state) {
+  form_load_include($form_state, 'inc', 'field_group', 'field_group.field_ui');
+  field_group_field_ui_overview_form_alter($form, $form_state);
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ * Using hook_form_field_ui_display_overview_form_alter.
+ */
+function field_group_form_field_ui_display_overview_form_alter(&$form, &$form_state) {
+  form_load_include($form_state, 'inc', 'field_group', 'field_group.field_ui');
+  field_group_field_ui_overview_form_alter($form, $form_state, TRUE);
+}
+
+/**
+ * Implements hook_field_attach_view_alter().
+ */
+function field_group_field_attach_view_alter(&$element, $context) {
+  // Check whether the view mode uses custom display settings or the 'default' mode.
+  $actual_mode = 'default';
+  if (isset($element['#entity_type']) && isset($element['#bundle'])) {
+    $view_mode_settings = field_view_mode_settings($element['#entity_type'], $element['#bundle']);
+    $view_mode = $context['view_mode'];
+    $actual_mode = (!empty($view_mode_settings[$view_mode]['custom_settings']) ? $view_mode : 'default');
+    field_group_attach_groups($element, $actual_mode);
+  }
+}
+
+/**
+ * Implements hook_field_group_formatter_info().
+ */
+function field_group_field_group_formatter_info() {
+
+  return array(
+    'form' => array(
+      'html-element' => array(
+        'label' => t('HTML element'),
+        'description' => t('This fieldgroup renders the inner content in a HTML element with classes and attributes.'),
+        'instance_settings' => array('element' => 'div', 'classes' => '', 'attributes' => '', 'required_fields' => 1),
+      ),
+      'div' => array(
+        'label' => t('Div'),
+        'description' => t('This fieldgroup renders the inner content in a simple div with the title as legend.'),
+        'format_types' => array('open', 'collapsible', 'collapsed'),
+        'instance_settings' => array('description' => '', 'show_label' => 1, 'label_element' => 'h3', 'effect' => 'none', 'speed' => 'fast', 'classes' => '', 'required_fields' => 1, 'id' => ''),
+        'default_formatter' => 'open',
+      ),
+      'html5' => array(
+        'label' => t('HTML5'),
+        'description' => t('This fieldgroup renders the inner content in a semantic HTML5 wrapper'),
+        'instance_settings' => array('wrapper' => '', 'classes' => ''),
+      ),
+      'fieldset' => array(
+        'label' => t('Fieldset'),
+        'description' => t('This fieldgroup renders the inner content in a fieldset with the title as legend.'),
+        'format_types' => array('open', 'collapsible', 'collapsed'),
+        'instance_settings' => array('description' => '', 'classes' => '', 'required_fields' => 1),
+        'default_formatter' => 'collapsible',
+      ),
+      'tabs' => array(
+        'label' => t('Vertical tabs group'),
+        'description' => t('This fieldgroup renders child groups in its own vertical tabs wrapper.'),
+        'instance_settings' => array('classes' => ''),
+      ),
+      'tab' => array(
+        'label' => t('Vertical tab'),
+        'description' => t('This fieldgroup renders the content in a fieldset, part of vertical tabs group.'),
+        'format_types' => array('open', 'closed'),
+        'instance_settings' => array('description' => '', 'classes' => '', 'required_fields' => 1),
+        'default_formatter' => 'closed',
+      ),
+      'htabs' => array(
+        'label' => t('Horizontal tabs group'),
+        'description' => t('This fieldgroup renders child groups in its own horizontal tabs wrapper.'),
+        'instance_settings' => array('classes' => ''),
+      ),
+      'htab' => array(
+        'label' => t('Horizontal tab'),
+        'format_types' => array('open', 'closed'),
+        'description' => t('This fieldgroup renders the content in a fieldset, part of horizontal tabs group.'),
+        'default_formatter' => 'closed',
+        'instance_settings' => array('description' => '', 'classes' => '', 'required_fields' => 1, 'id' => ''),
+      ),
+      'multipage-group' => array(
+        'label' => t('Multipage group'),
+        'description' => t('This fieldgroup renders groups on separate pages.'),
+        'instance_settings' => array('classes' => '', 'page_header' => 3, 'move_additional' => 1, 'page_counter' => 1, 'move_button' => 0),
+      ),
+      'multipage' => array(
+        'label' => t('Multipage'),
+        'format_types' => array('start', 'no-start'),
+        'description' => t('This fieldgroup renders the content in a page.'),
+        'default_formatter' => 'no-start',
+        'instance_settings' => array('description' => '', 'classes' => '', 'required_fields' => 1),
+      ),
+      'accordion' => array(
+        'label' => t('Accordion group'),
+        'description' => t('This fieldgroup renders child groups as jQuery accordion.'),
+        'instance_settings' => array('effect' => 'none', 'classes' => ''),
+      ),
+      'accordion-item' => array(
+        'label' => t('Accordion item'),
+        'format_types' => array('open', 'closed'),
+        'description' => t('This fieldgroup renders the content in a div, part of accordion group.'),
+        'default_formatter' => 'closed',
+        'instance_settings' => array('description' => '', 'classes' => '', 'required_fields' => 1),
+      ),
+    ),
+    'display' => array(
+      'html-element' => array(
+        'label' => t('HTML element'),
+        'description' => t('This fieldgroup renders the inner content in a HTML element with classes and attributes.'),
+        'instance_settings' => array('element' => 'div', 'classes' => '', 'attributes' => '', 'required_fields' => 1),
+      ),
+      'div' => array(
+        'label' => t('Div'),
+        'description' => t('This fieldgroup renders the inner content in a simple div with the title as legend.'),
+        'format_types' => array('open', 'collapsible', 'collapsed'),
+        'instance_settings' => array('description' => '', 'show_label' => 1, 'label_element' => 'h3', 'effect' => 'none', 'speed' => 'fast', 'classes' => ''),
+        'default_formatter' => 'collapsible',
+      ),
+      'html5' => array(
+        'label' => t('HTML5'),
+        'description' => t('This fieldgroup renders the inner content in a semantic HTML5 wrapper'),
+        'instance_settings' => array('wrapper' => '', 'classes' => ''),
+      ),
+      'fieldset' => array(
+        'label' => t('Fieldset'),
+        'description' => t('This fieldgroup renders the inner content in a fieldset with the title as legend.'),
+        'format_types' => array('open', 'collapsible', 'collapsed'),
+        'instance_settings' => array('description' => '', 'classes' => ''),
+        'default_formatter' => 'collapsible',
+      ),
+      'tabs' => array(
+        'label' => t('Vertical tabs group'),
+        'description' => t('This fieldgroup renders child groups in its own vertical tabs wrapper.'),
+        'instance_settings' => array('classes' => ''),
+      ),
+      'tab' => array(
+        'label' => t('Vertical tab'),
+        'description' => t('This fieldgroup renders the content in a fieldset, part of vertical tabs group.'),
+        'format_types' => array('open', 'closed'),
+        'instance_settings' => array('description' => '', 'classes' => ''),
+        'default_formatter' => 'closed',
+      ),
+      'htabs' => array(
+        'label' => t('Horizontal tabs group'),
+        'description' => t('This fieldgroup renders child groups in its own horizontal tabs wrapper.'),
+        'instance_settings' => array('classes' => ''),
+      ),
+      'htab' => array(
+        'label' => t('Horizontal tab item'),
+        'format_types' => array('open', 'closed'),
+        'description' => t('This fieldgroup renders the content in a fieldset, part of horizontal tabs group.'),
+        'instance_settings' => array('description' => '', 'classes' => '', 'id' => ''),
+        'default_formatter' => 'closed',
+      ),
+      'accordion' => array(
+        'label' => t('Accordion group'),
+        'description' => t('This fieldgroup renders child groups as jQuery accordion.'),
+        'instance_settings' => array('description' => '', 'classes' => '', 'effect' => 'bounceslide'),
+      ),
+      'accordion-item' => array(
+        'label' => t('Accordion item'),
+        'format_types' => array('open', 'closed'),
+        'description' => t('This fieldgroup renders the content in a div, part of accordion group.'),
+        'instance_settings' => array('classes' => ''),
+        'default_formatter' => 'closed',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_group_format_settings().
+ * If the group has no format settings, default ones will be added.
+ * @params Object $group The group object.
+ * @return Array $form The form element for the format settings.
+ */
+function field_group_field_group_format_settings($group) {
+  // Add a wrapper for extra settings to use by others.
+  $form = array(
+    'instance_settings' => array(
+      '#tree' => TRUE,
+      '#weight' => 2,
+    ),
+  );
+
+  $field_group_types = field_group_formatter_info();
+  $mode = $group->mode == 'form' ? 'form' : 'display';
+  $formatter = $field_group_types[$mode][$group->format_type];
+
+  // Add the required formatter type selector.
+  if (isset($formatter['format_types'])) {
+    $form['formatter'] = array(
+      '#title' => t('Fieldgroup settings'),
+      '#type' => 'select',
+      '#options' => drupal_map_assoc($formatter['format_types']),
+      '#default_value' => isset($group->format_settings['formatter']) ? $group->format_settings['formatter'] : $formatter['default_formatter'],
+      '#weight' => 1,
+    );
+  }
+
+  if (isset($formatter['instance_settings']['required_fields']) && $mode == 'form') {
+    $form['instance_settings']['required_fields'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Mark group for required fields.'),
+      '#default_value' => isset($group->format_settings['instance_settings']['required_fields']) ? $group->format_settings['instance_settings']['required_fields'] : (isset($formatter['instance_settings']['required_fields']) ? $formatter['instance_settings']['required_fields'] : ''),
+      '#weight' => 2,
+    );
+  }
+
+  if (isset($formatter['instance_settings']['id'])) {
+    $form['instance_settings']['id'] = array(
+      '#title' => t('ID'),
+      '#type' => 'textfield',
+      '#default_value' => isset($group->format_settings['instance_settings']['id']) ? $group->format_settings['instance_settings']['id'] : (isset($formatter['instance_settings']['id']) ? $formatter['instance_settings']['id'] : ''),
+      '#weight' => 3,
+      '#element_validate' => array('field_group_validate_id'),
+    );
+  }
+  if (isset($formatter['instance_settings']['classes'])) {
+    $form['instance_settings']['classes'] = array(
+      '#title' => t('Extra CSS classes'),
+      '#type' => 'textfield',
+      '#default_value' => isset($group->format_settings['instance_settings']['classes']) ? $group->format_settings['instance_settings']['classes'] : (isset($formatter['instance_settings']['classes']) ? $formatter['instance_settings']['classes'] : ''),
+      '#weight' => 4,
+      '#element_validate' => array('field_group_validate_css_class'),
+    );
+  }
+
+  if (isset($formatter['instance_settings']['description'])) {
+    $form['instance_settings']['description'] = array(
+      '#title' => t('Description'),
+      '#type' => 'textarea',
+      '#default_value' => isset($group->format_settings['instance_settings']['description']) ? $group->format_settings['instance_settings']['description'] : (isset($formatter['instance_settings']['description']) ? $formatter['instance_settings']['description'] : ''),
+      '#weight' => 0,
+    );
+  }
+
+  // Add optional instance_settings.
+  switch ($group->format_type) {
+    case 'html-element':
+      $form['instance_settings']['element'] = array(
+        '#title' => t('Element'),
+        '#type' => 'textfield',
+        '#default_value' => isset($group->format_settings['instance_settings']['element']) ? $group->format_settings['instance_settings']['element'] : $formatter['instance_settings']['element'],
+        '#description' => t('E.g. div, section, aside etc.'),
+        '#weight' => 2,
+      );
+
+      $form['instance_settings']['attributes'] = array(
+        '#title' => t('Attributes'),
+        '#type' => 'textfield',
+        '#default_value' => isset($group->format_settings['instance_settings']['attributes']) ? $group->format_settings['instance_settings']['attributes'] : $formatter['instance_settings']['attributes'],
+        '#description' => t('E.g. name="anchor"'),
+        '#weight' => 4,
+      );
+      break;
+    case 'div':
+      $form['instance_settings']['show_label'] = array(
+        '#title' => t('Show label'),
+        '#type' => 'select',
+        '#options' => array(0 => t('No'), 1 => t('Yes')),
+        '#default_value' => isset($group->format_settings['instance_settings']['show_label']) ? $group->format_settings['instance_settings']['show_label'] : $formatter['instance_settings']['show_label'],
+        '#weight' => 2,
+      );
+      $form['instance_settings']['label_element'] = array(
+        '#title' => t('Label element'),
+        '#type' => 'select',
+        '#options' => array('h2' => t('Header 2'), 'h3' => t('Header 3')),
+        '#default_value' => isset($group->format_settings['instance_settings']['label_element']) ? $group->format_settings['instance_settings']['label_element'] : $formatter['instance_settings']['label_element'],
+        '#weight' => 2,
+      );
+      $form['instance_settings']['effect'] = array(
+        '#title' => t('Effect'),
+        '#type' => 'select',
+        '#options' => array('none' => t('None'), 'blind' => t('Blind')),
+        '#default_value' => isset($group->format_settings['instance_settings']['effect']) ? $group->format_settings['instance_settings']['effect'] : $formatter['instance_settings']['effect'],
+        '#weight' => 2,
+      );
+      $form['instance_settings']['speed'] = array(
+        '#title' => t('Speed'),
+        '#type' => 'select',
+        '#options' => array('none' => t('None'), 'slow' => t('Slow'), 'fast' => t('Fast')),
+        '#default_value' => isset($group->format_settings['instance_settings']['speed']) ? $group->format_settings['instance_settings']['speed'] : $formatter['instance_settings']['speed'],
+        '#weight' => 3,
+      );
+      break;
+    case 'html5':
+      $form['instance_settings']['wrapper'] = array(
+        '#title' => t('HTML5 wrapper'),
+        '#type' => 'select',
+        '#options' => array('section' => t('Section'), 'article' => t('Article'), 'header' => t('Header'), 'footer' => t('Footer'), 'aside' => t('Aside')),
+        '#default_value' => isset($group->format_settings['instance_settings']['wrapper']) ? $group->format_settings['instance_settings']['wrapper'] : 'section',
+      );
+      break;
+    case 'fieldset':
+      break;
+    case 'multipage-group':
+      $form['instance_settings']['page_header'] = array(
+        '#title' => t('Format page title'),
+        '#type' => 'select',
+        '#options' => array(0 => t('None'), 1 => t('Label only'), 2 => t('Step 1 of 10'), 3 => t('Step 1 of 10 [Label]'),),
+        '#default_value' => isset($group->format_settings['instance_settings']['page_header']) ? $group->format_settings['instance_settings']['page_header'] : $formatter['instance_settings']['page_header'],
+        '#weight' => 1,
+      );
+      $form['instance_settings']['page_counter'] = array(
+        '#title' => t('Add a page counter at the bottom'),
+        '#type' => 'select',
+        '#options' => array(0 => t('No'), 1 => t('Format 1 / 10'), 2 => t('The count number only')),
+        '#default_value' => isset($group->format_settings['instance_settings']['page_counter']) ? $group->format_settings['instance_settings']['page_counter'] : $formatter['instance_settings']['page_counter'],
+        '#weight' => 2,
+      );
+      $form['instance_settings']['move_button'] = array(
+        '#title' => t('Move submit button to last multipage'),
+        '#type' => 'select',
+        '#options' => array(0 => t('No'), 1 => t('Yes')),
+        '#default_value' => isset($group->format_settings['instance_settings']['move_button']) ? $group->format_settings['instance_settings']['move_button'] : $formatter['instance_settings']['move_button'],
+        '#weight' => 3,
+      );
+      $form['instance_settings']['move_additional'] = array(
+        '#title' => t('Move additional settings to last multipage (if available)'),
+        '#type' => 'select',
+        '#options' => array(0 => t('No'), 1 => t('Yes')),
+        '#default_value' => isset($group->format_settings['instance_settings']['move_additional']) ? $group->format_settings['instance_settings']['move_additional'] : $formatter['instance_settings']['move_additional'],
+        '#weight' => 4,
+      );
+    case 'tabs':
+    case 'htabs':
+      break;
+    case 'accordion':
+      $form['instance_settings']['effect'] = array(
+        '#title' => t('Effect'),
+        '#type' => 'select',
+        '#options' => array('none' => t('None'), 'bounceslide' => t('Bounce slide')),
+        '#default_value' => isset($group->format_settings['instance_settings']['effect']) ? $group->format_settings['instance_settings']['effect'] : $formatter['instance_settings']['effect'],
+        '#weight' => 2,
+      );
+      break;
+    case 'multipage':
+      break;
+    case 'tab':
+    case 'htab':
+    case 'accordion-item':
+    default:
+  }
+
+  return $form;
+}
+
+/**
+ * Helper function to prepare basic variables needed for most formatters.
+ *
+ * Called in field_group_field_group_pre_render(), but can also be called in
+ * other implementations of hook_field_group_pre_render().
+ */
+function field_group_pre_render_prepare(&$group) {
+
+  $classes = _field_group_get_html_classes($group);
+
+  $group->classes = implode(' ', $classes->required);
+  $group->description = isset($group->format_settings['instance_settings']['description']) ? filter_xss_admin(t($group->format_settings['instance_settings']['description'])) : '';
+
+}
+
+/**
+ * Implements hook_field_group_pre_render().
+ *
+ * @param Array $elements by address.
+ * @param Object $group The Field group info.
+ */
+function field_group_field_group_pre_render(& $element, &$group, & $form) {
+
+  field_group_pre_render_prepare($group);
+
+  $view_mode = isset($form['#view_mode']) ? $form['#view_mode'] : 'form';
+
+  // Add all field_group format types to the js settings.
+  $form['#attached']['js'][] = array(
+    'data' => array('field_group' => array($group->format_type => $view_mode)),
+    'type' => 'setting',
+  );
+  $form['#attached']['js'][] = 'misc/form.js';
+  $form['#attached']['js'][] = 'misc/collapse.js';
+
+  if (isset($group->format_settings['instance_settings']['id']) && !empty($group->format_settings['instance_settings']['id'])) {
+    $element['#id'] = $group->format_settings['instance_settings']['id'];
+  }
+  else {
+    $element['#id'] = $form['#entity_type'] . '_' . $form['#bundle'] . '_' . $view_mode . '_' . $group->group_name;
+  }
+
+  $element['#weight'] = $group->weight;
+
+  // Call the pre render function for the format type.
+  $function = "field_group_pre_render_" . str_replace("-", "_", $group->format_type);
+  if (function_exists($function)) {
+    $function($element, $group, $form);
+  }
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Fieldset.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_fieldset(&$element, $group, &$form) {
+
+  $element += array(
+    '#type' => 'fieldset',
+    '#title' => check_plain(t($group->label)),
+    '#collapsible' => $group->collapsible,
+    '#collapsed' => $group->collapsed,
+    '#pre_render' => array(),
+    '#attributes' => array('class' => explode(' ', $group->classes)),
+    '#description' => $group->description,
+  );
+  $element['#attached']['js'][] = 'misc/form.js';
+  $element['#attached']['js'][] = 'misc/collapse.js';
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: HTML element.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_html_element(&$element, $group, &$form) {
+  $html_element = isset($group->format_settings['instance_settings']['element']) ? $group->format_settings['instance_settings']['element'] : 'div';
+  $attributes = isset($group->format_settings['instance_settings']['attributes']) ? ' ' . $group->format_settings['instance_settings']['attributes'] : '';
+  $group->classes = trim($group->classes);
+
+  // This regex split the attributes string so that we can pass that
+  // later to drupal_attributes().
+  preg_match_all('/([^\s=]+)="([^"]+)"/', $attributes, $matches);
+
+  $element_attributes = array();
+  // Put the attribute and the value together.
+  foreach ($matches[1] as $key => $attribute) {
+    $element_attributes[$attribute] = $matches[2][$key];
+  }
+
+  // Add the classes to the attributes array.
+  if (!isset($element_attributes['class']) && $group->classes) {
+    $element_attributes['class'] = $group->classes;
+  }
+  elseif (isset($element_attributes['class']) && $group->classes) {
+    $element_attributes['class'] .= ' ' . $group->classes;
+  }
+
+  $attributes = drupal_attributes($element_attributes);
+
+  $element['#prefix'] = '<' . $html_element . $attributes . '>';
+  $element['#suffix'] = '</' . $html_element . '>';
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Div.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_div(&$element, $group, &$form) {
+
+  $show_label = isset($group->format_settings['instance_settings']['show_label']) ? $group->format_settings['instance_settings']['show_label'] : 0;
+  $label_element = isset($group->format_settings['instance_settings']['label_element']) ? $group->format_settings['instance_settings']['label_element'] : 'h2';
+  $effect = isset($group->format_settings['instance_settings']['effect']) ? $group->format_settings['instance_settings']['effect'] : 'none';
+
+  $element['#type'] = 'markup';
+  if ($group->format_settings['formatter'] != 'open') {
+    $element['#prefix'] = '<div id="' . $element['#id'] . '" class="' . $group->classes . '">
+      <' . $label_element . '><span class="field-group-format-toggler">' . check_plain(t($group->label)) . '</span></' . $label_element . '>
+      <div class="field-group-format-wrapper" style="display: ' . (!empty($group->collapsed) ? 'none' : 'block') . ';">';
+    $element['#suffix'] = '</div></div>';
+  }
+  else {
+    $class_attribute = '';
+    if (!empty($group->classes)) {
+      $class_attribute = 'class = "' . $group->classes . '"';
+    }
+    $element['#prefix'] = '<div id="' . $element['#id'] . '"' . $class_attribute . '>';
+    if ($show_label) {
+      $element['#prefix'] .= '<' . $label_element . '><span>' . check_plain(t($group->label)) . '</span></' . $label_element . '>';
+    }
+    $element['#suffix'] = '</div>';
+  }
+  if (!empty($group->description)) {
+    $element['#prefix'] .= '<div class="description">' . $group->description . '</div>';
+  }
+
+  if ($effect == 'blind') {
+    drupal_add_library('system', 'effects.blind');
+  }
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: HTML5.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_html5(&$element, $group, &$form) {
+  $element += array(
+    '#type' => 'markup',
+    '#prefix' => '<' . $group->format_settings['instance_settings']['wrapper'] . ' id="' . $element['#id'] . '" class="' . $group->classes . '">',
+    '#suffix' => '</' . $group->format_settings['instance_settings']['wrapper'] . '>',
+  );
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Accordion.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_accordion(&$element, $group, &$form) {
+
+  // Add the jQuery UI accordion.
+  drupal_add_library('system', 'ui.accordion');
+
+  $element += array(
+    '#type' => 'markup',
+    '#prefix' => '<div class="' . $group->classes . '">',
+    '#suffix' => '</div>',
+  );
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Accordion item.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_accordion_item(&$element, $group, &$form) {
+
+  $element += array(
+    '#type' => 'markup',
+    '#prefix' => '<h3 class="field-group-format-toggler ' . $group->format_type . ($group->collapsed ? '' : ' field-group-accordion-active') . '"><a href="#">' . check_plain(t($group->label)) . '</a></h3>
+    <div class="field-group-format-wrapper ' . $group->classes . '">',
+    '#suffix' => '</div>',
+    //'#attributes' => array('class' => array($group->format_type)),
+  );
+  if (!empty($group->description)) {
+    $element['#prefix'] .= '<div class="description">' . $group->description . '</div>';
+  }
+  drupal_add_library('system', 'ui.accordion');
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Horizontal tabs group.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_htabs(&$element, $group, &$form) {
+
+  $element += array(
+    '#type' => 'horizontal_tabs',
+    '#title' => check_plain(t($group->label)),
+    '#theme_wrappers' => array('horizontal_tabs'),
+    '#prefix' => '<div class="field-group-' . $group->format_type . '-wrapper ' . $group->classes . '">',
+    '#suffix' => '</div>',
+  );
+
+  // By default vertical_tabs don't have titles but you can override it in the theme.
+  if (!empty($group->label)) {
+    $element['#title'] = check_plain($group->label);
+  }
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Horizontal tab.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_htab(&$element, $group, &$form) {
+
+  $element += array(
+    '#type' => 'fieldset',
+    '#title' => check_plain(t($group->label)),
+    '#collapsible' => $group->collapsible,
+    '#collapsed' => $group->collapsed,
+    '#attributes' => array('class' => explode(" ", $group->classes)),
+    '#group' => $group->parent_name,
+    // very important. Cannot be added on the form!
+    '#parents' => array($group->parent_name),
+    '#description' => $group->description,
+  );
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Multipage group.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_multipage_group(&$element, &$group, &$form) {
+
+  $multipage_element = array(
+    '#type' => 'multipage',
+    '#theme_wrappers' => array('multipage'),
+    '#prefix' => '<div class="field-group-' . $group->format_type . '-wrapper ' . $group->classes . '">',
+    '#suffix' => '</div>',
+  );
+
+  $element += $multipage_element;
+
+  $move_additional = isset($group->format_settings['instance_settings']['move_additional']) ? ($group->format_settings['instance_settings']['move_additional'] && isset($form['additional_settings'])) : isset($form['additional_settings']);
+  $move_button = isset($group->format_settings['instance_settings']['move_button']) ? $group->format_settings['instance_settings']['move_button'] : 0;
+
+  drupal_add_js(array(
+    'field_group' => array(
+      'multipage_move_submit' => (bool) $move_button,
+      'multipage_move_additional' => (bool) $move_additional
+    )
+  ), 'setting');
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Multipage.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_multipage(&$element, $group, &$form) {
+
+  $group->classes .= $group->format_settings['formatter'] == 'start' ? ' multipage-open' : ' multipage-closed';
+  $element += array(
+    '#type' => 'multipage_pane',
+    '#title' => check_plain(t($group->label)),
+    '#collapsible' => $group->collapsible,
+    '#collapsed' => $group->collapsed,
+    '#attributes' => array('class' => explode(" ", $group->classes)),
+    '#group' => $group->parent_name,
+    '#group_object' => $group,
+    '#parent_group_object' => $form['#groups'][$group->parent_name],
+    // very important. Cannot be added on the form!
+    '#parents' => array($group->parent_name),
+    '#description' => $group->description,
+  );
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Vertical tabs wrapper.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_tabs(&$element, $group, &$form) {
+
+  $element += array(
+    '#type' => 'vertical_tabs',
+    '#theme_wrappers' => array('vertical_tabs'),
+    '#prefix' => '<div class="field-group-' . $group->format_type . '-wrapper ' . $group->classes . '">',
+    '#suffix' => '</div>',
+  );
+
+  // By default vertical_tabs don't have titles but you can override it in the theme.
+  if (!empty($group->label)) {
+    $element['#title'] = check_plain($group->label);
+  }
+
+  $element[$group->group_name . '__active_tab'] = array(
+    '#type' => 'hidden',
+    '#default_value' => '',
+    '#attributes' => array('class' => array('vertical-tabs-active-tab')),
+  );
+  $form['#attached']['library'][] = array('system', 'drupal.form');
+  $form['#attached']['library'][] = array('system', 'drupal.collapse');
+
+}
+
+/**
+ * Implements field_group_pre_render_<format-type>.
+ * Format type: Vertical tab.
+ *
+ * @param $element The field group form element.
+ * @param $group The Field group object prepared for pre_render.
+ * @param $form The root element or form.
+ */
+function field_group_pre_render_tab(&$element, $group, &$form) {
+
+  $view_mode = isset($form['#view_mode']) ? $form['#view_mode'] : 'form';
+
+  // Could be it never runs through htab.
+  $form['#attached']['js'][] = array(
+    'data' => array('field_group' => array('tabs' => $view_mode)),
+    'type' => 'setting',
+  );
+
+  $add = array(
+    '#type' => 'fieldset',
+    '#id' => 'edit-' . $group->group_name,
+    '#title' => check_plain(t($group->label)),
+    '#collapsible' => $group->collapsible,
+    '#collapsed' => $group->collapsed,
+    '#attributes' => array('class' => explode(" ", $group->classes)),
+    '#description' => $group->description,
+  );
+
+  // Front-end and back-end on configuration will lead
+  // to vertical tabs nested in a separate vertical group.
+  if ($view_mode != 'form') {
+    $add['#group'] = empty($group->parent_name) ? 'additional_settings' : $group->parent_name;
+    $add['#parents'] = array($add['#group']);
+    $element += $add;
+  }
+  // Form fieldgroups which are nested into a vertical tab group
+  // are handled a little different.
+  elseif (!empty($group->parent_name)) {
+    $add['#group'] = $group->parent_name;
+    $element += $add;
+  }
+  // Forms "can" have additional settins. We'll try to locate it first, if not
+  // exists, field_group will create a parallel additional settings entry.
+  else {
+    // Create the fieldgroup element.
+    $add['#parents'] = array('additional_settings');
+    $add['#group'] = 'additional_settings';
+    $add['#weight'] = -30 + $group->weight; // hardcoded to bring our extra additional vtabs on top.
+
+    // Check if the additional_settings exist for this type of form.
+    if (isset($form['additional_settings']['group']['#groups']['additional_settings'])) {
+
+      // Merge fieldgroups with the core additional settings.
+      $form['additional_settings']['group']['#groups']['additional_settings'][$group->group_name] = $add;
+      $form['additional_settings']['group']['#groups'][$group->group_name] = array('#group_exists' => TRUE);
+      // Nest the fields inside the appropriate structure.
+      foreach (element_children($element) as $fieldname) {
+        $form['additional_settings']['group']['#groups']['additional_settings'][$group->group_name][$fieldname] = &$element[$fieldname];
+        unset($element[$fieldname]);
+      }
+    }
+    // Assumption the wrapper is in the root. This could be done by field_group itself
+    // in previous loop of tabs in same wrapper or even some other contrib / custom module.
+    else {
+      if (!isset($form['additional_settings']['#type'])) {
+        $form['additional_settings'] = array(
+          '#type' => 'vertical_tabs',
+          '#weight' => $group->weight,
+          '#theme_wrappers' => array('vertical_tabs'),
+          '#prefix' => '<div class="field-group-' . $group->format_type . '-wrapper">',
+          '#suffix' => '</div>',
+        );
+        $form['#attached']['js'][] = 'misc/form.js';
+        $form['#attached']['js'][] = 'misc/collapse.js';
+      }
+      $form['additional_settings'][$group->group_name] = $add;
+      // Nest the fields inside the appropriate structure.
+      foreach (element_children($element) as $fieldname) {
+        $form['additional_settings'][$group->group_name][$fieldname] = &$element[$fieldname];
+        unset($element[$fieldname]);
+      }
+    }
+  }
+
+}
+
+/**
+ * Implements hook_field_group_build_pre_render_alter().
+ * @param Array $elements by address.
+ */
+function field_group_field_group_build_pre_render_alter(& $element) {
+
+  // Someone is doing a node view, in a node view. Reset content.
+  // TODO Check if this breaks something else.
+  if (isset($element['#node']->content) && count($element['#node']->content) > 0) {
+    $element['#node']->content = array();
+  }
+
+  $display = isset($element['#view_mode']);
+  $groups = array_keys($element['#groups']);
+
+  // Dish the fieldgroups with no fields for non-forms.
+  if ($display) {
+    field_group_remove_empty_display_groups($element, $groups);
+  }
+  else {
+    // Fix the problem on forms with additional settings.
+    field_group_remove_empty_form_groups('form', $element, $groups, $element['#groups'], $element['#entity_type']);
+  }
+
+  // Add the default field_group javascript and stylesheet.
+  $element['#attached']['js'][] = drupal_get_path('module', 'field_group') . '/field_group.js';
+  $element['#attached']['css'][] = drupal_get_path('module', 'field_group') . '/field_group.css';
+
+  // Move additional settings to the last multipage pane if configured that way.
+  // Note that multipages MUST be in the root of the form.
+  foreach (element_children($element) as $name) {
+    if (isset($element[$name]['#type']) && $element[$name]['#type'] == 'multipage' && isset($element['additional_settings'])) {
+      $parent_group = $element['#groups'][$name];
+      $move_additional = isset($parent_group->format_settings['instance_settings']['move_additional']) ? $parent_group->format_settings['instance_settings']['move_additional'] : 1;
+      $last_pane = NULL;
+      foreach (element_children($element[$name], TRUE) as $pane) {
+        $last_pane = $pane;
+      }
+      $element[$name][$last_pane]['additional_settings'] = $element['additional_settings'];
+      unset($element['additional_settings']);
+    }
+  }
+
+}
+
+/**
+ * Remove empty groups on forms.
+ *
+ * @param String $parent_name
+ *   The name of the element.
+ * @param array $element
+ *   The element to check the empty state.
+ * @param array $groups
+ *   Array of group objects.
+ */
+function field_group_remove_empty_form_groups($name, & $element, $groups, &$form_groups, $entity) {
+
+  $exceptions = array('user__account', 'comment__author');
+
+  $children = element_children($element);
+
+  $hasChildren = FALSE;
+  if (count($children)) {
+    foreach ($children as $childname) {
+      if (in_array($childname, $groups)) {
+        field_group_remove_empty_form_groups($childname, $element[$childname], $groups, $form_groups, $entity);
+      }
+      $exception = $entity . '__' . $childname;
+      $hasChildren = $hasChildren ? TRUE : (isset($element[$childname]['#type']) || in_array($exception, $exceptions));
+    }
+  }
+
+  if (!$hasChildren) {
+
+    // Remove empty elements from the #groups.
+    if (empty($element) && isset($form_groups[$name]) && !is_array($form_groups[$name])) {
+      foreach ($form_groups as $group_name => $group) {
+        if (isset($group->children)) {
+          $group_children = array_flip($group->children);
+          if (isset($group_children[$name])) {
+            unset($form_groups[$group_name]->children[$group_children[$name]]);
+          }
+        }
+      }
+    }
+
+    $element['#access'] = FALSE;
+
+  }
+
+}
+
+/**
+ * Remove empty groups on entity display.
+ * @param array $element
+ *   The element to check the empty state.
+ * @param array $groups
+ *   Array of group objects.
+ */
+function field_group_remove_empty_display_groups(& $element, $groups) {
+
+  $empty_child = TRUE;
+  $empty_group = TRUE;
+
+  // Loop through the children for current element.
+  foreach (element_children($element) as $name) {
+
+    // Descend if the child is a group.
+    if (in_array($name, $groups)) {
+      $empty_child = field_group_remove_empty_display_groups($element[$name], $groups);
+      if (!$empty_child) {
+        $empty_group = FALSE;
+      }
+    }
+    // Child is a field, the element is not empty.
+    elseif (!empty($element[$name])) {
+      $empty_group = FALSE;
+    }
+
+  }
+
+  // Reset an empty group.
+  if ($empty_group) {
+    $element = NULL;
+  }
+
+  return $empty_group;
+
+}
+
+/**
+ * Implements hook_field_group_format_summary().
+ */
+function field_group_field_group_format_summary($group) {
+
+  $group_form = module_invoke_all('field_group_format_settings', $group);
+
+  $output = '';
+  if (isset($group->format_settings['formatter'])) {
+    $output .= '<strong>' . $group->format_type . '</strong> ' . $group->format_settings['formatter'] . '';
+  }
+  if (isset($group->format_settings['instance_settings'])) {
+    $last = end($group->format_settings['instance_settings']);
+    $output .= '<br />';
+    foreach ($group->format_settings['instance_settings'] as $key => $value) {
+      if (empty($value)) {
+        continue;
+      }
+
+      $output .= '<strong>' . $key . '</strong> ';
+
+      if (isset($group_form['instance_settings'], $group_form['instance_settings'][$key]['#options'])) {
+        if (is_array($value)) {
+          $value = implode(array_filter($value), ', ');
+        }
+        else {
+          $value = $group_form['instance_settings'][$key]['#options'][$value];
+        }
+      }
+
+      // Shorten the string.
+      if (drupal_strlen($value) > 38) {
+        $value = truncate_utf8($value, 50, TRUE, TRUE);
+      }
+      // If still numeric, handle it as yes or no.
+      elseif (is_numeric($value)) {
+        $value = $value == '1' ? t('yes') : t('no');
+      }
+      $output .= check_plain($value);
+      $output .= $last == $value ? ' ' : '<br />';
+    }
+  }
+  return $output;
+}
+
+/**
+ * Implements hook_element_info().
+ */
+function field_group_element_info() {
+  $types['horizontal_tabs'] = array(
+    '#theme_wrappers' => array('horizontal_tabs'),
+    '#default_tab' => '',
+    '#process' => array('form_process_horizontal_tabs'),
+  );
+  $types['multipage'] = array(
+    '#theme_wrappers' => array('multipage'),
+    '#default_tab' => '',
+    '#process' => array('form_process_multipage'),
+  );
+  $types['multipage_pane'] = array(
+    '#value' => NULL,
+    '#process' => array('form_process_fieldset', 'ajax_process_form'),
+    '#pre_render' => array('form_pre_render_fieldset'),
+    '#theme_wrappers' => array('multipage_pane'),
+  );
+  return $types;
+}
+
+/**
+ * Implements hook_library().
+ */
+function field_group_library() {
+
+  $path = drupal_get_path('module', 'field_group');
+  // Horizontal Tabs.
+  $libraries['horizontal-tabs'] = array(
+    'title' => 'Horizontal Tabs',
+    'website' => 'http://drupal.org/node/323112',
+    'version' => '1.0',
+    'js' => array(
+      $path . '/horizontal-tabs/horizontal-tabs.js' => array(),
+    ),
+    'css' => array(
+      $path . '/horizontal-tabs/horizontal-tabs.css' => array(),
+    ),
+  );
+  // Multipage Tabs.
+  $libraries['multipage'] = array(
+    'title' => 'Multipage',
+    'website' => 'http://drupal.org/node/323112',
+    'version' => '1.0',
+    'js' => array(
+      $path . '/multipage/multipage.js' => array(),
+    ),
+    'css' => array(
+      $path . '/multipage/multipage.css' => array(),
+    ),
+  );
+
+  return $libraries;
+}
+
+/**
+ * Implements hook_field_extra_fields().
+ */
+function field_group_field_extra_fields() {
+  $extra = array();
+
+  $extra['user']['user'] = array('form' => array());
+
+  // User picture field to integrate with user module.
+  if (variable_get('user_pictures', 0)) {
+    $extra['user']['user']['form']['picture'] = array(
+      'label' => t('Picture'),
+      'description' => t('User picture'),
+      'weight' => 5,
+    );
+  }
+
+  // Field to itegrate with overlay module.
+  if (module_exists('overlay')) {
+    $extra['user']['user']['form']['overlay_control'] = array(
+      'label' => t('Administrative overlay'),
+      'description' => t('Administrative overlay'),
+      'weight' => 5,
+    );
+  }
+
+  // Field to itegrate with contact module.
+  if (module_exists('contact')) {
+    $extra['user']['user']['form']['contact'] = array(
+      'label' => t('Contact'),
+      'description' => t('Contact user element'),
+     'weight' => 5,
+    );
+  }
+
+  // Field to integrate with the locale module.
+  if (module_exists('locale')) {
+    $extra['user']['user']['form']['locale'] = array(
+      'label' => t('Language settings'),
+      'description' => t('Language settings for the user account.'),
+      'weight' => 5,
+    );
+  }
+
+  // Field to integrate with the wysiwyg module on user settings.
+  if (module_exists('wysiwyg')) {
+    $extra['user']['user']['form']['wysiwyg'] = array(
+      'label' => t('Wysiwyg status'),
+      'description' => t('Text formats enabled for rich-text editing'),
+      'weight' => 5,
+    );
+  }
+
+  return $extra;
+}
+
+/**
+ * Implements hook_field_attach_rename_bundle().
+ */
+function field_group_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
+  db_query('UPDATE {field_group} SET bundle = :bundle WHERE bundle = :old_bundle AND entity_type = :entity_type', array(
+    ':bundle' => $bundle_new,
+    ':old_bundle' => $bundle_old,
+    ':entity_type' => $entity_type,
+  ));
+}
+
+/**
+ * Creates a group formatted as horizontal tabs.
+ * This function will never be callable from within field_group rendering. Other
+ * modules using #type horizontal_tabs will have the benefit of this processor.
+ *
+ * @param $element
+ *   An associative array containing the properties and children of the
+ *   fieldset.
+ * @param $form_state
+ *   The $form_state array for the form this horizontal tab widget belongs to.
+ * @return
+ *   The processed element.
+ */
+function form_process_horizontal_tabs($element, &$form_state) {
+  // Inject a new fieldset as child, so that form_process_fieldset() processes
+  // this fieldset like any other fieldset.
+  $element['group'] = array(
+    '#type' => 'fieldset',
+    '#theme_wrappers' => array(),
+    '#parents' => $element['#parents'],
+  );
+
+  // The JavaScript stores the currently selected tab in this hidden
+  // field so that the active tab can be restored the next time the
+  // form is rendered, e.g. on preview pages or when form validation
+  // fails.
+  $name = implode('__', $element['#parents']);
+  if (isset($form_state['values'][$name . '__active_tab'])) {
+    $element['#default_tab'] = $form_state['values'][$name . '__active_tab'];
+  }
+  $element[$name . '__active_tab'] = array(
+    '#type' => 'hidden',
+    '#default_value' => $element['#default_tab'],
+    '#attributes' => array('class' => array('horizontal-tabs-active-tab')),
+  );
+
+  return $element;
+}
+
+/**
+ * Returns HTML for an element's children fieldsets as horizontal tabs.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties and children of the
+ *     fieldset. Properties used: #children.
+ *
+ * @ingroup themeable
+ */
+function theme_horizontal_tabs($variables) {
+  $element = $variables['element'];
+  // Add required JavaScript and Stylesheet.
+  drupal_add_library('field_group', 'horizontal-tabs');
+
+  $output = '<h2 class="element-invisible">' . (!empty($element['#title']) ? $element['#title'] : t('Horizontal Tabs')) . '</h2>';
+  $output .= '<div class="horizontal-tabs-panes">' . $element['#children'] . '</div>';
+
+  return $output;
+}
+
+/**
+ * Creates a group formatted as multipage.
+ * This function will never be callable from within field_group rendering. Other
+ * modules using #type multipage will have the benefit of this processor.
+ *
+ * @param $element
+ *   An associative array containing the properties and children of the
+ *   fieldset.
+ * @param $form_state
+ *   The $form_state array for the form this multipage tab widget belongs to.
+ * @return
+ *   The processed element.
+ */
+function form_process_multipage($element, &$form_state) {
+  // Inject a new fieldset as child, so that form_process_fieldset() processes
+  // this fieldset like any other fieldset.
+  $element['group'] = array(
+    '#type' => 'fieldset',
+    '#theme_wrappers' => array(),
+    '#parents' => $element['#parents'],
+  );
+
+  // The JavaScript stores the currently selected tab in this hidden
+  // field so that the active control can be restored the next time the
+  // form is rendered, e.g. on preview pages or when form validation
+  // fails.
+  $name = implode('__', $element['#parents']);
+  if (isset($form_state['values'][$name . '__active_control'])) {
+    $element['#default_tab'] = $form_state['values'][$name . '__active_control'];
+  }
+  $element[$name . '__active_control'] = array(
+    '#type' => 'hidden',
+    '#default_value' => $element['#default_control'],
+    '#attributes' => array('class' => array('multipage-active-control')),
+  );
+
+  return $element;
+}
+
+/**
+ * Returns HTML for an element's children fieldsets as multipage.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties and children of the
+ *     fieldset. Properties used: #children.
+ *
+ * @ingroup themeable
+ */
+function theme_multipage($variables) {
+  $element = $variables['element'];
+  // Add required JavaScript and Stylesheet.
+  drupal_add_library('field_group', 'multipage');
+
+  $output = '<h2 class="element-invisible">' . (!empty($element['#title']) ? $element['#title'] : t('Multipage')) . '</h2>';
+
+  $output .= '<div class="multipage-panes">';
+  $output .= $element['#children'];
+  $output .= '</div>';
+
+  return $output;
+}
+
+/**
+ * Returns HTML for multipage pane.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties and children of the
+ *     fieldset. Properties used: #children.
+ *
+ * @ingroup themeable
+ */
+function theme_multipage_pane($variables) {
+
+  $element = $variables['element'];
+  $group = $variables['element']['#group_object'];
+  $parent_group = $variables['element']['#parent_group_object'];
+
+  static $multipages;
+  if (!isset($multipages[$group->parent_name])) {
+    $multipages = array($group->parent_name => 0);
+  }
+  $multipages[$parent_group->group_name]++;
+
+  // Create a page title from the label.
+  $page_header = isset($parent_group->format_settings['instance_settings']['page_header']) ? $parent_group->format_settings['instance_settings']['page_header'] : 3;
+  switch ($page_header) {
+    case 1:
+      $title = $element['#title'];
+      break;
+    case 2:
+      $title = t('Step %count of %total', array('%count' => $multipages[$parent_group->group_name], '%total' => count($parent_group->children)));
+      break;
+    case 3:
+      $title = t('Step %count of %total !label', array('%count' => $multipages[$parent_group->group_name], '%total' => count($parent_group->children), '!label' => $element['#title']));
+      break;
+    case 0:
+    default:
+      $title = '';
+      break;
+  }
+
+  element_set_attributes($element, array('id'));
+  _form_set_class($element, array('form-wrapper'));
+
+  $output = '<div' . drupal_attributes($element['#attributes']) . '>';
+  if (!empty($element['#title'])) {
+    // Always wrap fieldset legends in a SPAN for CSS positioning.
+    $output .= '<h2 class="multipage-pane-title"><span>' . $title . '</span></h2>';
+  }
+  $output .= '<div class="fieldset-wrapper multipage-pane-wrapper">';
+  if (!empty($element['#description'])) {
+    $output .= '<div class="fieldset-description">' . $element['#description'] . '</div>';
+  }
+  $output .= $element['#children'];
+  if (isset($element['#value'])) {
+    $output .= $element['#value'];
+  }
+
+  // Add a page counter if needed.
+  // counter array(0 => t('No'), 1 => t('Format 1 / 10'), 2 => t('The count number only'));
+  $page_counter_format = isset($parent_group->format_settings['instance_settings']['page_counter']) ? $parent_group->format_settings['instance_settings']['page_counter'] : 1;
+  $multipage_element['#page_counter_rendered'] = '';
+  if ($page_counter_format == 1) {
+    $output .= t('<span class="multipage-counter">%count / %total</span>', array('%count' => $multipages[$parent_group->group_name], '%total' => count($parent_group->children)));
+  }
+  elseif ($page_counter_format == 2) {
+    $output .=  t('<span class="multipage-counter">%count</span>', array('%count' => $multipages[$parent_group->group_name]));
+  }
+
+  $output .= '</div>';
+  $output .= "</div>\n";
+
+  return $output;
+
+}
+
+/**
+ * Get all groups.
+ *
+ * @param $entity_type
+ *   The name of the entity.
+ * @param $bundle
+ *   The name of the bundle.
+ * @param $view_mode
+ *   The view mode.
+ * @param $reset.
+ *   Whether to reset the cache or not.
+ */
+function field_group_info_groups($entity_type = NULL, $bundle = NULL, $view_mode = NULL, $reset = FALSE) {
+  static $groups = FALSE;
+
+  if (!$groups || $reset) {
+    if (!$reset && $cached = cache_get('field_groups', 'cache_field')) {
+      $groups = $cached->data;
+    }
+    else {
+      drupal_static_reset('ctools_export_load_object');
+      drupal_static_reset('ctools_export_load_object_all');
+      $groups = field_group_read_groups();
+      cache_set('field_groups', $groups, 'cache_field');
+    }
+  }
+
+  if (!isset($entity_type)) {
+    return $groups;
+  }
+  elseif (!isset($bundle) && isset($groups[$entity_type])) {
+    return $groups[$entity_type];
+  }
+  elseif (!isset($view_mode) && isset($groups[$entity_type][$bundle])) {
+    return $groups[$entity_type][$bundle];
+  }
+  elseif (isset($groups[$entity_type][$bundle][$view_mode])) {
+    return $groups[$entity_type][$bundle][$view_mode];
+  }
+  return array();
+}
+
+/**
+ * Read all groups.
+ *
+ * @param $conditions
+ *   Parameters for the query
+ *   $name The name of the entity.
+ *   $bundle The name of the bundle.
+ *   $view_mode The view mode.
+ * @param $enabled
+ *   Return enabled or disabled groups.
+ */
+function field_group_read_groups($conditions = array(), $enabled = TRUE) {
+
+  $groups = array();
+  ctools_include('export');
+
+  if (empty($conditions)) {
+    $records = ctools_export_load_object('field_group');
+  }
+  else {
+    $records = ctools_export_load_object('field_group', 'conditions', $conditions);
+  }
+
+  foreach ($records as $group) {
+
+    // Return only enabled groups.
+    if ($enabled && isset($group->disabled) && $group->disabled) {
+      continue;
+    }
+    // Return only disabled groups.
+    elseif (!$enabled && (!isset($group->disabled) || !$group->disabled)) {
+      continue;
+    }
+
+    $groups[$group->entity_type][$group->bundle][$group->mode][$group->group_name] = field_group_unpack($group);
+
+  }
+  drupal_alter('field_group_info', $groups);
+  return $groups;
+
+}
+
+/**
+ * Utility function to recreate identifiers.
+ */
+function _field_group_recreate_identifiers() {
+
+  // Migrate the field groups so they have a unique identifier.
+  $result = db_select('field_group', 'fg')
+    ->fields('fg')
+    ->execute();
+  $rows = array();
+  foreach($result as $row) {
+    $row->identifier = $row->group_name . '|' . $row->entity_type . '|' . $row->bundle . '|' . $row->mode;
+    $row->data = unserialize($row->data);
+    $rows[] = $row;
+  }
+  foreach ($rows as $row) {
+    drupal_write_record('field_group', $row, array('id'));
+  }
+
+}
+
+/**
+ * Checks if a field_group exists in required context.
+ *
+ * @param String $group_name
+ *   The name of the group.
+ * @param String $entity_type
+ *   The name of the entity.
+ * @param String $bundle
+ *   The bundle for the entity.
+ * @param String $mode
+ *   The view mode context the group will be rendered.
+ */
+function field_group_exists($group_name, $entity_type, $bundle, $mode) {
+  $groups = field_group_read_groups();
+  return !empty($groups[$entity_type][$bundle][$mode][$group_name]);
+}
+
+/**
+ * Unpacks a database row in a FieldGroup object.
+ * @param $packed_group
+ *   Database result object with stored group data.
+ * @return $group
+ *   Field group object.
+ */
+function field_group_unpack($packed_group) {
+  if (!isset($packed_group->data)) {
+    return $packed_group;
+  }
+
+  // Extract unserialized data.
+  $group = clone $packed_group;
+  $data = $group->data;
+  unset($group->data);
+  $group->label = $data['label'];
+  $group->weight = $data['weight'];
+  $group->children = $data['children'];
+  $group->format_type = !empty($data['format_type']) ? $data['format_type'] : 'fieldset';
+  if (isset($data['format_settings'])) {
+    $group->format_settings = $data['format_settings'];
+  }
+
+  return $group;
+}
+
+/**
+ * Packs a FieldGroup object into a database row.
+ * @param $group
+ *   FieldGroup object.
+ * @return $record
+ *   Database row object, ready to be inserted/update
+ */
+function field_group_pack($group) {
+
+  $record = clone $group;
+  $record->data = array(
+    'label' => $record->label,
+    'weight' => $record->weight,
+    'children' => $record->children,
+    'format_type' => !empty($record->format_type) ? $record->format_type : 'fieldset',
+  );
+  if (isset($record->format_settings)) {
+    $record->data['format_settings'] = $record->format_settings;
+  }
+  return $record;
+}
+
+/**
+ * Delete a field group.
+ * This function is also called by ctools export when calls are
+ * made through ctools_export_crud_delete().
+ *
+ * @param $group
+ *   A group definition.
+ * @param $ctools_crud
+ *  Is this function called by the ctools crud delete.
+ */
+function field_group_group_export_delete($group, $ctools_crud = TRUE) {
+
+  $query = db_delete('field_group');
+
+  if (isset($group->identifier)) {
+    $query->condition('identifier', $group->identifier);
+    if (!$ctools_crud) {
+      ctools_export_crud_disable('field_group', $group->identifier);
+    }
+  }
+  elseif (isset($group->id)) {
+    $query->condition('id', $group->id);
+  }
+
+  if (!empty($group->mode)) {
+    $query->condition('mode', $group->mode);
+  }
+
+  $query->execute();
+
+  cache_clear_all('field_groups', 'cache_field');
+  module_invoke_all('field_group_delete_field_group', $group);
+
+}
+
+/**
+ * field_group_group_save().
+ *
+ * Saves a group definition.
+ * This function is called by ctools export when calls are made
+ * through ctools_export_crud_save().
+ *
+ * @param $group
+ *   A group definition.
+ */
+function field_group_group_save(& $group) {
+
+  // Prepare the record.
+  $object = field_group_pack($group);
+
+  if (isset($object->export_type) && $object->export_type & EXPORT_IN_DATABASE) {
+    // Existing record.
+    $update = array('id');
+    module_invoke_all('field_group_update_field_group', $object);
+  }
+  else {
+    // New record.
+    $update = array();
+    $object->export_type = EXPORT_IN_DATABASE;
+    module_invoke_all('field_group_create_field_group', $object);
+  }
+
+  return drupal_write_record('field_group', $object, $update);
+
+}
+
+/**
+ * Function to retrieve all format possibilities for the fieldgroups.
+ */
+function field_group_formatter_info($display_overview = FALSE) {
+  $cache = &drupal_static(__FUNCTION__, array());
+  if (empty($cache)) {
+    if ($cached = cache_get('field_group_formatter_info', 'cache_field')) {
+      $formatters = $cached->data;
+    }
+    else {
+      $formatters = array();
+      $formatters += module_invoke_all('field_group_formatter_info');
+      $hidden_region = array(
+        'label' => '<' . t('Hidden') . '>',
+        'description' => '',
+        'format_types' => array(),
+        'instance_settings' => array(),
+        'default_formatter' => '',
+      );
+      //$formatters['form']['hidden'] = $hidden_region;
+      $formatters['display']['hidden'] = $hidden_region;
+      cache_set('field_group_formatter_info', $formatters, 'cache_field');
+    }
+    $cache = $formatters;
+  }
+  return $cache;
+}
+
+/**
+ * Attach groups to the (form) build.
+ *
+ * @param Array $element
+ *   The part of the form.
+ * @param String $view_mode
+ *   The mode for the build.
+ * @param Array $form_state
+ *   The optional form state when in view_mode = form context.
+ */
+function field_group_attach_groups(&$element, $view_mode, $form_state = array()) {
+
+  $entity_type = $element['#entity_type'];
+  $bundle = $element['#bundle'];
+
+  $element['#groups'] = field_group_info_groups($entity_type, $bundle, $view_mode);
+  $element['#fieldgroups'] = $element['#groups'];
+
+  // Create a lookup array.
+  $group_children = array();
+  foreach ($element['#groups'] as $group_name => $group) {
+    foreach ($group->children as $child) {
+      $group_children[$child] = $group_name;
+    }
+  }
+  $element['#group_children'] = $group_children;
+
+}
+
+/**
+ * Pre render callback for rendering groups.
+ * @see field_group_field_attach_form
+ * @param $element Form that is beïng rendered.
+ */
+function field_group_form_pre_render(&$element) {
+  return field_group_build_entity_groups($element, 'form');
+}
+
+/**
+ * Preprocess/ Pre-render callback.
+ *
+ * @see field_group_form_pre_render()
+ * @see field_group_theme_registry_alter
+ * @see field_group_fields_nest()
+ * @param $vars preprocess vars or form element
+ * @param $type The type of object beïng rendered
+ * @return $element Array with re-arranged fields in forms.
+ */
+function field_group_build_entity_groups(&$vars, $type) {
+
+  if ($type == 'form') {
+    $element = &$vars;
+    $nest_vars = NULL;
+  }
+  else {
+    $element = &$vars['elements'];
+    $nest_vars = &$vars;
+  }
+
+  // No groups on the entity.
+  if (empty($element['#groups'])) {
+    return $element;
+  }
+
+  // Nest the fields in the corresponding field groups.
+  field_group_fields_nest($element, $nest_vars);
+
+  // Allow others to alter the pre_rendered build.
+  drupal_alter('field_group_build_pre_render', $element);
+
+  // Return the element on forms.
+  if ($type == 'form') {
+    return $element;
+  }
+
+  // Put groups inside content if we are rendering an entity_view.
+  foreach ($element['#groups'] as $group) {
+    if (!empty($element[$group->group_name])) {
+      $vars['content'][$group->group_name] = $element[$group->group_name];
+    }
+  }
+
+  // New css / js can be attached.
+  drupal_process_attached($element);
+}
+
+/**
+ * Recursive function to nest fields in the field groups.
+ *
+ * This function will take out all the elements in the form and
+ * place them in the correct container element, a fieldgroup.
+ * The current group element in the loop is passed recursively so we can
+ * stash fields and groups in it while we go deeper in the array.
+ * @param Array $element
+ *   The current element to analyse for grouping.
+ * @param Array $vars
+ *   Rendering vars from the entity beïng viewed.
+ */
+function field_group_fields_nest(&$element, &$vars = NULL) {
+
+  // Create all groups and keep a flat list of references to these groups.
+  $group_references = array();
+  foreach ($element['#groups'] as $group_name => $group) {
+    // Construct own weight, as some fields (for example preprocess fields) don't have weight set.
+    $element[$group_name] = array('#child_weight' => -20);
+    $group_references[$group_name] = &$element[$group_name];
+  }
+
+  // Loop through all form children looking for those that are supposed to be
+  // in groups, and insert placeholder element for the new group field in the
+  // correct location within the form structure.
+  $element_clone = array();
+  foreach (element_children($element) as $child_name) {
+    $element_clone[$child_name] = $element[$child_name];
+    // If this element is in a group, create the placeholder element.
+    if (isset($element['#group_children'][$child_name])) {
+      $element_clone[$element['#group_children'][$child_name]] = array();
+    }
+  }
+  $element = array_merge($element_clone, $element);
+
+  // Move all children to their parents. Use the flat list of references for
+  // direct access as we don't know where in the root_element hierarchy the
+  // parent currently is situated.
+  foreach ($element['#group_children'] as $child_name => $parent_name) {
+
+    // Entity beïng viewed
+    if ($vars) {
+      // If not a group, check vars['content'] for empty field.
+      if (!isset($element['#groups'][$child_name]) && isset($vars['content'][$child_name])) {
+        $group_references[$parent_name][$child_name] = $vars['content'][$child_name];
+        unset($vars['content'][$child_name]);
+      }
+      // If this is a group, we have to use a reference to keep the reference
+      // list intact (but if it is a field we don't mind).
+      else {
+        $group_references[$parent_name][$child_name] = &$element[$child_name];
+        unset($element[$child_name]);
+      }
+    }
+    // Form beïng viewed
+    else {
+
+      // Block denied fields (#access) before they are put in groups.
+      // Fields (not groups) that don't have children (like field_permissions) are removed
+      // in field_group_field_group_build_pre_render_alter.
+      if (isset($element[$child_name]) && (!isset($element[$child_name]['#access']) || $element[$child_name]['#access'])) {
+        // If this is a group, we have to use a reference to keep the reference
+        // list intact (but if it is a field we don't mind).
+        $group_references[$parent_name][$child_name] = &$element[$child_name];
+        $group_references[$parent_name]['#weight'] = $element['#groups'][$parent_name]->weight;
+      }
+
+      // The child has been copied to its parent: remove it from the root element.
+      unset($element[$child_name]);
+    }
+
+    // Set correct weight.
+    //$group_references[$parent_name][$child_name]['#weight'] = $group_references[$parent_name]['#child_weight'];
+    //$group_references[$parent_name]['#child_weight']++;
+  }
+
+  // Bring extra element wrappers to achieve a grouping of fields.
+  // This will mainly be prefix and suffix altering.
+  foreach ($element['#groups'] as $group_name => $group) {
+    field_group_pre_render($group_references[$group_name], $group, $element);
+  }
+
+}
+
+/**
+ * Function to pre render the field group element.
+ *
+ * @see field_group_fields_nest()
+ *
+ * @param $element Array of group element that needs to be created!
+ * @param $group Object with the group information.
+ * @param $form The form object itself.
+ */
+function field_group_pre_render(& $element, $group, & $form) {
+
+  // Only run the pre_render function if the group has elements.
+  // $group->group_name
+  if ($element == array()) {
+    return;
+  }
+
+  // Let modules define their wrapping element.
+  // Note that the group element has no properties, only elements.
+  foreach (module_implements('field_group_pre_render') as $module) {
+    $function = $module . '_field_group_pre_render';
+    if (function_exists($function)) {
+      // The intention here is to have the opportunity to alter the
+      // elements, as defined in hook_field_group_formatter_info.
+      // Note, implement $element by reference!
+      $function($element, $group, $form);
+    }
+  }
+
+  // Allow others to alter the pre_render.
+  drupal_alter('field_group_pre_render', $element, $group, $form);
+
+}
+
+/**
+ * Hides field groups including children in a render array.
+ *
+ * @param array $element
+ *   A render array. Can be a form, node, user, ...
+ * @param array $group_names
+ *   An array of field group names that should be hidden.
+ */
+function field_group_hide_field_groups(&$element, $group_names) {
+  foreach ($group_names as $group_name) {
+    if (isset($element['#fieldgroups'][$group_name]) && isset($element['#group_children'])) {
+      // Hide the field group.
+      $element['#fieldgroups'][$group_name]->format_type = 'hidden';
+      // Hide the elements inside the field group.
+      $sub_groups = array();
+      foreach (array_keys($element['#group_children'], $group_name) as $field_name) {
+        if (isset($element['#fieldgroups'][$field_name])) {
+          $sub_groups[] = $field_name;
+        } else {
+          $element[$field_name]['#access'] = FALSE;
+        }
+      }
+      field_group_hide_field_groups($element, $sub_groups);
+    }
+  }
+}
+
+/**
+ * Calculates html classes for a group.
+ */
+function _field_group_get_html_classes(&$group) {
+
+  if (isset($group->format_settings['formatter'])) {
+    $group->collapsible = in_array($group->format_settings['formatter'], array('collapsible', 'collapsed'));
+    // Open or closed horizontal or vertical tabs will be collapsible by default.
+    if ($group->format_type == 'tab' || $group->format_type == 'htab') {
+      $group->collapsible = TRUE;
+    }
+    $group->collapsed = in_array($group->format_settings['formatter'], array('collapsed', 'closed'));
+  }
+
+  $classes = new stdClass();
+
+  // Prepare extra classes, required and optional ones.
+  $optional = array(str_replace('_', '-', $group->group_name));
+  $required = array();
+  if ($group->format_type == 'multipage') {
+    $required[] = 'field-group-' . $group->format_type;
+  }
+  else {
+    $optional[] = 'field-group-' . $group->format_type;
+  }
+
+  if (isset($group->format_settings['formatter']) && $group->collapsible) {
+    $required[] = 'collapsible';
+    if ($group->collapsed) {
+      $required[] = 'collapsed';
+    }
+  }
+
+  if (isset($group->format_settings['instance_settings'])) {
+
+    // Add a required-fields class to trigger the js.
+    if (!empty($group->format_settings['instance_settings']['required_fields'])) {
+      $required[] = 'required-fields';
+    }
+
+    // Add user selected classes.
+    if (!empty($group->format_settings['instance_settings']['classes'])) {
+      $required[] = check_plain($group->format_settings['instance_settings']['classes']);
+    }
+
+    // Extra required classes for div.
+    if ($group->format_type == 'div') {
+      if (!empty($group->format_settings['instance_settings']['effect'])) {
+        $effect = $group->format_settings['instance_settings']['effect'];
+        // Only add effect class when an effect was selected.
+        if ($effect != 'none') {
+          $speed = isset($group->format_settings['instance_settings']['speed']) ? $group->format_settings['instance_settings']['speed'] : 'none';
+          $required[] = 'speed-' . $speed . 'effect-' . $effect;
+        }
+      }
+    }
+
+    // Extra required classes for accordions.
+    elseif ($group->format_type == 'accordion') {
+      $required[] = 'field-group-' . $group->format_type . '-wrapper';
+      $effect = isset($group->format_settings['instance_settings']['effect']) ? $group->format_settings['instance_settings']['effect'] : 'none';
+      $required[] = 'effect-' . $effect;
+    }
+
+  }
+
+  $classes->required = $required;
+  $classes->optional = $optional;
+
+  return $classes;
+}
+
+/**
+ * Get the default formatter settings for a given formatter and a mode.
+ */
+function _field_group_get_default_formatter_settings($format_type, $mode) {
+
+  $field_group_types = field_group_formatter_info();
+  $mode = $format_type == 'form' ? 'form' : 'display';
+  $formatter = $field_group_types[$mode][$format_type];
+
+  return array(
+    'formatter' => isset($formatter['default_formatter']) ? $formatter['default_formatter'] : '',
+    'instance_settings' => $formatter['instance_settings']
+  );
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/field_group.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,488 @@
+<?php
+
+/**
+ * @file
+ * Unit test file for groups.
+ *
+ * @todo - fill along if we know more.
+ *
+ * - nest a group under another group and see if parent_name is first group
+ * - nest a group under second group and see if parent_name is second group
+ * - settings: open f and verify on front-end (classes)
+ * - settings: collapsible f and verify on front-end (classes)
+ * - settings: collapsed f and verify on front-end (classes)
+ * - settings: vertical tabs and verify on front-end (classes)
+ * - settings: horizontal item and verify on front-end (classes)
+ * - settings: vertical item  and verify on front-end (classes)
+ * - settings: hidden (simple div) and verify on front-end (classes)
+ * - settings: label and verify on front-end
+ * - delete a fieldgroup - make sure we have a couple with the same name
+ *   and make sure the right one is deleted!
+ */
+
+/**
+ * Group UI tests.
+ */
+class GroupUITestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'UI tests',
+      'description' => 'Test the field group UI.',
+      'group' => 'Field group',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('field_test', 'field_group');
+
+    // Create test user.
+    $admin_user = $this->drupalCreateUser(array('administer content types', 'administer nodes', 'access administration pages', 'bypass node access'));
+    $this->drupalLogin($admin_user);
+  }
+
+  /**
+   * Test the creation a group on the article content type.
+   */
+  function createGroup() {
+
+    // Create random group name.
+    $this->group_label = $this->randomName(8);
+    $this->group_name_input = drupal_strtolower($this->randomName(8));
+    $this->group_name = 'group_' . $this->group_name_input;
+
+    // Setup new group.
+    $group = array(
+      'fields[_add_new_group][label]' => $this->group_label,
+      'fields[_add_new_group][group_name]' => $this->group_name_input,
+    );
+
+    // Add new group on the 'Manage fields' page.
+    $this->drupalPost('admin/structure/types/manage/article/fields', $group, t('Save'));
+
+    $this->assertRaw(t('New group %label successfully created.', array('%label' => $this->group_label)), t('Group message displayed on screen.'));
+
+    // Test if group is in the $groups array.
+    $groups = field_group_info_groups('node', 'article', 'form', TRUE);
+    $this->assertTrue(array_key_exists($this->group_name, $groups), t('Group found in groups array'));
+
+    // Add new group on the 'Manage display' page.
+    $this->drupalPost('admin/structure/types/manage/article/display', $group, t('Save'));
+    $this->assertRaw(t('New group %label successfully created.', array('%label' => $this->group_label)), t('Group message displayed on screen.'));
+
+    // Test if group is in the $groups array.
+    $groups = field_group_info_groups('node', 'article', 'default', TRUE);
+    $this->assertTrue(array_key_exists($this->group_name, $groups), t('Group found in groups array'));
+  }
+
+  /**
+   * Delete a group.
+   */
+  function deleteGroup() {
+
+    $this->drupalPost('admin/structure/types/manage/article/groups/' . $this->group_name . '/delete/form', array(), t('Delete'));
+    $this->assertRaw(t('The group %label has been deleted from the %article content type.', array('%label' => $this->group_label, '%article' => 'Article')), t('Group removal message displayed on screen.'));
+
+    // Test that group is not in the $groups array.
+    $groups = field_group_info_groups('node', 'article', 'form', TRUE);
+    $this->assertFalse(array_key_exists($this->group_name, $groups), t('Group not found in groups array while deleting'));
+
+    $this->drupalPost('admin/structure/types/manage/article/groups/' . $this->group_name . '/delete/default', array(), t('Delete'));
+    $this->assertRaw(t('The group %label has been deleted from the %article content type.', array('%label' => $this->group_label, '%article' => 'Article')), t('Group removal message displayed on screen.'));
+
+    // Test that group is not in the $groups array.
+    $groups = field_group_info_groups('node', 'article', 'default', TRUE);
+    $this->assertFalse(array_key_exists($this->group_name, $groups), t('Group not found in groups array while deleting'));
+  }
+
+  /**
+   * General CRUD.
+   */
+  function testCRUDGroup() {
+    $this->createGroup();
+    $this->deleteGroup();
+  }
+
+  /**
+   * Nest a field underneath a group.
+   */
+  function testNestField() {
+
+    $this->createGroup();
+
+    $edit = array(
+      'fields[field_image][parent]' => $this->group_name,
+    );
+    $this->drupalPost('admin/structure/types/manage/article/fields', $edit, t('Save'));
+    $this->assertRaw(t('Your settings have been saved.'), t('Settings saved'));
+
+    $groups = field_group_info_groups('node', 'article', 'form', TRUE);
+    $this->assertTrue(in_array('field_image', $groups[$this->group_name]->children), t('Image is a child of %group', array('%group' => $this->group_name)));
+  }
+
+}
+
+/**
+ * Group display tests
+ */
+class GroupDisplayTestCase extends DrupalWebTestCase {
+
+  protected $node;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Display tests',
+      'description' => 'Test the field group display.',
+      'group' => 'Field group',
+    );
+  }
+
+  function setUp() {
+
+    parent::setUp('field_test', 'field_group');
+
+    $node = new stdClass();
+    $node->type = 'article';
+    $node->title = $this->randomName();
+    $node->status = 1;
+
+    // Create test fields.
+    $test_fields = array('field_test', 'field_test_2');
+    foreach ($test_fields as $field_name) {
+
+      $field = array(
+        'field_name' => $field_name,
+        'type' => 'test_field',
+        'cardinality' => 1,
+      );
+      $instance = array(
+        'field_name' => $field_name,
+        'entity_type' => 'node',
+        'bundle' => 'article',
+        'label' => $this->randomName(),
+        'display' => array(
+          'default' => array(
+            'type' => 'field_test_default',
+            'settings' => array(
+              'test_formatter_setting' => $this->randomName(),
+            ),
+          ),
+          'teaser' => array(
+            'type' => 'field_test_default',
+            'settings' => array(
+              'test_formatter_setting' => $this->randomName(),
+            ),
+          ),
+        ),
+      );
+      field_create_field($field);
+      field_create_instance($instance);
+
+      $node->{$field_name}[LANGUAGE_NONE][0]['value'] = mt_rand(1, 127);
+    }
+
+    node_save($node);
+    $this->node = $node;
+  }
+
+  /**
+   * Create a new group.
+   * @param array $data
+   *   Data for the field group.
+   */
+  function createGroup($mode, array $data) {
+
+    $group_name = 'group_' . drupal_strtolower($this->randomName(8));
+    $identifier = $group_name . '|node|article|' . $mode;
+
+    $field_group = new stdClass;
+    $field_group->disabled = FALSE;
+    $field_group->api_version = 1;
+    $field_group->identifier = $identifier;
+    $field_group->group_name = $group_name;
+    $field_group->entity_type = 'node';
+    $field_group->bundle = 'article';
+    $field_group->mode = $mode;
+    $field_group->parent_name = '';
+    $field_group->children = $data['children'];
+    $field_group->data = $data;
+    drupal_write_record('field_group', $field_group);
+    ctools_export_crud_enable('field_group', $field_group->identifier);
+
+    return $field_group;
+  }
+
+  /**
+   * Test the div formatter.
+   */
+  function testDiv() {
+
+    $data = array(
+      'label' => 'Wrapper',
+      'weight' => '1',
+      'children' => array(
+        0 => 'field_test',
+      ),
+      'format_type' => 'div',
+      'format_settings' => array(
+        'label' => 'Link',
+        'instance_settings' => array(
+          'required_fields' => 0,
+          'id' => 'wrapper-id',
+          'classes' => 'test-class',
+          'description' => '',
+          'show_label' => FALSE,
+          'label_element' => 'h3',
+          'effect' => 'none',
+          'speed' => 'fast',
+        ),
+        'formatter' => 'open',
+      ),
+    );
+    $group = $this->createGroup('default', $data);
+
+    $groups = field_group_info_groups('node', 'article', 'default', TRUE);
+    $this->drupalGet('node/' . $this->node->nid);
+
+    // Test group ids and classes.
+    $this->assertRaw('id="wrapper-id"', t('Wrapper id set on wrapper div'));
+    $this->assertRaw('class="' . $group->group_name . ' test-class', t('Test class set on wrapper div') . 'class="' . $group->group_name . ' test-class');
+
+    // Test group label.
+    $this->assertNoRaw('<h3><span>' . $data['label'] . '</span></h3>', t('Label is not shown'));
+
+    // Set show label to true.
+    $group->data['format_settings']['instance_settings']['show_label'] = TRUE;
+    drupal_write_record('field_group', $group, array('identifier'));
+    $groups = field_group_info_groups('node', 'article', 'form', TRUE);
+    $this->drupalGet('node/' . $this->node->nid);
+    $this->assertRaw('<h3><span>' . $data['label'] . '</span></h3>', t('Label is shown'));
+  }
+
+  /**
+   * Test the horizontal tabs formatter.
+   */
+  function testHorizontalTabs() {
+
+    $data = array(
+      'label' => 'Tab 1',
+      'weight' => '1',
+      'children' => array(
+        0 => 'field_test',
+      ),
+      'format_type' => 'htab',
+      'format_settings' => array(
+        'label' => 'Tab 1',
+        'instance_settings' => array(
+          'classes' => 'test-class',
+          'description' => '',
+        ),
+        'formatter' => 'open',
+      ),
+    );
+    $first_tab = $this->createGroup('default', $data);
+    $first_tab_id = 'node_article_full_' . $first_tab->group_name;
+
+    $data = array(
+      'label' => 'Tab 2',
+      'weight' => '1',
+      'children' => array(
+        0 => 'field_test_2',
+      ),
+      'format_type' => 'htab',
+      'format_settings' => array(
+        'label' => 'Tab 1',
+        'instance_settings' => array(
+          'classes' => 'test-class-2',
+          'description' => 'description of second tab',
+        ),
+        'formatter' => 'closed',
+      ),
+    );
+    $second_tab = $this->createGroup('default', $data);
+    $second_tab_id = 'node_article_full_' . $first_tab->group_name;
+
+    $data = array(
+      'label' => 'Tabs',
+      'weight' => '1',
+      'children' => array(
+        0 => $first_tab->group_name,
+        1 => $second_tab->group_name,
+      ),
+      'format_type' => 'htabs',
+      'format_settings' => array(
+        'label' => 'Tab 1',
+        'instance_settings' => array(
+          'classes' => 'test-class-wrapper',
+        ),
+      ),
+    );
+    $tabs = $this->createGroup('default', $data);
+
+    $groups = field_group_info_groups('node', 'article', 'default', TRUE);
+
+    $this->drupalGet('node/' . $this->node->nid);
+
+    // Test properties.
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, t('Test class set on tabs wrapper'));
+    $this->assertFieldByXPath("//fieldset[contains(@class, 'test-class-2')]", NULL, t('Test class set on second tab'));
+    $this->assertRaw('<div class="fieldset-description">description of second tab</div>', t('Description of tab is shown'));
+    $this->assertRaw('class="collapsible collapsed test-class-2', t('Second tab is default collapsed'));
+
+    // Test if correctly nested
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@id, '$first_tab_id')]", NULL, 'First tab is displayed as child of the wrapper.');
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@id, '$second_tab_id')]", NULL, 'Second tab is displayed as child of the wrapper.');
+
+  }
+
+  /**
+   * Test the vertical tabs formatter.
+   */
+  function testVerticalTabs() {
+
+    $data = array(
+      'label' => 'Tab 1',
+      'weight' => '1',
+      'children' => array(
+        0 => 'field_test',
+      ),
+      'format_type' => 'tab',
+      'format_settings' => array(
+        'label' => 'Tab 1',
+        'instance_settings' => array(
+          'classes' => 'test-class',
+          'description' => '',
+        ),
+        'formatter' => 'open',
+      ),
+    );
+    $first_tab = $this->createGroup('default', $data);
+    $first_tab_id = 'node_article_full_' . $first_tab->group_name;
+
+    $data = array(
+      'label' => 'Tab 2',
+      'weight' => '1',
+      'children' => array(
+        0 => 'field_test_2',
+      ),
+      'format_type' => 'tab',
+      'format_settings' => array(
+        'label' => 'Tab 1',
+        'instance_settings' => array(
+          'classes' => 'test-class-2',
+          'description' => 'description of second tab',
+        ),
+        'formatter' => 'closed',
+      ),
+    );
+    $second_tab = $this->createGroup('default', $data);
+    $second_tab_id = 'node_article_full_' . $first_tab->group_name;
+
+    $data = array(
+      'label' => 'Tabs',
+      'weight' => '1',
+      'children' => array(
+        0 => $first_tab->group_name,
+        1 => $second_tab->group_name,
+      ),
+      'format_type' => 'tabs',
+      'format_settings' => array(
+        'label' => 'Tab 1',
+        'instance_settings' => array(
+          'classes' => 'test-class-wrapper',
+        ),
+      ),
+    );
+    $tabs = $this->createGroup('default', $data);
+
+    $groups = field_group_info_groups('node', 'article', 'default', TRUE);
+
+    $this->drupalGet('node/' . $this->node->nid);
+
+    // Test properties.
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, t('Test class set on tabs wrapper'));
+    $this->assertFieldByXPath("//fieldset[contains(@class, 'test-class-2')]", NULL, t('Test class set on second tab'));
+    $this->assertRaw('<div class="fieldset-description">description of second tab</div>', t('Description of tab is shown'));
+    $this->assertRaw('class="collapsible collapsed test-class-2', t('Second tab is default collapsed'));
+
+    // Test if correctly nested
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@id, '$first_tab_id')]", NULL, 'First tab is displayed as child of the wrapper.');
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//fieldset[contains(@id, '$second_tab_id')]", NULL, 'Second tab is displayed as child of the wrapper.');
+  }
+
+  /**
+   * Test the accordion formatter.
+   */
+  function testAccordion() {
+
+    $data = array(
+      'label' => 'Accordion item 1',
+      'weight' => '1',
+      'children' => array(
+        0 => 'field_test',
+      ),
+      'format_type' => 'accordion-item',
+      'format_settings' => array(
+        'label' => 'Accordion item 1',
+        'instance_settings' => array(
+          'classes' => 'test-class',
+        ),
+        'formatter' => 'closed',
+      ),
+    );
+    $first_item = $this->createGroup('default', $data);
+    $first_item_id = 'node_article_full_' . $first_item->group_name;
+
+    $data = array(
+      'label' => 'Accordion item 2',
+      'weight' => '1',
+      'children' => array(
+        0 => 'field_test_2',
+      ),
+      'format_type' => 'accordion-item',
+      'format_settings' => array(
+        'label' => 'Tab 2',
+        'instance_settings' => array(
+          'classes' => 'test-class-2',
+        ),
+        'formatter' => 'open',
+      ),
+    );
+    $second_item = $this->createGroup('default', $data);
+    $second_item_id = 'node_article_full_' . $second_item->group_name;
+
+    $data = array(
+      'label' => 'Accordion',
+      'weight' => '1',
+      'children' => array(
+        0 => $first_item->group_name,
+        1 => $second_item->group_name,
+      ),
+      'format_type' => 'accordion',
+      'format_settings' => array(
+        'label' => 'Tab 1',
+        'instance_settings' => array(
+          'classes' => 'test-class-wrapper',
+          'effect' => 'bounceslide'
+        ),
+      ),
+    );
+    $accordion = $this->createGroup('default', $data);
+
+    $groups = field_group_info_groups('node', 'article', 'default', TRUE);
+
+    $this->drupalGet('node/' . $this->node->nid);
+
+    // Test properties.
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]", NULL, t('Test class set on tabs wrapper'));
+    $this->assertFieldByXPath("//div[contains(@class, 'effect-bounceslide')]", NULL, t('Correct effect is set on the accordion'));
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class')]", NULL, t('Accordion item with test-class is shown'));
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-2')]", NULL, t('Accordion item with test-class-2 is shown'));
+    $this->assertFieldByXPath("//h3[contains(@class, 'field-group-accordion-active')]", NULL, t('Accordion item 2 was set active'));
+
+    // Test if correctly nested
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class')]", NULL, 'First item is displayed as child of the wrapper.');
+    $this->assertFieldByXPath("//div[contains(@class, 'test-class-wrapper')]//div[contains(@class, 'test-class-2')]", NULL, 'Second item is displayed as child of the wrapper.');
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/horizontal-tabs/horizontal-tabs-rtl.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+div.horizontal-tabs {
+  margin: 0 0 1em 0;
+}
+
+.horizontal-tabs ul.horizontal-tabs-list {
+  border-right: 0;
+  border-left: 1px solid #dedede;
+}
+
+/* Layout of each tab */
+.horizontal-tabs ul.horizontal-tabs-list li {
+  border-right: 0;
+  border-left: 1px solid #ccc;
+  float: right;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/horizontal-tabs/horizontal-tabs.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,101 @@
+div.horizontal-tabs {
+  margin: 0 0 1em 0; /* LTR */
+  padding: 0;
+  border: 1px solid #ccc;
+  position: relative; /* IE6/7 */
+}
+
+.horizontal-tabs ul.horizontal-tabs-list {
+  display: inline-block;
+  margin: 0;
+  border: 0;
+  padding: 0px;
+  position: relative; /* IE6 */
+  list-style: none;
+  list-style-image: none; /* IE6 */
+  background-color: #dedede;
+  border-right: 1px solid #dedede; /* LTR */
+  width: 100%;
+  height: auto;
+  clear: both;
+}
+
+.horizontal-tabs fieldset.horizontal-tabs-pane {
+  padding: 0 1em;
+  border: 0;
+}
+
+fieldset.horizontal-tabs-pane > legend,
+fieldset.vertical-tabs-pane fieldset.horizontal-tabs-pane > legend {
+  display: none;
+}
+
+/* Layout of each tab */
+.horizontal-tabs ul.horizontal-tabs-list li {
+  background: #eee;
+  border-right: 1px solid #ccc; /* LTR */
+  padding: 1px;
+  padding-top: 0;
+  margin: 0;
+  min-width: 5em; /* IE7 */
+  float: left; /* LTR */
+}
+.horizontal-tabs ul.horizontal-tabs-list li.selected {
+  background-color: #fff;
+  padding: 0 0 1px 0;
+}
+.horizontal-tabs ul.horizontal-tabs-list li a {
+  display: block;
+  text-decoration: none;
+  padding: 0.5em 0.6em;
+}
+.horizontal-tabs ul.horizontal-tabs-list li a:hover {
+  outline: none;
+  background-color: #ededdd;
+}
+.horizontal-tabs ul.horizontal-tabs-list li:hover,
+.horizontal-tabs ul.horizontal-tabs-list li:focus {
+  background-color: #ddd;
+}
+.horizontal-tabs ul.horizontal-tabs-list :focus {
+  outline: none;
+}
+.horizontal-tabs ul.horizontal-tabs-list li a:focus strong,
+.horizontal-tabs ul.horizontal-tabs-list li a:active strong,
+.horizontal-tabs ul.horizontal-tabs-list li a:hover strong {
+  text-decoration: none;
+  outline: none;
+}
+.horizontal-tabs ul.horizontal-tabs-list li a,
+.horizontal-tabs ul.horizontal-tabs-list li.selected a {
+  display: block;
+  text-decoration: none;
+  padding: 0.5em 0.6em 0.3em 0.6em;
+  position:relative;
+  top: 0px;
+}
+.horizontal-tabs ul.horizontal-tabs-list .selected strong {
+  color: #000;
+}
+.horizontal-tabs ul.horizontal-tabs-list .summary {
+  display: block;
+}
+.horizontal-tabs ul.horizontal-tabs ul.horizontal-tabs-list .summary {
+  line-height: normal;
+  margin-bottom: 0;
+}
+
+/**
+ * tab content
+ */
+div.field-group-htabs-wrapper .field-group-format-wrapper {
+  clear: both;
+  padding: 0 0 0.6em;
+}
+/*hide*/
+.horizontal-tabs .horizontal-tab-hidden {
+  display: block;
+  position: absolute;
+  top: -100000px;
+  width: 100%;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/horizontal-tabs/horizontal-tabs.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,197 @@
+(function ($) {
+
+/**
+ * This script transforms a set of fieldsets into a stack of horizontal
+ * tabs. Another tab pane can be selected by clicking on the respective
+ * tab.
+ *
+ * Each tab may have a summary which can be updated by another
+ * script. For that to work, each fieldset has an associated
+ * 'horizontalTabCallback' (with jQuery.data() attached to the fieldset),
+ * which is called every time the user performs an update to a form
+ * element inside the tab pane.
+ */
+Drupal.behaviors.horizontalTabs = {
+  attach: function (context) {
+    $('.horizontal-tabs-panes', context).once('horizontal-tabs', function () {
+      var focusID = $(':hidden.horizontal-tabs-active-tab', this).val();
+      var tab_focus;
+
+      // Check if there are some fieldsets that can be converted to horizontal-tabs
+      var $fieldsets = $('> fieldset', this);
+      if ($fieldsets.length == 0) {
+        return;
+      }
+
+      // Create the tab column.
+      var tab_list = $('<ul class="horizontal-tabs-list"></ul>');
+      $(this).wrap('<div class="horizontal-tabs clearfix"></div>').before(tab_list);
+
+      // Transform each fieldset into a tab.
+      $fieldsets.each(function (i) {
+        var horizontal_tab = new Drupal.horizontalTab({
+          title: $('> legend', this).text(),
+          fieldset: $(this)
+        });
+        horizontal_tab.item.addClass('horizontal-tab-button-' + i);
+        tab_list.append(horizontal_tab.item);
+        $(this)
+          .removeClass('collapsible collapsed')
+          .addClass('horizontal-tabs-pane')
+          .data('horizontalTab', horizontal_tab);
+        if (this.id == focusID) {
+          tab_focus = $(this);
+        }
+      });
+
+      $('> li:first', tab_list).addClass('first');
+      $('> li:last', tab_list).addClass('last');
+
+      if (!tab_focus) {
+        // If the current URL has a fragment and one of the tabs contains an
+        // element that matches the URL fragment, activate that tab.
+        if (window.location.hash && $(window.location.hash, this).length) {
+          tab_focus = $(window.location.hash, this).closest('.horizontal-tabs-pane');
+        }
+        else {
+          tab_focus = $('> .horizontal-tabs-pane:first', this);
+        }
+      }
+      if (tab_focus.length) {
+        tab_focus.data('horizontalTab').focus();
+      }
+    });
+  }
+};
+
+/**
+ * The horizontal tab object represents a single tab within a tab group.
+ *
+ * @param settings
+ *   An object with the following keys:
+ *   - title: The name of the tab.
+ *   - fieldset: The jQuery object of the fieldset that is the tab pane.
+ */
+Drupal.horizontalTab = function (settings) {
+  var self = this;
+  $.extend(this, settings, Drupal.theme('horizontalTab', settings));
+
+  this.link.click(function () {
+    self.focus();
+    return false;
+  });
+
+  // Keyboard events added:
+  // Pressing the Enter key will open the tab pane.
+  this.link.keydown(function(event) {
+    if (event.keyCode == 13) {
+      self.focus();
+      // Set focus on the first input field of the visible fieldset/tab pane.
+      $("fieldset.horizontal-tabs-pane :input:visible:enabled:first").focus();
+      return false;
+    }
+  });
+
+  this.fieldset
+    .bind('summaryUpdated', function () {
+      self.updateSummary();
+    })
+    .trigger('summaryUpdated');
+};
+
+Drupal.horizontalTab.prototype = {
+  /**
+   * Displays the tab's content pane.
+   */
+  focus: function () {
+    this.fieldset
+      .removeClass('horizontal-tab-hidden')
+      .siblings('fieldset.horizontal-tabs-pane')
+        .each(function () {
+          var tab = $(this).data('horizontalTab');
+          tab.fieldset.addClass('horizontal-tab-hidden');
+          tab.item.removeClass('selected');
+        })
+        .end()
+      .siblings(':hidden.horizontal-tabs-active-tab')
+        .val(this.fieldset.attr('id'));
+    this.item.addClass('selected');
+    // Mark the active tab for screen readers.
+    $('#active-horizontal-tab').remove();
+    this.link.append('<span id="active-horizontal-tab" class="element-invisible">' + Drupal.t('(active tab)') + '</span>');
+  },
+
+  /**
+   * Updates the tab's summary.
+   */
+  updateSummary: function () {
+    this.summary.html(this.fieldset.drupalGetSummary());
+  },
+
+  /**
+   * Shows a horizontal tab pane.
+   */
+  tabShow: function () {
+    // Display the tab.
+    this.item.removeClass('horizontal-tab-hidden');
+    // Update .first marker for items. We need recurse from parent to retain the
+    // actual DOM element order as jQuery implements sortOrder, but not as public
+    // method.
+    this.item.parent().children('.horizontal-tab-button').removeClass('first')
+      .filter(':visible:first').addClass('first');
+    // Display the fieldset.
+    this.fieldset.removeClass('horizontal-tab-hidden');
+    // Focus this tab.
+    this.focus();
+    return this;
+  },
+
+  /**
+   * Hides a horizontal tab pane.
+   */
+  tabHide: function () {
+    // Hide this tab.
+    this.item.addClass('horizontal-tab-hidden');
+    // Update .first marker for items. We need recurse from parent to retain the
+    // actual DOM element order as jQuery implements sortOrder, but not as public
+    // method.
+    this.item.parent().children('.horizontal-tab-button').removeClass('first')
+      .filter(':visible:first').addClass('first');
+    // Hide the fieldset.
+    this.fieldset.addClass('horizontal-tab-hidden');
+    // Focus the first visible tab (if there is one).
+    var $firstTab = this.fieldset.siblings('.horizontal-tabs-pane:not(.horizontal-tab-hidden):first');
+    if ($firstTab.length) {
+      $firstTab.data('horizontalTab').focus();
+    }
+    return this;
+  }
+};
+
+/**
+ * Theme function for a horizontal tab.
+ *
+ * @param settings
+ *   An object with the following keys:
+ *   - title: The name of the tab.
+ * @return
+ *   This function has to return an object with at least these keys:
+ *   - item: The root tab jQuery element
+ *   - link: The anchor tag that acts as the clickable area of the tab
+ *       (jQuery version)
+ *   - summary: The jQuery element that contains the tab summary
+ */
+Drupal.theme.prototype.horizontalTab = function (settings) {
+  var tab = {};
+  var idAttr = settings.fieldset.attr('id');
+
+  tab.item = $('<li class="horizontal-tab-button" tabindex="-1"></li>')
+    .append(tab.link = $('<a href="#' + idAttr + '"></a>')
+      .append(tab.title = $('<strong></strong>').text(settings.title))
+      .append(tab.summary = $('<span class="summary"></span>')
+    )
+  );
+  return tab;
+};
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/multipage/multipage-rtl.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+.multipage-controls-list #edit-actions {
+  float: right !important;
+}
+
+.multipage-button {    
+  float: right !important;
+}
+
+.multipage-counter{
+  float: left !important;
+  margin-right: 0 !important;
+  margin-left: 5px !important;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/multipage/multipage.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,128 @@
+.multipage-controls-list #edit-actions {
+  float: left; /* LTR */
+}
+
+.multipage-button {    
+  margin-bottom: 1em;
+  margin-top: 0;
+  float: left; /* LTR */
+  line-height: 36px;
+}
+
+.multipage-button a {    
+  padding-top: 10px;
+}
+
+.multipage-counter {
+  float: right; /* LTR */
+  margin-right: 5px; /* LTR */
+  height: 0;
+  position: relative;
+  top: 1.8em;
+  line-height: 30px;
+  font: 12px arial,sans-serif;
+  font-weight: bold;
+  color:#666;
+}
+
+a.multipage-link-previous {
+  font: 12px arial,sans-serif;
+  font-weight: bold;
+  color:#666;
+  -webkit-transition: color 218ms;
+  -moz-transition: color 218ms;
+  -o-transition: color 218ms;
+  transition: color 218ms;
+}
+
+a.multipage-link-previous:hover {
+  text-decoration:none;
+  color: #333;
+}
+
+.multipage-controls-list input.form-submit {
+  background:none;
+  border: none;
+  border-radius: 2px;
+  -moz-border-radius: 2px;
+  -webkit-border-radius: 2px;
+  border: 1px solid rgba(0, 0, 0, 0.1);
+  font: 12px arial,sans-serif;
+  font-weight: bold;
+  color: #666;
+  text-shadow: 0 1px 0 white;
+  padding: 7px 12px;
+  background: -webkit-gradient(linear,0% 40%,0% 70%,from(whiteSmoke),to(#F1F1F1));
+  -o-transition: border-top-color 0.218s,border-right-color 0.218s,border-bottom-color 0.218s,border-left-color .218s;
+  -webkit-transition: border-color .218s;
+}
+
+.multipage-controls-list input.form-submit:hover {
+  color:#333;
+  box-shadow: 0 1px 1px rgba(0,0,0,0.1);
+  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.1);
+  border-color: #939393;
+}
+
+.multipage-controls-list input.form-submit:active {
+  background: -webkit-gradient(linear,0% 40%,0% 70%,from(#F1F1F1),to(whiteSmoke));
+}
+
+.multipage-controls-list input#edit-submit {
+  background: #4D90FE; /* for non-css3 browsers */
+  background-image: #4D90FE; /* for non-css3 browsers */
+  background-image: -o-linear-gradient(top,#4d90fe,#4787ed);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4D90FE', endColorstr='#4787ED'); /* for IE */
+  background: -webkit-gradient(linear, center top, center bottom, from(#4D90FE), to(#4787ED)); /* for webkit browsers */
+  background: -moz-linear-gradient(center top,  #4D90FE,  #4787ED); /* for firefox 3.6+ */ 
+  color: white;
+  text-shadow: none;
+  text-transform: uppercase;
+  min-width: 79px;
+}
+
+.multipage-controls-list input#edit-submit:hover {
+  background-image: -moz-linear-gradient(top,#4d90fe,#357ae8);
+  background-image: -o-linear-gradient(top,#4d90fe,#357ae8);
+  background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#357ae8));
+  color: white;
+  text-shadow: none;
+  box-shadow: 0 1px 1px rgba(0,0,0,0.2);
+  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.2);
+}
+
+.multipage-controls-list input#edit-submit:active {
+  background: #4D90FE;
+  border-color: #2F5BB7;
+}
+
+.multipage-controls-list input#edit-delete {
+  background-image: -moz-linear-gradient(top,#dd4b39,#d14836);
+  background-image: -o-linear-gradient(top,#dd4b39,#d14836);
+  background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836));
+  text-shadow: 0 1px rgba(0, 0, 0, 0.1);
+  border: 1px solid transparent;
+  color: white;
+  text-shadow: none;
+
+}
+
+.multipage-controls-list input#edit-delete:hover {
+  background-image: -moz-linear-gradient(top,#dd4b39,#c53727);
+  background-image: -o-linear-gradient(top,#dd4b39,#c53727);
+  background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#c53727));
+  border: 1px solid #B0281A!important;
+  border-bottom: 1px solid #AF301F!important;
+  box-shadow: 0 1px 1px rgba(0,0,0,0.2);
+  -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.2);
+  color: white;
+}
+
+.multipage-controls-list input#edit-delete:active {
+  background-image: -moz-linear-gradient(top,#dd4b39,#b0281a);
+  background-image: -o-linear-gradient(top,#dd4b39,#b0281a);
+  background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#b0281a));
+  border: 1px solid #992A1b!important;
+  box-shadow: 0 1px 2px rgba(0,0,0,0.3);
+  -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.3);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/field_group/multipage/multipage.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,268 @@
+(function ($) {
+
+/**
+ * This script transforms a set of wrappers into a stack of multipage pages. 
+ * Another pane can be entered by clicking next/previous.
+ *
+ */
+Drupal.behaviors.MultiPage = {
+  attach: function (context) {
+    $('.multipage-panes', context).once('multipage', function () {
+
+      var focusID = $(':hidden.multipage-active-control', this).val();
+      var paneWithFocus;
+
+      // Check if there are some wrappers that can be converted to multipages.
+      var $panes = $('> div.field-group-multipage', this);
+      var $form = $panes.parents('form');
+      if ($panes.length == 0) {
+        return;
+      }
+
+      // Create the next/previous controls.
+      var $controls;
+
+      // Transform each div.multipage-pane into a multipage with controls.
+      $panes.each(function () {
+        
+        $controls = $('<div class="multipage-controls-list clearfix"></div>');
+        $(this).append($controls);
+        
+        // Check if the submit button needs to move to the latest pane.
+        if (Drupal.settings.field_group.multipage_move_submit && $('.form-actions').length) {
+          $('.form-actions', $form).remove().appendTo($($controls, $panes.last()));
+        }
+        
+        var multipageControl = new Drupal.multipageControl({
+          title: $('> .multipage-pane-title', this).text(),
+          wrapper: $(this),
+          has_next: $(this).next().length,
+          has_previous: $(this).prev().length
+        });
+        
+        $controls.append(multipageControl.item);
+        $(this)
+          .addClass('multipage-pane')
+          .data('multipageControl', multipageControl);
+
+        if (this.id == focusID) {
+          paneWithFocus = $(this);
+        }
+        
+      });
+
+      if (paneWithFocus === undefined) {
+        // If the current URL has a fragment and one of the tabs contains an
+        // element that matches the URL fragment, activate that tab.
+        if (window.location.hash && $(window.location.hash, this).length) {
+          paneWithFocus = $(window.location.hash, this).closest('.multipage-pane');
+        }
+        else {
+          paneWithFocus = $('multipage-open', this).length ? $('multipage-open', this) : $('> .multipage-pane:first', this);
+        }
+      }
+      if (paneWithFocus !== undefined) {
+        paneWithFocus.data('multipageControl').focus();
+      }
+    });
+  }
+};
+
+/**
+ * The multipagePane object represents a single div as a page.
+ *
+ * @param settings
+ *   An object with the following keys:
+ *   - title: The name of the tab.
+ *   - wrapper: The jQuery object of the <div> that is the tab pane.
+ */
+Drupal.multipageControl = function (settings) {
+  var self = this;
+  var controls = Drupal.theme('multipage', settings);
+  $.extend(self, settings, controls);
+
+  this.nextLink.click(function () {
+    self.nextPage();
+    return false;
+  });
+  
+  this.previousLink.click(function () {
+    self.previousPage();
+    return false;
+  });
+  
+/*
+  // Keyboard events added:
+  // Pressing the Enter key will open the tab pane.
+  this.nextLink.keydown(function(event) {
+    if (event.keyCode == 13) {
+      self.focus();
+      // Set focus on the first input field of the visible wrapper/tab pane.
+      $("div.multipage-pane :input:visible:enabled:first").focus();
+      return false;
+    }
+  });
+
+  // Pressing the Enter key lets you leave the tab again.
+  this.wrapper.keydown(function(event) {
+    // Enter key should not trigger inside <textarea> to allow for multi-line entries.
+    if (event.keyCode == 13 && event.target.nodeName != "TEXTAREA") {
+      // Set focus on the selected tab button again.
+      $(".multipage-tab-button.selected a").focus();
+      return false;
+    }
+  });
+*/
+};
+
+Drupal.multipageControl.prototype = {
+    
+  /**
+   * Displays the tab's content pane.
+   */
+  focus: function () {
+    this.wrapper
+      .show()
+      .siblings('div.multipage-pane')
+        .each(function () {
+          var tab = $(this).data('multipageControl');
+          tab.wrapper.hide();
+        })
+        .end()
+      .siblings(':hidden.multipage-active-control')
+        .val(this.wrapper.attr('id'));
+    // Mark the active control for screen readers.
+    $('#active-multipage-control').remove();
+    this.nextLink.after('<span id="active-multipage-control" class="element-invisible">' + Drupal.t('(active page)') + '</span>');
+  },
+  
+  /**
+   * Continues to the next page or step in the form.
+   */
+  nextPage: function () {
+    this.wrapper.next().data('multipageControl').focus();
+    $('html, body').scrollTop(this.wrapper.parents('.field-group-multipage-group-wrapper').offset().top);
+  },
+  
+  /**
+   * Returns to the previous page or step in the form.
+   */
+  previousPage: function () {
+    this.wrapper.prev().data('multipageControl').focus();
+    $('html, body').scrollTop(this.wrapper.parents('.field-group-multipage-group-wrapper').offset().top);
+  },
+
+  /**
+   * Shows a horizontal tab pane.
+   */
+  tabShow: function () {
+    // Display the tab.
+    this.item.show();
+    // Update .first marker for items. We need recurse from parent to retain the
+    // actual DOM element order as jQuery implements sortOrder, but not as public
+    // method.
+    this.item.parent().children('.multipage-control').removeClass('first')
+      .filter(':visible:first').addClass('first');
+    // Display the wrapper.
+    this.wrapper.removeClass('multipage-control-hidden').show();
+    // Focus this tab.
+    this.focus();
+    return this;
+  },
+
+  /**
+   * Hides a horizontal tab pane.
+   */
+  tabHide: function () {
+    // Hide this tab.
+    this.item.hide();
+    // Update .first marker for items. We need recurse from parent to retain the
+    // actual DOM element order as jQuery implements sortOrder, but not as public
+    // method.
+    this.item.parent().children('.multipage-control').removeClass('first')
+      .filter(':visible:first').addClass('first');
+    // Hide the wrapper.
+    this.wrapper.addClass('horizontal-tab-hidden').hide();
+    // Focus the first visible tab (if there is one).
+    var $firstTab = this.wrapper.siblings('.multipage-pane:not(.multipage-control-hidden):first');
+    if ($firstTab.length) {
+      $firstTab.data('multipageControl').focus();
+    }
+    return this;
+  }
+};
+
+/**
+ * Theme function for a multipage control.
+ *
+ * @param settings
+ *   An object with the following keys:
+ *   - title: The name of the tab.
+ * @return
+ *   This function has to return an object with at least these keys:
+ *   - item: The root tab jQuery element
+ *   - nextLink: The anchor tag that acts as the clickable area of the control
+ *   - nextTitle: The jQuery element that contains the group title
+ *   - previousLink: The anchor tag that acts as the clickable area of the control
+ *   - previousTitle: The jQuery element that contains the group title
+ */
+Drupal.theme.prototype.multipage = function (settings) {
+
+  var controls = {};
+  controls.item = $('<span class="multipage-button"></span>');
+  
+  controls.previousLink = $('<input type="button" class="form-submit multipage-link-previous" value="" />');
+  controls.previousTitle = Drupal.t('Previous page');
+  controls.item.append(controls.previousLink.val(controls.previousTitle));  
+  
+  controls.nextLink = $('<input type="button" class="form-submit multipage-link-next" value="" />');
+  controls.nextTitle = Drupal.t('Next page');
+  controls.item.append(controls.nextLink.val(controls.nextTitle));
+  
+  if (!settings.has_next) {
+    controls.nextLink.hide();
+  }
+  if (!settings.has_previous) {
+    controls.previousLink.hide();
+  }
+  
+  return controls;
+};
+
+
+Drupal.FieldGroup = Drupal.FieldGroup || {};
+Drupal.FieldGroup.Effects = Drupal.FieldGroup.Effects || {};
+
+/**
+ * Implements Drupal.FieldGroup.processHook().
+ */
+Drupal.FieldGroup.Effects.processMultipage = {
+  execute: function (context, settings, type) {
+    if (type == 'form') {
+      
+      var $firstErrorItem = false;
+      
+      // Add required fields mark to any element containing required fields
+      $('div.multipage-pane').each(function(i){
+        if ($('.error', $(this)).length) {
+          
+          // Save first error item, for focussing it.
+          if (!$firstErrorItem) {
+            $firstErrorItem = $(this).data('multipageControl');
+          }          
+          
+          Drupal.FieldGroup.setGroupWithfocus($(this));
+          $(this).data('multipageControl').focus();
+        }
+      });
+
+      // Focus on first multipage that has an error.
+      if ($firstErrorItem) {
+        $firstErrorItem.focus();
+      }
+      
+    }
+  }
+}
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/github/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/github/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,3 @@
+#GitHub
+
+**Display ribbon on page that links to your GitHub-user**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/github/github.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,91 @@
+<?php
+/**
+ * @file
+ * Module settings.
+ */
+
+/**
+ * Menu callback. Displays the administration settings.
+ */
+function github_admin_settings() {
+  $form = array();
+
+  $form['settings'] = array(
+    '#type' => 'vertical_tabs',
+    '#weight' => 50,
+  );
+
+  $form['details'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Your Details'),
+    '#group' => 'settings',
+  );
+
+  $form['details']['github_username'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Your Github username'),
+    '#description' => t('Your GitHub username - required to determine the link to your profile'),
+    '#default_value' => variable_get('github_username', ''),
+    '#required' => TRUE,
+  );
+
+  $form['appearance'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Appearance'),
+    '#group' => 'settings',
+  );
+
+  $form['appearance']['github_placement'] = array(
+    '#type' => 'select',
+    '#options' => array('left' => t('Left'), 'right' => t('Right')),
+    '#title' => t('Placement'),
+    '#description' => t('Which side should the ribbon be placed on'),
+    '#default_value' => variable_get('github_placement', 'right'),
+    '#required' => TRUE,
+  );
+
+  $form['appearance']['github_colour'] = array(
+    '#type' => 'select',
+    '#options' => array(
+      'red' => t('Red'),
+      'green' => t('Green'),
+      'darkblue' => t('Dark Blue'),
+      'orange' => t('Orange'),
+      'grey' => t('Grey'),
+      'white' => t('White'),
+    ),
+    '#title' => t('Colour'),
+    '#description' => t('Which color should the ribbon have'),
+    '#default_value' => variable_get('github_colour', 'red'),
+    '#required' => TRUE,
+  );
+
+  $theme_regions = system_region_list('lndesign_theme', 'REGIONS_ALL');
+  $system_regions = array(
+    'page_top' => 'Page top',
+    'header' => 'Header',
+    'sidebar_first' => 'Sidebar First',
+    'sidebar_second' => 'Sidebar Second',
+    'page_bottom' => 'Page bottom',
+  );
+
+  // Merge arrays and remove dublicates
+  $region_array = array_unique(array_merge($system_regions, $theme_regions));
+  
+  // Find content position in array
+  $content_pos = array_search('Content', $region_array);
+  // Remove content from array
+  if ($content_pos) {
+    unset($region_array[$content_pos]);
+  }
+
+  $form['appearance']['github_page_block'] = array(
+    '#type' => 'select',
+    '#options' => $region_array,
+    '#title' => t('Block placement'),
+    '#description' => t('Which region should the ribbon be placed in'),
+    '#default_value' => variable_get('github_page_block', 'page_top'),
+  );
+
+  return system_settings_form($form);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/github/github.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,11 @@
+name = Github
+description = A simple module to display the "fork me on Github" banner on your site
+core = 7.x
+package = Git
+
+; Information added by drupal.org packaging script on 2013-08-22
+version = "7.x-1.2"
+core = "7.x"
+project = "github"
+datestamp = "1377193595"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/github/github.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,116 @@
+<?php
+/**
+ * @file
+ * Displays a ribbon with a link to a GitHub-account.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function github_help($path, $arg) {
+  switch ($path) {
+    case 'admin/setting/github':
+      return t('Display a ribbon on the site, that links to your GitHub-account');
+
+    case 'admin/help#github';
+      $output = '<h2>' . t('About') . '</h2>';
+      $output .= '<p>' . t('Display a GitHub-ribbon that links to your GitHub-account') . '</p>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_permission().
+ */
+function github_permission() {
+  return array(
+    'administer github' => array(
+      'title' => t('Administer Github'),
+      'description' => t('Change settings for your Github ribbon'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function github_menu() {
+  $items = array();
+  $items['admin/config/system/github'] = array(
+    'title' => 'GitHub',
+    'description' => 'Configuration for the GitHub module',
+    'access arguments' => array('administer github'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('github_admin_settings'),
+    'file' => 'github.admin.inc',
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_page_build().
+ */
+// function github_page_build(&$page) {
+function github_page_alter(&$page) {
+  if (variable_get('github_username', '')) {
+    
+    $selectedRegion = variable_get('github_page_block', 'page_top');
+
+    $page[(string)$selectedRegion]['github_container'] = array(
+      '#markup' => github_ribbon(),
+    );
+  }
+}
+
+/**
+ * Custom function to display markup.
+ */
+function github_ribbon() {
+  $username = variable_get('github_username', '');
+  $urls = github_ribbon_urls();
+  $placement = variable_get('github_placement', 'left');
+  $colour = variable_get('github_colour', 'red');
+  $image_url = $urls[$placement][$colour];
+
+  return theme('github_ribbon', compact('username', 'image_url', 'placement'));
+}
+
+/**
+ * Implements hook_theme() for github_ribbon().
+ */
+function github_theme($existing, $type, $theme, $path) {
+  return array(
+    'github_ribbon' => array(
+      'variables' => array(
+        'username' => NULL,
+        'image_url' => NULL,
+        'placement' => NULL,
+      ),
+      'template' => 'github_ribbon',
+    ),
+  );
+}
+
+/**
+ * Custom function for image urls.
+ */
+function github_ribbon_urls() {
+  return array(
+    'left' => array(
+      'red' => drupal_get_path('module', 'github') . '/ribbons/forkme_left_red_aa0000.png',
+      'green' => drupal_get_path('module', 'github') . '/ribbons/forkme_left_green_007200.png',
+      'darkblue' => drupal_get_path('module', 'github') . '/ribbons/forkme_left_darkblue_121621.png',
+      'orange' => drupal_get_path('module', 'github') . '/ribbons/forkme_left_orange_ff7600.png',
+      'grey' => drupal_get_path('module', 'github') . '/ribbons/forkme_left_gray_6d6d6d.png',
+      'white' => drupal_get_path('module', 'github') . '/ribbons/forkme_left_white_ffffff.png',
+    ),
+    'right' => array(
+      'red' => drupal_get_path('module', 'github') . '/ribbons/forkme_right_red_aa0000.png',
+      'green' => drupal_get_path('module', 'github') . '/ribbons/forkme_right_green_007200.png',
+      'darkblue' => drupal_get_path('module', 'github') . '/ribbons/forkme_right_darkblue_121621.png',
+      'orange' => drupal_get_path('module', 'github') . '/ribbons/forkme_right_orange_ff7600.png',
+      'grey' => drupal_get_path('module', 'github') . '/ribbons/forkme_right_gray_6d6d6d.png',
+      'white' => drupal_get_path('module', 'github') . '/ribbons/forkme_right_white_ffffff.png',
+    ),
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/github/github_ribbon.tpl.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,11 @@
+<?php
+/**
+ * @file
+ * HTML markup.
+ */
+?>
+
+<a href="http://github.com/<?php echo $username; ?>">
+  <img style="position: absolute; top: 0; <?php echo $placement; ?>: 0; border: 0;"
+    src="<?php echo $image_url; ?>" alt="Fork me on GitHub"/>
+</a>
Binary file sites/all/modules/github/ribbons/forkme_left_darkblue_121621.png has changed
Binary file sites/all/modules/github/ribbons/forkme_left_gray_6d6d6d.png has changed
Binary file sites/all/modules/github/ribbons/forkme_left_green_007200.png has changed
Binary file sites/all/modules/github/ribbons/forkme_left_orange_ff7600.png has changed
Binary file sites/all/modules/github/ribbons/forkme_left_red_aa0000.png has changed
Binary file sites/all/modules/github/ribbons/forkme_left_white_ffffff.png has changed
Binary file sites/all/modules/github/ribbons/forkme_right_darkblue_121621.png has changed
Binary file sites/all/modules/github/ribbons/forkme_right_gray_6d6d6d.png has changed
Binary file sites/all/modules/github/ribbons/forkme_right_green_007200.png has changed
Binary file sites/all/modules/github/ribbons/forkme_right_orange_ff7600.png has changed
Binary file sites/all/modules/github/ribbons/forkme_right_red_aa0000.png has changed
Binary file sites/all/modules/github/ribbons/forkme_right_white_ffffff.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/link.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,8 @@
+.link-field-column {
+  float: left;
+  width: 48%;
+}
+
+.link-field-column .form-text {
+  width: 95%;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/link.devel_generate.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Devel Generate support for Link module.
+ */
+
+/**
+ * Implements hook_devel_generate().
+ */
+function link_devel_generate($object, $field, $instance, $bundle) {
+  if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
+    return devel_generate_multiple('_link_devel_generate', $object, $field, $instance, $bundle);
+  }
+  else {
+    return _link_devel_generate($object, $field, $instance, $bundle);
+  }
+}
+
+/**
+ * Callback for hook_devel_generate().
+ */
+function _link_devel_generate($object, $field, $instance, $bundle) {
+  return array(
+    'url' => url('<front>', array('absolute' => TRUE)),
+    'title' => devel_create_greeking(mt_rand(1, 3), TRUE),
+    'attributes' => _link_default_attributes(),
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/link.diff.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Provide diff field functions for the Link module.
+ */
+
+/**
+ * Diff field callback for parsing link fields comparative values.
+ */
+function link_field_diff_view($items, $context) {
+  $diff_items = array();
+  foreach ($items as $delta => $item) {
+    if ($item['url'] && $item['title']) {
+      $diff_items[$delta] = $item['title'] . ' (' . $item['url'] . ')';
+    }
+    else {
+      $diff_items[$delta] = $item['title'] . $item['url'];
+    }
+  }
+  return $diff_items;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/link.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,26 @@
+name = Link
+description = Defines simple link field types.
+core = 7.x
+package = Fields
+
+files[] = link.module
+files[] = link.migrate.inc
+
+; Tests
+files[] = tests/link.test
+files[] = tests/link.attribute.test
+files[] = tests/link.crud.test
+files[] = tests/link.crud_browser.test
+files[] = tests/link.token.test
+files[] = tests/link.validate.test
+
+; Views Handlers
+files[] = views/link_views_handler_argument_target.inc
+files[] = views/link_views_handler_filter_protocol.inc
+
+; Information added by drupal.org packaging script on 2013-02-09
+version = "7.x-1.1"
+core = "7.x"
+project = "link"
+datestamp = "1360444361"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/link.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * @file
+ * Install file for the link module.
+ */
+
+/**
+ * Upgrade notes:
+ * Things we need to make sure work when upgrading from Drupal 6 to Drupal 7:
+ */
+
+/**
+ * Implements hook_field_schema().
+ */
+function link_field_schema($field) {
+  return array(
+    'columns' => array(
+      'url' => array(
+        'type' => 'varchar',
+        // Maximum URLs length.
+        'length' => 2048,
+        'not null' => FALSE,
+        'sortable' => TRUE,
+      ),
+      'title' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'sortable' => TRUE,
+      ),
+      'attributes' => array(
+        'type' => 'text',
+        'size' => 'medium',
+        'not null' => FALSE,
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_update_last_removed().
+ */
+function link_update_last_removed() {
+  return 6001;
+}
+
+/**
+ * Handles moving settings data from field_config.data to field_config_instance.data.
+ */
+function link_update_7000() {
+  
+  // For each field that is a link field, we need to copy the settings from the general field level down to the instance.
+  //$field_data = array();
+  $result = db_query("SELECT id, field_name, data FROM {field_config} WHERE module = 'link' AND type = 'link_field'");
+  foreach ($result as $field) {
+    $field_id = $field->id;
+    $name = $field->field_name;
+    $field_data = unserialize($field->data);
+    
+    $instances = db_query("SELECT id, data FROM {field_config_instance} WHERE field_id = :field_id", array(':field_id' => $field_id));
+    foreach ($instances as $instance) {
+      // If this field has been updated already, we want to skip it.
+      $instance_data = unserialize($instance->data);
+      $update_instance = FALSE;
+      if (!isset($instance_data['settings']['title'])) {
+        foreach ($field_data['settings'] as $key => $value) {
+          if (!isset($instance_data['settings'][$key])) {
+            $instance_data['settings'][$key] = $value;
+            $update_instance = TRUE;
+          }
+        }
+        if ($update_instance) {
+          // update the database.
+          $num_updated = db_update('field_config_instance')
+            ->fields(array('data' => serialize($instance_data)))
+            ->condition('id', $instance->id)
+            ->execute();
+        }
+      }
+    }
+  }
+  
+  return t("Instance settings have been set with the data from the field settings.");
+}
+
+/**
+ * Renames all displays from foobar to link_foobar
+ */
+function link_update_7001() {
+  // Update the display type for each link field type.
+  $result = db_query("SELECT id, field_name, data FROM {field_config} WHERE module = 'link' AND type = 'link_field'");
+  foreach ($result as $field) {
+    $field_id = $field->id;
+    $name = $field->field_name;
+    $field_data = unserialize($field->data);
+    
+    $instances = db_query("SELECT id, data FROM {field_config_instance} WHERE field_id = :field_id", array(':field_id' => $field_id));
+    foreach ($instances as $instance) {
+      // If this field has been updated already, we want to skip it.
+      $instance_data = unserialize($instance->data);
+      $update_instance = FALSE;
+      foreach ($instance_data['display'] as $display_name => $display_data) {
+        if ($display_data['type'] && (0 !== strpos($display_data['type'], 'link_'))) {
+          $instance_data['display'][$display_name]['type'] = 'link_' . $display_data['type'];
+          $update_instance = TRUE;
+        }
+      }
+      if ($update_instance) {
+        db_update('field_config_instance')
+          ->fields(array('data' => serialize($instance_data)))
+          ->condition('id', $instance->id)
+          ->execute();
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/link.migrate.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ * @file
+ * Support for migrate module.
+ *
+ * With Migrate 2.4 or later, you can use the subfield syntax to set the title
+ * and attributes:
+ *
+ * @code
+ * $this->addFieldMapping('field_my_link', 'source_url');
+ * $this->addFieldMapping('field_my_link:title', 'source_title');
+ * $this->addFieldMapping('field_my_link:attributes', 'source_attributes');
+ * @endcode
+ *
+ * With earlier versions of Migrate, you must pass an arguments array:
+ *
+ * @code
+ * $link_args = array(
+ *   'title' => array('source_field' => 'source_title'),
+ *   'attributes' => array('source_field' => 'source_attributes'),
+ * );
+ * $this->addFieldMapping('field_my_link', 'source_url')
+ *      ->arguments($link_args);
+ * @endcode
+ */
+
+/**
+ * Implements hook_migrate_api().
+ */
+function link_migrate_api() {
+  return array(
+    'api' => 2,
+    'field handlers' => array('MigrateLinkFieldHandler'),
+  );
+}
+
+class MigrateLinkFieldHandler extends MigrateFieldHandler {
+  public function __construct() {
+    $this->registerTypes(array('link_field'));
+  }
+
+  static function arguments($title = NULL, $attributes = NULL, $language = NULL) {
+    $arguments = array();
+    if (!is_null($title)) {
+      $arguments['title'] = $title;
+    }
+    if (!is_null($attributes)) {
+      $arguments['attributes'] = $attributes;
+    }
+    if (!is_null($language)) {
+      $arguments['language'] = $language;
+    }
+    return $arguments;
+  }
+
+  /**
+   * Implementation of MigrateFieldHandler::fields().
+   *
+   * @param $type
+   *  The field type.
+   * @param $instance
+   *  Instance info for the field.
+   * @param Migration $migration
+   *  The migration context for the parent field. We can look at the mappings
+   *  and determine which subfields are relevant.
+   * @return array
+   */
+  public function fields($type, $instance, $migration = NULL) {
+    return array(
+      'title' => t('Subfield: The link title attribute'),
+      'attributes' => t('Subfield: The attributes for this link'),
+      'language' => t('Subfield: The language for the field'),
+    );
+  }
+
+  public function prepare($entity, array $field_info, array $instance, array $values) {
+    if (isset($values['arguments'])) {
+      $arguments = $values['arguments'];
+      unset($values['arguments']);
+    }
+    else {
+      $arguments = array();
+    }
+
+    $language = $this->getFieldLanguage($entity, $field_info, $arguments);
+    $values = array_filter($values);
+
+    foreach ($values as $delta => $value) {
+      $item = array();
+      if (isset($arguments['title'])) {
+        if (!is_array($arguments['title'])) {
+          $item['title'] = $arguments['title'];
+        }
+        elseif (isset($arguments['title'][$delta])) {
+          $item['title'] = $arguments['title'][$delta];
+        }
+      }
+      if (isset($arguments['attributes'])) {
+        $item['attributes'] = $arguments['attributes'];
+      }
+      $item['url'] = $value;
+      $return[$language][$delta] = $item;
+    }
+
+    return isset($return) ? $return : NULL;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/link.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1320 @@
+<?php
+
+/**
+ * @file
+ * Defines simple link field types.
+ */
+
+define('LINK_EXTERNAL', 'external');
+define('LINK_INTERNAL', 'internal');
+define('LINK_FRONT', 'front');
+define('LINK_EMAIL', 'email');
+define('LINK_NEWS', 'news');
+define('LINK_DOMAINS', 'aero|arpa|asia|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|local');
+
+define('LINK_TARGET_DEFAULT', 'default');
+define('LINK_TARGET_NEW_WINDOW', '_blank');
+define('LINK_TARGET_TOP', '_top');
+define('LINK_TARGET_USER', 'user');
+
+/**
+ * Maximum URLs length - needs to match value in link.install.
+ */
+define('LINK_URL_MAX_LENGTH', 2048);
+
+/**
+ * Implements hook_field_info().
+ */
+function link_field_info() {
+  return array(
+    'link_field' => array(
+      'label' => t('Link'),
+      'description' => t('Store a title, href, and attributes in the database to assemble a link.'),
+      'settings' => array(
+        'attributes' => _link_default_attributes(),
+        'url' => 0,
+        'title' => 'optional',
+        'title_value' => '',
+        'title_maxlength' => 128,
+        'enable_tokens' => 1,
+        'display' => array(
+          'url_cutoff' => 80,
+        ),
+      ),
+      'instance_settings' => array(
+        'attributes' => _link_default_attributes(),
+        'url' => 0,
+        'title' => 'optional',
+        'title_value' => '',
+        'title_maxlength' => 128,
+        'enable_tokens' => 1,
+        'display' => array(
+          'url_cutoff' => 80,
+        ),
+        'validate_url' => 1,
+      ),
+      'default_widget' => 'link_field',
+      'default_formatter' => 'link_default',
+      // Support hook_entity_property_info() from contrib "Entity API".
+      'property_type' => 'field_item_link',
+      'property_callbacks' => array('link_field_property_info_callback'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function link_field_instance_settings_form($field, $instance) {
+  $form = array(
+    '#element_validate' => array('link_field_settings_form_validate'),
+  );
+
+  $form['validate_url'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Validate URL'),
+    '#default_value' => isset($instance['settings']['validate_url']) && ($instance['settings']['validate_url'] !== '') ? $instance['settings']['validate_url'] : TRUE,
+    '#description' => t('If checked, the URL field will be verified as a valid URL during validation.'),
+  );
+
+  $form['url'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Optional URL'),
+    '#default_value' => isset($instance['settings']['url']) ? $instance['settings']['url'] : '',
+    '#return_value' => 'optional',
+    '#description' => t('If checked, the URL field is optional and submitting a title alone will be acceptable. If the URL is omitted, the title will be displayed as plain text.'),
+  );
+
+  $title_options = array(
+    'optional' => t('Optional Title'),
+    'required' => t('Required Title'),
+    'value' => t('Static Title'),
+    'none' => t('No Title'),
+  );
+
+  $form['title'] = array(
+    '#type' => 'radios',
+    '#title' => t('Link Title'),
+    '#default_value' => isset($instance['settings']['title']) ? $instance['settings']['title'] : 'optional',
+    '#options' => $title_options,
+    '#description' => t('If the link title is optional or required, a field will be displayed to the end user. If the link title is static, the link will always use the same title. If <a href="http://drupal.org/project/token">token module</a> is installed, the static title value may use any other entity field as its value. Static and token-based titles may include most inline XHTML tags such as <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc.'),
+  );
+
+  $form['title_value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Static title'),
+    '#default_value' => isset($instance['settings']['title_value']) ? $instance['settings']['title_value'] : '',
+    '#description' => t('This title will always be used if &ldquo;Static Title&rdquo; is selected above.'),
+  );
+
+  $form['title_maxlength'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Max length of title field'),
+    '#default_value' => isset($instance['settings']['title_maxlength']) ? $instance['settings']['title_maxlength'] : '128',
+    '#description' => t('Set a maximum length on the title field (applies only if Link Title is optional or required).  The maximum limit is 255 characters.'),
+    '#maxlength' => 3,
+    '#size' => 3,
+  );
+
+  if (module_exists('token')) {
+    // Add token module replacements fields
+    $form['tokens'] = array(
+      '#type' => 'fieldset',
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#title' => t('Placeholder tokens'),
+      '#description' => t("The following placeholder tokens can be used in both paths and titles. When used in a path or title, they will be replaced with the appropriate values."),
+    );
+    $entity_info = entity_get_info($instance['entity_type']);
+    $form['tokens']['help'] = array(
+      '#theme' => 'token_tree',
+      '#token_types' => array($entity_info['token type']),
+      '#global_types' => TRUE,
+      '#click_insert' => TRUE,
+    );
+
+    $form['enable_tokens'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Allow user-entered tokens'),
+      '#default_value' => isset($instance['settings']['enable_tokens']) ? $instance['settings']['enable_tokens'] : 1,
+      '#description' => t('Checking will allow users to enter tokens in URLs and Titles on the entity edit form. This does not affect the field settings on this page.'),
+    );
+  }
+
+  $form['display'] = array(
+    '#tree' => TRUE,
+  );
+  $form['display']['url_cutoff'] = array(
+    '#type' => 'textfield',
+    '#title' => t('URL Display Cutoff'),
+    '#default_value' => isset($instance['settings']['display']['url_cutoff']) ? $instance['settings']['display']['url_cutoff'] : '80',
+    '#description' => t('If the user does not include a title for this link, the URL will be used as the title. When should the link title be trimmed and finished with an elipsis (&hellip;)? Leave blank for no limit.'),
+    '#maxlength' => 3,
+    '#size' => 3,
+  );
+
+  $target_options = array(
+    LINK_TARGET_DEFAULT => t('Default (no target attribute)'),
+    LINK_TARGET_TOP => t('Open link in window root'),
+    LINK_TARGET_NEW_WINDOW => t('Open link in new window'),
+    LINK_TARGET_USER => t('Allow the user to choose'),
+  );
+  $form['attributes'] = array(
+    '#tree' => TRUE,
+  );
+  $form['attributes']['target'] = array(
+    '#type' => 'radios',
+    '#title' => t('Link Target'),
+    '#default_value' => empty($instance['settings']['attributes']['target']) ? LINK_TARGET_DEFAULT : $instance['settings']['attributes']['target'],
+    '#options' => $target_options,
+  );
+  $form['attributes']['rel'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Rel Attribute'),
+    '#description' => t('When output, this link will have this rel attribute. The most common usage is <a href="http://en.wikipedia.org/wiki/Nofollow">rel=&quot;nofollow&quot;</a> which prevents some search engines from spidering entered links.'),
+    '#default_value' => empty($instance['settings']['attributes']['rel']) ? '' : $instance['settings']['attributes']['rel'],
+    '#field_prefix' => 'rel = "',
+    '#field_suffix' => '"',
+    '#size' => 20,
+  );
+  $rel_remove_options = array(
+    'default' => t('Keep rel as set up above (untouched/default)'),
+    'rel_remove_external' => t('Remove rel if given link is external'),
+    'rel_remove_internal' => t('Remove rel if given link is internal'),
+  );
+  $form['rel_remove'] = array(
+    '#type' => 'radios',
+    '#title' => t('Remove rel attribute automatically'),
+    '#default_value' => !isset($instance['settings']['rel_remove']) ? 'default' : $instance['settings']['rel_remove'],
+    '#description' => t('Turn on/off if rel attribute should be removed automatically, if user given link is internal/external'),
+    '#options' => $rel_remove_options,
+  );
+  $form['attributes']['class'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Additional CSS Class'),
+    '#description' => t('When output, this link will have this class attribute. Multiple classes should be separated by spaces.'),
+    '#default_value' => empty($instance['settings']['attributes']['class']) ? '' : $instance['settings']['attributes']['class'],
+  );
+  $form['attributes']['configurable_title'] = array(
+    '#title' => t("Allow the user to enter a link 'title' attribute"),
+    '#type' => 'checkbox',
+    '#default_value' => empty($instance['settings']['attributes']['configurable_title']) ? '' : $instance['settings']['attributes']['configurable_title'],
+  );
+  $form['attributes']['title'] = array(
+    '#title' => t("Default link 'title' Attribute"),
+    '#type' => 'textfield',
+    '#description' => t('When output, links will use this "title" attribute if the user does not provide one and when different from the link text. Read <a href="http://www.w3.org/TR/WCAG10-HTML-TECHS/#links">WCAG 1.0 Guidelines</a> for links comformances. Tokens values will be evaluated.'),
+    '#default_value' => empty($instance['settings']['attributes']['title']) ? '' : $instance['settings']['attributes']['title'],
+    '#field_prefix' => 'title = "',
+    '#field_suffix' => '"',
+    '#size' => 20,
+  );
+  return $form;
+}
+
+/**
+ * #element_validate handler for link_field_instance_settings_form().
+ */
+function link_field_settings_form_validate($element, &$form_state, $complete_form) {
+  if ($form_state['values']['instance']['settings']['title'] === 'value' && empty($form_state['values']['instance']['settings']['title_value'])) {
+    form_set_error('title_value', t('A default title must be provided if the title is a static value.'));
+  }
+  if (!empty($form_state['values']['instance']['settings']['display']['url_cutoff']) && !is_numeric($form_state['values']['instance']['settings']['display']['url_cutoff'])) {
+    form_set_error('display', t('URL Display Cutoff value must be numeric.'));
+  }
+  if (empty($form_state['values']['instance']['settings']['title_maxlength'])) {
+    form_set_value($element['title_maxlength'], '128', $form_state);
+  }
+  elseif (!is_numeric($form_state['values']['instance']['settings']['title_maxlength'])) {
+    form_set_error('title_maxlength', t('The max length of the link title must be numeric.'));
+  }
+  elseif ($form_state['values']['instance']['settings']['title_maxlength'] > 255) {
+    form_set_error('title_maxlength', t('The max length of the link title cannot be greater than 255 characters.'));
+  }
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function link_field_is_empty($item, $field) {
+  return empty($item['title']) && empty($item['url']);
+}
+
+/**
+ * Implements hook_field_load().
+ */
+function link_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
+  foreach ($entities as $id => $entity) {
+    foreach ($items[$id] as $delta => $item) {
+      $items[$id][$delta]['attributes'] = _link_load($field, $item, $instances[$id]);
+    }
+  }
+}
+
+/**
+ * Implements hook_field_validate().
+ */
+function link_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  $optional_field_found = FALSE;
+  if ($instance['settings']['validate_url'] !== 0 || is_null($instance['settings']['validate_url']) || !isset($instance['settings']['validate_url'])) {
+    foreach ($items as $delta => $value) {
+      _link_validate($items[$delta], $delta, $field, $entity, $instance, $langcode, $optional_field_found);
+    }
+  }
+
+  if ($instance['settings']['url'] === 'optional' && $instance['settings']['title'] === 'optional' && $instance['required'] && !$optional_field_found) {
+    form_set_error($field['field_name'] . '][' . $langcode . '][0][title', t('At least one title or URL must be entered.'));
+  }
+}
+
+/**
+ * Implements hook_field_insert().
+ */
+function link_field_insert($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  foreach ($items as $delta => $value) {
+    _link_process($items[$delta], $delta, $field, $entity);
+  }
+}
+
+/**
+ * Implements hook_field_update().
+ */
+function link_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  foreach ($items as $delta => $value) {
+    _link_process($items[$delta], $delta, $field, $entity);
+  }
+}
+
+/**
+ * Implements hook_field_prepare_view().
+ */
+function link_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  foreach ($items as $entity_id => $entity_items) {
+    foreach ($entity_items as $delta => $value) {
+      _link_sanitize($items[$entity_id][$delta], $delta, $field, $instances[$entity_id], $entities[$entity_id]);
+    }
+  }
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function link_field_widget_info() {
+  return array(
+    'link_field' => array(
+      'label' => 'Link',
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function link_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  $element += array(
+    '#type' => $instance['widget']['type'],
+    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
+  );
+  return $element;
+}
+
+/**
+ * Unpacks the item attributes for use.
+ */
+function _link_load($field, $item, $instance) {
+  if (isset($item['attributes'])) {
+    if (!is_array($item['attributes'])) {
+      $item['attributes'] = unserialize($item['attributes']);
+    }
+    return $item['attributes'];
+  }
+  elseif (isset($instance['settings']['attributes'])) {
+    return $instance['settings']['attributes'];
+  }
+  else {
+    return $field['settings']['attributes'];
+  }
+}
+
+/**
+ * Prepares the item attributes and url for storage.
+ */
+function _link_process(&$item, $delta = 0, $field, $entity) {
+  // Trim whitespace from URL.
+  $item['url'] = trim($item['url']);
+
+  // If no attributes are set then make sure $item['attributes'] is an empty
+  // array, so $field['attributes'] can override it.
+  if (empty($item['attributes'])) {
+    $item['attributes'] = array();
+  }
+
+  // Serialize the attributes array.
+  if (!is_string($item['attributes'])) {
+    $item['attributes'] = serialize($item['attributes']);
+  }
+
+  // Don't save an invalid default value (e.g. 'http://').
+  if ((isset($field['widget']['default_value'][$delta]['url']) && $item['url'] == $field['widget']['default_value'][$delta]['url']) && is_object($entity)) {
+    if (!link_validate_url($item['url'])) {
+      unset($item['url']);
+    }
+  }
+}
+
+/**
+ * Validates that the link field has been entered properly.
+ */
+function _link_validate(&$item, $delta, $field, $entity, $instance, $langcode, &$optional_field_found) {
+  if ($item['url'] && !(isset($instance['default_value'][$delta]['url']) && $item['url'] === $instance['default_value'][$delta]['url'] && !$instance['required'])) {
+    // Validate the link.
+    if (link_validate_url(trim($item['url'])) == FALSE) {
+      form_set_error($field['field_name'] . '][' . $langcode . '][' . $delta . '][url', t('The value provided for %field is not a valid URL.', array('%field' => $instance['label'])));
+    }
+    // Require a title for the link if necessary.
+    if ($instance['settings']['title'] == 'required' && strlen(trim($item['title'])) == 0) {
+      form_set_error($field['field_name'] . '][' . $langcode . '][' . $delta . '][title', t('Titles are required for all links.'));
+    }
+  }
+  // Require a link if we have a title.
+  if ($instance['settings']['url'] !== 'optional' && strlen(isset($item['title']) ? $item['title'] : NULL) > 0 && strlen(trim($item['url'])) == 0) {
+    form_set_error($field['field_name'] . '][' . $langcode . '][' . $delta . '][url', t('You cannot enter a title without a link url.'));
+  }
+  // In a totally bizzaro case, where URLs and titles are optional but the field is required, ensure there is at least one link.
+  if ($instance['settings']['url'] === 'optional' && $instance['settings']['title'] === 'optional' && (strlen(trim($item['url'])) !== 0 || strlen(trim($item['title'])) !== 0)) {
+    $optional_field_found = TRUE;
+  }
+  // Require entire field
+  if ($instance['settings']['url'] === 'optional' && $instance['settings']['title'] === 'optional' && $instance['required'] == 1 && !$optional_field_found && isset($instance['id'])) {
+    form_set_error($instance['field_name'] . '][' . $langcode . '][0][title', t('At least one title or URL must be entered.'));
+  }
+}
+
+/**
+ * Clean up user-entered values for a link field according to field settings.
+ *
+ * @param $item
+ *   A single link item, usually containing url, title, and attributes.
+ * @param $delta
+ *   The delta value if this field is one of multiple fields.
+ * @param $field
+ *   The CCK field definition.
+ * @param $entity
+ *   The entity containing this link.
+ */
+function _link_sanitize(&$item, $delta, &$field, $instance, &$entity) {
+  // Don't try to process empty links.
+  if (empty($item['url']) && empty($item['title'])) {
+    return;
+  }
+
+  // Replace URL tokens.
+  $entity_type = $instance['entity_type'];
+  $entity_info = entity_get_info($entity_type);
+  $property_id = $entity_info['entity keys']['id'];
+  $entity_token_type = isset($entity_info['token type']) ? $entity_info['token type'] : (
+    $entity_type == 'taxonomy_term' || $entity_type == 'taxonomy_vocabulary' ? str_replace('taxonomy_', '', $entity_type) : $entity_type
+  );
+  if (isset($instance['settings']['enable_tokens']) && $instance['settings']['enable_tokens']) {
+    global $user;
+    // Load the entity if necessary for entities in views.
+    if (isset($entity->{$property_id})) {
+      $entity_loaded = entity_load($entity_type, array($entity->{$property_id}));
+      $entity_loaded = array_pop($entity_loaded);
+    }
+    else {
+      $entity_loaded = $entity;
+    }
+    $item['url'] = token_replace($item['url'], array($entity_token_type => $entity_loaded));
+  }
+
+  $type = link_validate_url($item['url']);
+  // If the type of the URL cannot be determined and URL validation is disabled,
+  // then assume LINK_EXTERNAL for later processing.
+  if ($type == FALSE && $instance['settings']['validate_url'] === 0) {
+    $type = LINK_EXTERNAL;
+  }
+  $url = link_cleanup_url($item['url']);
+  $url_parts = _link_parse_url($url);
+
+  // We can't check_plain('<front>') because it'll break.
+  if ($type != LINK_FRONT) {
+    $url_parts['url'] = check_plain($url_parts['url']);
+  }
+
+  if (!empty($url_parts['url'])) {
+    $item['url'] = url($url_parts['url'],
+      array(
+        'query' => isset($url_parts['query']) ? $url_parts['query'] : NULL,
+        'fragment' => isset($url_parts['fragment']) ? $url_parts['fragment'] : NULL,
+        'absolute' => TRUE,
+        'html' => TRUE,
+      )
+    );
+  }
+
+  // Create a shortened URL for display.
+  if ($type == LINK_EMAIL) {
+    $display_url = str_replace('mailto:', '', $url);
+  }
+  else {
+    $display_url = url($url_parts['url'],
+      array(
+        'query' => isset($url_parts['query']) ? $url_parts['query'] : NULL,
+        'fragment' => isset($url_parts['fragment']) ? $url_parts['fragment'] : NULL,
+        'absolute' => TRUE,
+      )
+    );
+  }
+  if ($instance['settings']['display']['url_cutoff'] && strlen($display_url) > $instance['settings']['display']['url_cutoff']) {
+    $display_url = substr($display_url, 0, $instance['settings']['display']['url_cutoff']) . "...";
+  }
+  $item['display_url'] = $display_url;
+
+  // Use the title defined at the instance level.
+  if ($instance['settings']['title'] == 'value' && strlen(trim($instance['settings']['title_value']))) {
+    $title = $instance['settings']['title_value'];
+    if (function_exists('i18n_string_translate')) {
+      $i18n_string_name = "field:{$instance['field_name']}:{$instance['bundle']}:title_value";
+      $title = i18n_string_translate($i18n_string_name, $title);
+    }
+  }
+  // Use the title defined by the user at the widget level.
+  elseif (isset($item['title'])) {
+    $title = $item['title'];
+  }
+  else {
+    $title = '';
+  }
+
+  // Replace tokens.
+  if ($title && ($instance['settings']['title'] == 'value' || $instance['settings']['enable_tokens'])) {
+    // Load the entity if necessary for entities in views.
+    if (isset($entity->{$property_id})) {
+      $entity_loaded = entity_load($entity_type, array($entity->{$property_id}));
+      $entity_loaded = array_pop($entity_loaded);
+    }
+    else {
+      $entity_loaded = $entity;
+    }
+    $title = token_replace($title, array($entity_token_type => $entity_loaded));
+    $title = filter_xss($title, array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+    $item['html'] = TRUE;
+  }
+  $item['title'] = empty($title) ? $item['display_url'] : $title;
+
+  if (!isset($item['attributes'])) {
+    $item['attributes'] = array();
+  }
+
+  // Unserialize attributtes array if it has not been unserialized yet.
+  if (!is_array($item['attributes'])) {
+    $item['attributes'] = (array)unserialize($item['attributes']);
+  }
+
+  // Add default attributes.
+  if (!is_array($instance['settings']['attributes'])) {
+    $instance['settings']['attributes'] = _link_default_attributes();
+  }
+  else {
+    $instance['settings']['attributes'] += _link_default_attributes();
+  }
+
+  // Merge item attributes with attributes defined at the field level.
+  $item['attributes'] += $instance['settings']['attributes'];
+
+  // If user is not allowed to choose target attribute, use default defined at
+  // field level.
+  if ($instance['settings']['attributes']['target'] != LINK_TARGET_USER) {
+    $item['attributes']['target'] = $instance['settings']['attributes']['target'];
+  }
+  elseif ($item['attributes']['target'] == LINK_TARGET_USER) {
+    $item['attributes']['target'] = LINK_TARGET_DEFAULT;
+  }
+
+  // Remove the target attribute if the default (no target) is selected.
+  if (empty($item['attributes']) || (isset($item['attributes']['target']) && $item['attributes']['target'] == LINK_TARGET_DEFAULT)) {
+    unset($item['attributes']['target']);
+  }
+
+  // Remove rel attribute for internal or external links if selected.
+  if (isset($item['attributes']['rel']) && isset($instance['settings']['rel_remove']) && $instance['settings']['rel_remove'] != 'default') {
+    if (($instance['settings']['rel_remove'] != 'rel_remove_internal' && $type != LINK_INTERNAL) ||
+      ($instance['settings']['rel_remove'] != 'rel_remove_external' && $type != LINK_EXTERNAL)) {
+      unset($item['attributes']['rel']);
+    }
+  }
+
+  // Handle "title" link attribute.
+  if (!empty($item['attributes']['title']) && module_exists('token')) {
+    // Load the entity (necessary for entities in views).
+    if (isset($entity->{$property_id})) {
+      $entity_loaded = entity_load($entity_type, array($entity->{$property_id}));
+      $entity_loaded = array_pop($entity_loaded);
+    }
+    else {
+      $entity_loaded = $entity;
+    }
+    $item['attributes']['title'] = token_replace($item['attributes']['title'], array($entity_token_type => $entity_loaded));
+    $item['attributes']['title'] = filter_xss($item['attributes']['title'], array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+  }
+  // Remove title attribute if it's equal to link text.
+  if (isset($item['attributes']['title']) && $item['attributes']['title'] == $item['title']) {
+    unset($item['attributes']['title']);
+  }
+  unset($item['attributes']['configurable_title']);
+
+  // Remove empty attributes.
+  $item['attributes'] = array_filter($item['attributes']);
+
+  // Sets title to trimmed url if one exists
+  // @todo: Obsolete?
+  /*if(!empty($item['display_url']) && empty($item['title'])) {
+    $item['title'] = $item['display_url'];
+  }
+  elseif(!isset($item['title'])) {
+    $item['title'] = $item['url'];
+  }*/
+}
+
+/**
+ * Because parse_url doesn't work with relative urls.
+ *
+ * @param string $url
+ *   URL to parse.
+ *
+ * @return Array
+ *   Array of url pieces - only 'url', 'query', and 'fragment'.
+ */
+function _link_parse_url($url) {
+  $url_parts = array();
+  // Separate out the anchor, if any.
+  if (strpos($url, '#') !== FALSE) {
+    $url_parts['fragment'] = substr($url, strpos($url, '#') + 1);
+    $url = substr($url, 0, strpos($url, '#'));
+  }
+  // Separate out the query string, if any.
+  if (strpos($url, '?') !== FALSE) {
+    $query = substr($url, strpos($url, '?') + 1);
+    parse_str($query, $query_array);
+    // See http://drupal.org/node/1710578
+    foreach ($query_array as $key=> &$value) {
+      if ($value === '' && FALSE === strpos($query, $key . '=')) {
+        $value = NULL;
+      }
+    }
+    $url_parts['query'] = $query_array;
+    $url = substr($url, 0, strpos($url, '?'));
+  }
+  $url_parts['url'] = $url;
+  return $url_parts;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function link_theme() {
+  return array(
+    'link_formatter_link_default' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_plain' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_absolute' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_domain' => array(
+      'variables' => array('element' => NULL, 'display' => NULL),
+    ),
+    'link_formatter_link_title_plain' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_url' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_short' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_formatter_link_label' => array(
+      'variables' => array('element' => NULL, 'field' => NULL),
+    ),
+    'link_formatter_link_separate' => array(
+      'variables' => array('element' => NULL),
+    ),
+    'link_field' => array(
+      'render element' => 'element',
+    ),
+  );
+}
+
+/**
+ * Formats a link field widget.
+ */
+function theme_link_field($vars) {
+  drupal_add_css(drupal_get_path('module', 'link') . '/link.css');
+  $element = $vars['element'];
+  // Prefix single value link fields with the name of the field.
+  if (empty($element['#field']['multiple'])) {
+    if (isset($element['url']) && !isset($element['title'])) {
+      $element['url']['#title_display'] = 'invisible';
+    }
+  }
+
+  $output = '';
+  $output .= '<div class="link-field-subrow clearfix">';
+  if (isset($element['title'])) {
+    $output .= '<div class="link-field-title link-field-column">' . drupal_render($element['title']) . '</div>';
+  }
+  $output .= '<div class="link-field-url' . (isset($element['title']) ? ' link-field-column' : '') . '">'. drupal_render($element['url']) . '</div>';
+  $output .= '</div>';
+  if (!empty($element['attributes']['target'])) {
+    $output .= '<div class="link-attributes">' . drupal_render($element['attributes']['target']) . '</div>';
+  }
+  if (!empty($element['attributes']['title'])) {
+    $output .= '<div class="link-attributes">' . drupal_render($element['attributes']['title']) . '</div>';
+  }
+  return $output;
+}
+
+/**
+ * Implements hook_element_info().
+ */
+function link_element_info() {
+  $elements = array();
+  $elements['link_field'] = array(
+    '#input' => TRUE,
+    '#process' => array('link_field_process'),
+    '#theme' => 'link_field',
+    '#theme_wrappers' => array('form_element'),
+  );
+  return $elements;
+}
+
+/**
+ * Returns the default attributes and their values.
+ */
+function _link_default_attributes() {
+  return array(
+    'target' => LINK_TARGET_DEFAULT,
+    'class' => '',
+    'rel' => '',
+  );
+}
+
+/**
+ * Processes the link type element before displaying the field.
+ *
+ * Build the form element. When creating a form using FAPI #process,
+ * note that $element['#value'] is already set.
+ *
+ * The $fields array is in $complete_form['#field_info'][$element['#field_name']].
+ */
+function link_field_process($element, $form_state, $complete_form) {
+  $instance = field_widget_instance($element, $form_state);
+  $settings = $instance['settings'];
+  $element['url'] = array(
+    '#type' => 'textfield',
+    '#maxlength' => LINK_URL_MAX_LENGTH,
+    '#title' => t('URL'),
+    '#required' => ($element['#delta'] == 0 && $settings['url'] !== 'optional') ? $element['#required'] : FALSE,
+    '#default_value' => isset($element['#value']['url']) ? $element['#value']['url'] : NULL,
+  );
+  if ($settings['title'] !== 'none' && $settings['title'] !== 'value') {
+    $element['title'] = array(
+      '#type' => 'textfield',
+      '#maxlength' => $settings['title_maxlength'],
+      '#title' => t('Title'),
+      '#description' => t('The link title is limited to @maxlength characters maximum.', array('@maxlength' => $settings['title_maxlength'])),
+      '#required' => ($settings['title'] == 'required' && (($element['#delta'] == 0 && $element['#required']) || !empty($element['#value']['url']))) ? TRUE : FALSE,
+      '#default_value' => isset($element['#value']['title']) ? $element['#value']['title'] : NULL,
+    );
+  }
+
+  // Initialize field attributes as an array if it is not an array yet.
+  if (!is_array($settings['attributes'])) {
+    $settings['attributes'] = array();
+  }
+  // Add default attributes.
+  $settings['attributes'] += _link_default_attributes();
+  $attributes = isset($element['#value']['attributes']) ? $element['#value']['attributes'] : $settings['attributes'];
+  if (!empty($settings['attributes']['target']) && $settings['attributes']['target'] == LINK_TARGET_USER) {
+    $element['attributes']['target'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Open URL in a New Window'),
+      '#return_value' => LINK_TARGET_NEW_WINDOW,
+      '#default_value' => isset($attributes['target']) ? $attributes['target'] : FALSE,
+    );
+  }
+  if (!empty($settings['attributes']['configurable_title']) && $settings['attributes']['configurable_title'] == 1) {
+    $element['attributes']['title'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Link "title" attribute'),
+      '#default_value' => isset($attributes['title']) ? $attributes['title'] : '',
+      '#field_prefix' => 'title = "',
+      '#field_suffix' => '"',
+    );
+  }
+
+  // If the title field is avaliable or there are field accepts multiple values
+  // then allow the individual field items display the required asterisk if needed.
+  if (isset($element['title']) || isset($element['_weight'])) {
+    // To prevent an extra required indicator, disable the required flag on the
+    // base element since all the sub-fields are already required if desired.
+    $element['#required'] = FALSE;
+  }
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function link_field_formatter_info() {
+  return array(
+    'link_default' => array(
+      'label' => t('Title, as link (default)'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_title_plain' => array(
+      'label' => t('Title, as plain text'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_url' => array(
+      'label' => t('URL, as link'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_plain' => array(
+      'label' => t('URL, as plain text'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_absolute' => array(
+      'label' => t('URL, absolute'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_domain' => array(
+      'label' => t('Domain, as link'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+      'settings' => array(
+        'strip_www' => FALSE,
+      ),
+    ),
+    'link_short' => array(
+      'label' => t('Short, as link with title "Link"'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_label' => array(
+      'label' => t('Label, as link with label as title'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+    'link_separate' => array(
+      'label' => t('Separate title and URL'),
+      'field types' => array('link_field'),
+      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function link_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $element = array();
+  if ($display['type'] == 'link_domain') {
+    $element['strip_www'] = array(
+      '#title' => t('Strip www. from domain'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['strip_www'],
+    );
+  }
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function link_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  if ($display['type'] == 'link_domain') {
+    if ($display['settings']['strip_www']) {
+      return t('Strip www. from domain');
+    }
+    else {
+      return t('Leave www. in domain');
+    }
+  }
+  return '';
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function link_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $elements = array();
+  foreach ($items as $delta => $item) {
+    $elements[$delta] = array(
+      '#theme' => 'link_formatter_' . $display['type'],
+      '#element' => $item,
+      '#field' => $instance,
+      '#display' => $display,
+    );
+  }
+  return $elements;
+}
+
+/**
+ * Formats a link.
+ */
+function theme_link_formatter_link_default($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['title']);
+  unset($link_options['url']);
+
+  if (isset($link_options['attributes']['class'])) {
+    $link_options['attributes']['class'] = array($link_options['attributes']['class']);
+  }
+
+  // Display a normal link if both title and URL are available.
+  if (!empty($vars['element']['title']) && !empty($vars['element']['url'])) {
+    return l($vars['element']['title'], $vars['element']['url'], $link_options);
+  }
+  // If only a title, display the title.
+  elseif (!empty($vars['element']['title'])) {
+    return check_plain($vars['element']['title']);
+  }
+  elseif (!empty($vars['element']['url'])) {
+    return l($vars['element']['title'], $vars['element']['url'], $link_options);
+  }
+}
+
+/**
+ * Formats a link (or its title) as plain text.
+ */
+function theme_link_formatter_link_plain($vars) {
+  $link_options = $vars['element'];
+  if (isset($link_options['title'])) {
+    unset($link_options['title']);
+  }
+  else {
+    $vars['element']['title'] = '';
+  }
+  unset($link_options['url']);
+  return empty($vars['element']['url']) ? check_plain($vars['element']['title']) : url($vars['element']['url'], $link_options);
+}
+
+/**
+ * Formats a link as an absolute URL
+ */
+function theme_link_formatter_link_absolute($vars) {
+  $absolute = array('absolute' => TRUE);
+  return empty($vars['element']['url']) ? '' : url($vars['element']['url'], $absolute + $vars['element']);
+}
+
+/**
+ * Formats a link using the URL's domain for it's link text.
+ */
+function theme_link_formatter_link_domain($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['title']);
+  unset($link_options['url']);
+  $domain = parse_url($vars['element']['display_url'], PHP_URL_HOST);
+  if (!empty($vars['display']['settings']['strip_www'])) {
+    $domain = str_replace('www.', '', $domain);
+  }
+  return $vars['element']['url'] ? l($domain, $vars['element']['url'], $link_options) : '';
+}
+
+/**
+ * Formats a link's title as plain text.
+ */
+function theme_link_formatter_link_title_plain($vars) {
+  return empty($vars['element']['title']) ? '' : check_plain($vars['element']['title']);
+}
+
+/**
+ * Formats a link using an alternate display URL for its link text.
+ */
+function theme_link_formatter_link_url($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['title']);
+  unset($link_options['url']);
+  return $vars['element']['url'] ? l($vars['element']['display_url'], $vars['element']['url'], $link_options) : '';
+}
+
+/**
+ * Formats a link using "Link" as the link text.
+ */
+function theme_link_formatter_link_short($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['title']);
+  unset($link_options['url']);
+  return $vars['element']['url'] ? l(t('Link'), $vars['element']['url'], $link_options) : '';
+}
+
+/**
+ * Formats a link using the field's label as link text.
+ */
+function theme_link_formatter_link_label($vars) {
+  $link_options = $vars['element'];
+  unset($link_options['title']);
+  unset($link_options['url']);
+  return $vars['element']['url'] ? l($vars['field']['label'], $vars['element']['url'], $link_options) : '';
+}
+
+/**
+ * Formats a link as separate title and URL elements.
+ */
+function theme_link_formatter_link_separate($vars) {
+  $class = empty($vars['element']['attributes']['class']) ? '' : ' ' . $vars['element']['attributes']['class'];
+  unset($vars['element']['attributes']['class']);
+  $link_options = $vars['element'];
+  unset($link_options['title']);
+  unset($link_options['url']);
+  $title = empty($vars['element']['title']) ? '' : check_plain($vars['element']['title']);
+
+  /**
+   * @TODO static html markup looks not very elegant
+   * needs smarter output solution and an optional title/url seperator
+   */
+  $url_parts = _link_parse_url($vars['element']['url']);
+  $output = '';
+  $output .= '<div class="link-item ' . $class . '">';
+  if (!empty($title)) {
+    $output .= '<div class="link-title">' . $title . '</div>';
+  }
+  $output .= '<div class="link-url">' . l($url_parts['url'], $vars['element']['url'], $link_options) . '</div>';
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Implements hook_token_list().
+ */
+function link_token_list($type = 'all') {
+  if ($type === 'field' || $type === 'all') {
+    $tokens = array();
+    $tokens['link']['url'] = t("Link URL");
+    $tokens['link']['title'] = t("Link title");
+    $tokens['link']['view'] = t("Formatted html link");
+    return $tokens;
+  }
+}
+
+function link_token_values($type, $object = NULL) {
+  if ($type === 'field') {
+    $item = $object[0];
+
+    $tokens['url'] = $item['url'];
+    $tokens['title'] = $item['title'];
+    $tokens['view'] = isset($item['view']) ? $item['view'] : '';
+
+    return $tokens;
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function link_views_api() {
+  return array(
+    'api' => 2,
+    'path' => drupal_get_path('module', 'link') . '/views',
+  );
+}
+
+/**
+ * Forms a valid URL if possible from an entered address.
+ * 
+ * Trims whitespace and automatically adds an http:// to addresses without a
+ * protocol specified
+ *
+ * @param string $url
+ * @param string $protocol
+ *   The protocol to be prepended to the url if one is not specified
+ */
+function link_cleanup_url($url, $protocol = 'http') {
+  $url = trim($url);
+  $type = link_validate_url($url);
+
+  if ($type === LINK_EXTERNAL) {
+    // Check if there is no protocol specified.
+    $protocol_match = preg_match("/^([a-z0-9][a-z0-9\.\-_]*:\/\/)/i", $url);
+    if (empty($protocol_match)) {
+      // But should there be? Add an automatic http:// if it starts with a domain name.
+      $LINK_DOMAINS = _link_domains();
+      $domain_match = preg_match('/^(([a-z0-9]([a-z0-9\-_]*\.)+)(' . $LINK_DOMAINS . '|[a-z]{2}))/i', $url);
+      if (!empty($domain_match)) {
+        $url = $protocol . "://" . $url;
+      }
+    }
+  }
+
+  return $url;
+}
+
+/**
+ * Validates a URL.
+ * 
+ * Accepts all URLs following RFC 1738 standard for URL formation and all e-mail
+ * addresses following the RFC 2368 standard for mailto address formation.
+ *
+ * @param string $text
+ * 
+ * @return mixed
+ *   Returns boolean FALSE if the URL is not valid. On success, returns one of
+ *   the LINK_(linktype) constants.
+ */
+function link_validate_url($text) {
+  // @TODO Complete letters.
+  $LINK_ICHARS_DOMAIN = (string) html_entity_decode(implode("", array(
+    "&#x00E6;", // æ
+    "&#x00C6;", // Æ
+    "&#x00C0;", // À
+    "&#x00E0;", // à
+    "&#x00C1;", // Ã
+    "&#x00E1;", // á
+    "&#x00C2;", // Â
+    "&#x00E2;", // â
+    "&#x00E5;", // å
+    "&#x00C5;", // Ã…
+    "&#x00E4;", // ä
+    "&#x00C4;", // Ä
+    "&#x00C7;", // Ç
+    "&#x00E7;", // ç
+    "&#x00D0;", // Ã
+    "&#x00F0;", // ð
+    "&#x00C8;", // È
+    "&#x00E8;", // è
+    "&#x00C9;", // É
+    "&#x00E9;", // é
+    "&#x00CA;", // Ê
+    "&#x00EA;", // ê
+    "&#x00CB;", // Ë
+    "&#x00EB;", // ë
+    "&#x00CE;", // ÃŽ
+    "&#x00EE;", // î
+    "&#x00CF;", // Ã
+    "&#x00EF;", // ï
+    "&#x00F8;", // ø
+    "&#x00D8;", // Ø
+    "&#x00F6;", // ö
+    "&#x00D6;", // Ö
+    "&#x00D4;", // Ô
+    "&#x00F4;", // ô
+    "&#x00D5;", // Õ
+    "&#x00F5;", // õ
+    "&#x0152;", // Å’
+    "&#x0153;", // Å“
+    "&#x00FC;", // ü
+    "&#x00DC;", // Ü
+    "&#x00D9;", // Ù
+    "&#x00F9;", // ù
+    "&#x00DB;", // Û
+    "&#x00FB;", // û
+    "&#x0178;", // Ÿ
+    "&#x00FF;", // ÿ
+    "&#x00D1;", // Ñ
+    "&#x00F1;", // ñ
+    "&#x00FE;", // þ
+    "&#x00DE;", // Þ
+    "&#x00FD;", // ý
+    "&#x00DD;", // Ã
+    "&#x00BF;", // ¿
+  )), ENT_QUOTES, 'UTF-8');
+
+  $LINK_ICHARS = $LINK_ICHARS_DOMAIN . (string) html_entity_decode(implode("", array(
+    "&#x00DF;", // ß
+  )), ENT_QUOTES, 'UTF-8');
+  $allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
+  $LINK_DOMAINS = _link_domains();
+
+  // Starting a parenthesis group with (?: means that it is grouped, but is not captured
+  $protocol = '((?:' . implode("|", $allowed_protocols) . '):\/\/)';
+  $authentication = "(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=" . $LINK_ICHARS . "]|%[0-9a-f]{2})+(?::(?:[\w" . $LINK_ICHARS . "\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})*)?)?@)";
+  $domain = '(?:(?:[a-z0-9' . $LINK_ICHARS_DOMAIN . ']([a-z0-9' . $LINK_ICHARS_DOMAIN . '\-_\[\]])*)(\.(([a-z0-9' . $LINK_ICHARS_DOMAIN . '\-_\[\]])+\.)*(' . $LINK_DOMAINS . '|[a-z]{2}))?)';
+  $ipv4 = '(?:[0-9]{1,3}(\.[0-9]{1,3}){3})';
+  $ipv6 = '(?:[0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})';
+  $port = '(?::([0-9]{1,5}))';
+
+  // Pattern specific to external links.
+  $external_pattern = '/^' . $protocol . '?' . $authentication . '?(' . $domain . '|' . $ipv4 . '|' . $ipv6 . ' |localhost)' . $port . '?';
+
+  // Pattern specific to internal links.
+  $internal_pattern = "/^(?:[a-z0-9" . $LINK_ICHARS . "_\-+\[\] ]+)";
+  $internal_pattern_file = "/^(?:[a-z0-9" . $LINK_ICHARS . "_\-+\[\]\. \/\(\)][a-z0-9" . $LINK_ICHARS . "_\-+\[\]\. \(\)][a-z0-9" . $LINK_ICHARS . "_\-+\[\]\. \/\(\)]+)$/i";
+
+  $directories = "(?:\/[a-z0-9" . $LINK_ICHARS . "_\-\.~+%=&,$'#!():;*@\[\]]*)*";
+  // Yes, four backslashes == a single backslash.
+  $query = "(?:\/?\?([?a-z0-9" . $LINK_ICHARS . "+_|\-\.~\/\\\\%=&,$'():;*@\[\]{} ]*))";
+  $anchor = "(?:#[a-z0-9" . $LINK_ICHARS . "_\-\.~+%=&,$'():;*@\[\]\/\?]*)";
+
+  // The rest of the path for a standard URL.
+  $end = $directories . '?' . $query . '?' . $anchor . '?' . '$/i';
+
+  $message_id = '[^@].*@' . $domain;
+  $newsgroup_name = '(?:[0-9a-z+-]*\.)*[0-9a-z+-]*';
+  $news_pattern = '/^news:(' . $newsgroup_name . '|' . $message_id . ')$/i';
+
+  $user = '[a-zA-Z0-9' . $LINK_ICHARS . '_\-\.\+\^!#\$%&*+\/\=\?\`\|\{\}~\'\[\]]+';
+  $email_pattern = '/^mailto:' . $user . '@'.'(?:' . $domain . '|' . $ipv4 . '|' . $ipv6 . '|localhost)' . $query . '?$/';
+
+  if (strpos($text, '<front>') === 0) {
+    return LINK_FRONT;
+  }
+  if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) {
+    return LINK_EMAIL;
+  }
+  if (in_array('news', $allowed_protocols) && preg_match($news_pattern, $text)) {
+    return LINK_NEWS;
+  }
+  if (preg_match($internal_pattern . $end, $text)) {
+    return LINK_INTERNAL;
+  }
+  if (preg_match($external_pattern . $end, $text)) {
+    return LINK_EXTERNAL;
+  }
+  if (preg_match($internal_pattern_file, $text)) {
+    return LINK_INTERNAL;
+  }
+
+  return FALSE;
+}
+
+/**
+ * Returns the list of allowed domains, including domains added by admins via variable_set/$config.
+ */
+function _link_domains() {
+  $link_extra_domains = variable_get('link_extra_domains', array());
+  return empty($link_extra_domains) ? LINK_DOMAINS : LINK_DOMAINS . '|' . implode('|', $link_extra_domains);
+}
+
+/**
+ * Implements hook_migrate_field_alter().
+ */
+function link_content_migrate_field_alter(&$field_value, $instance_value) {
+  if ($field_value['type'] == 'link') {
+    // Adjust the field type.
+    $field_value['type'] = 'link_field';
+    // Remove settings that are now on the instance.
+    foreach (array('attributes', 'display', 'url', 'title', 'title_value', 'enable_tokens', 'validate_url') as $setting) {
+      unset($field_value['settings'][$setting]);
+    }
+  }
+}
+
+/**
+ * Implements hook_migrate_instance_alter().
+ *
+ * Widget type also changed to link_field.
+ */
+function link_content_migrate_instance_alter(&$instance_value, $field_value) {
+  if ($field_value['type'] == 'link') {
+    // Grab settings that were previously on the field.
+    foreach (array('attributes', 'display', 'url', 'title', 'title_value', 'enable_tokens', 'validate_url') as $setting) {
+      if (isset($field_value['settings'][$setting])) {
+        $instance_value['settings'][$setting] = $field_value['settings'][$setting];
+      }
+    }
+    // Adjust widget type.
+    if ($instance_value['widget']['type'] == 'link') {
+      $instance_value['widget']['type'] = 'link_field';
+    }
+    // Adjust formatter types.
+    foreach ($instance_value['display'] as $context => $settings) {
+      if (in_array($settings['type'], array('default', 'title_plain', 'url', 'plain', 'short', 'label', 'separate'))) {
+        $instance_value['display'][$context]['type'] = 'link_' . $settings['type'];
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function link_field_settings_form() {
+  return array();
+}
+
+/**
+ * Additional callback to adapt the property info of link fields.
+ * 
+ * @see entity_metadata_field_entity_property_info().
+ */
+function link_field_property_info_callback(&$info, $entity_type, $field, $instance, $field_type) {
+  $property = &$info[$entity_type]['bundles'][$instance['bundle']]['properties'][$field['field_name']];
+  // Define a data structure so it's possible to deal with both the link title
+  // and URL.
+  $property['getter callback'] = 'entity_metadata_field_verbatim_get';
+  $property['setter callback'] = 'entity_metadata_field_verbatim_set';
+
+  // Auto-create the field item as soon as a property is set.
+  $property['auto creation'] = 'link_field_item_create';
+
+  $property['property info'] = link_field_item_property_info();
+  $property['property info']['url']['required'] = !$instance['settings']['url'];
+  $property['property info']['title']['required'] = ($instance['settings']['title'] == 'required');
+  if ($instance['settings']['title'] == 'none') {
+    unset($property['property info']['title']);
+  }
+  unset($property['query callback']);
+}
+
+/**
+ * Callback for creating a new, empty link field item.
+ *
+ * @see link_field_property_info_callback()
+ */
+function link_field_item_create() {
+  return array('title' => NULL, 'url' => NULL);
+}
+
+/**
+ * Defines info for the properties of the link-field item data structure.
+ */
+function link_field_item_property_info() {
+  $properties['title'] = array(
+    'type' => 'text',
+    'label' => t('The title of the link.'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  $properties['url'] = array(
+    'type' => 'uri',
+    'label' => t('The URL of the link.'),
+    'setter callback' => 'entity_property_verbatim_set',
+  );
+  return $properties;
+}
+
+/**
+ * Implements hook_field_update_instance().
+ */
+function link_field_update_instance($instance, $prior_instance) {
+  if (function_exists('i18n_string_update') && $prior_instance['settings']['title_value'] != $instance['settings']['title_value']) {
+    $i18n_string_name = "field:{$instance['field_name']}:{$instance['bundle']}:title_value";
+    i18n_string_update($i18n_string_name, $instance['settings']['title_value']);
+  }
+}
+
+/**
+ * Implements hook_i18n_string_list_TEXTGROUP_alter().
+ */
+function link_i18n_string_list_field_alter(&$strings, $type = NULL, $object = NULL) {
+  if ($type == 'field_instance' && $object && $object['widget']['type'] == 'link_field') {
+    if (isset($object['settings']['title_value'])) {
+      $strings['field'][$object['field_name']][$object['bundle']]['title_value']['string'] = $object['settings']['title_value'];
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/tests/link.attribute.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,494 @@
+<?php
+
+/**
+ * @file
+ * Basic simpletests to test options on link module.
+ */
+
+class LinkAttributeCrudTest extends DrupalWebTestCase {
+  private $zebra;
+
+  protected $permissions = array(
+    'access content',
+    'administer content types',
+    'administer nodes',
+    'administer filters',
+    'access comments',
+    'post comments',
+    'skip comment approval',
+    'access administration pages',
+  );
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link Attribute Tests',
+      'description' => 'Tests the field attributes, making sure they appear in various displayed situations.',
+      'group' => 'Link',
+    );
+  }
+
+  function setup() {
+    parent::setup('field_ui', 'link');
+    $this->zebra = 0;
+    // Create and login user.
+    $this->web_user = $this->drupalCreateUser(array('administer content types'));
+    $this->drupalLogin($this->web_user);
+  }
+
+  protected function createLink($url, $title, $attributes = array()) {
+    return array(
+      'url' => $url,
+      'title' => $title,
+      'attributes' => $attributes,
+    );
+  }
+
+  protected function assertLinkOnNode($field_name, $link_value, $message = '', $group = 'Other') {
+    $this->zebra++;
+    $zebra_string = ($this->zebra % 2 == 0) ? 'even' : 'odd';
+    $cssFieldLocator = 'field-'. str_replace('_', '-', $field_name);
+    $this->assertPattern('@<div class="field field-type-link '. $cssFieldLocator .'".*<div class="field-item '. $zebra_string .'">\s*'. $link_value .'\s*</div>@is',
+                         $message,
+                         $group);
+  }
+
+  /**
+   * A simple test that just creates a new node type, adds a link field to it, creates a new node of that type, and makes sure
+   * that the node is being displayed.
+   */
+  function testBasic() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+    $title = $this->randomName(20);
+
+    $this->drupalGet('admin/structure/types');
+
+    // Create the content type.
+    $this->clickLink(t('Add content type'));
+
+    $edit = array (
+      'name' => $content_type_friendly,
+      'type' => $content_type_machine,
+    );
+    $this->drupalPost(NULL, $edit, t('Save and add fields'));
+    $this->assertText(t('The content type @name has been added.', array('@name' => $content_type_friendly)));
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    $single_field_name = 'field_'. $single_field_name_machine;
+    $edit = array (
+      'fields[_add_new_field][label]' => $single_field_name_friendly,
+      'fields[_add_new_field][field_name]' => $single_field_name_machine,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // We'll go with the default settings for this run-through.
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+
+    // Using all the default settings, so press the button.
+    $this->drupalPost(NULL, array(), t('Save settings'));
+    $this->assertText(t('Saved @name configuration.', array('@name' => $single_field_name_friendly)));
+
+    // Somehow clicking "save" isn't enough, and we have to do a
+    // node_types_rebuild().
+    node_types_rebuild();
+    menu_rebuild();
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $content_type_machine))->fetchField();
+    $this->assertTrue($type_exists, 'The new content type has been created in the database.');
+
+    $permission = 'create ' . $content_type_machine . ' content';
+    $permission_edit = 'edit ' . $content_type_machine . ' content';
+    // Reset the permissions cache.
+    $this->checkPermissions(array($permission), TRUE);
+
+    // Now that we have a new content type, create a user that has privileges
+    // on the content type.
+    $permissions = array_merge($this->permissions, array($permission));
+    $this->web_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->web_user);
+
+    // Go to page.
+    $this->drupalGet('node/add/'. $content_type_machine);
+
+    // Add a node.
+    $edit = array(
+      'title' => $title,
+      'field_'. $single_field_name_machine. '[und][0][title]' => 'Link',
+      'field_'. $single_field_name_machine. '[und][0][url]' => 'http://www.drupal.org/',
+    );
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('@content_type_friendly @title has been created', array('@content_type_friendly' => $content_type_friendly, '@title' => $title)));
+
+    $this->drupalGet('node/add/'. $content_type_machine);
+
+    // Create a node:
+    $edit = array(
+      'title' => $title,
+      'field_' . $single_field_name_machine . '[und][0][url]' => 'http://www.example.com/',
+      'field_' . $single_field_name_machine . '[und][0][title]' => 'Display',
+    );
+
+    // Now we can fill in the second item in the multivalue field and save.
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('@content_type_friendly @title has been created', array('@content_type_friendly' => $content_type_friendly, '@title' => $title)));
+
+    $this->assertText('Display');
+    $this->assertLinkByHref('http://www.example.com');
+  }
+
+  protected function createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine) {
+    $this->drupalGet('admin/structure/types/manage/' . $content_type_machine . '/fields');
+    $edit = array (
+      'fields[_add_new_field][label]' => $single_field_name_friendly,
+      'fields[_add_new_field][field_name]' => $single_field_name_machine,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // We'll go with the default settings for this run-through.
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+
+    // Using all the default settings, so press the button.
+    $this->drupalPost(NULL, array(), t('Save settings'));
+    $this->assertText(t('Saved @name configuration.', array('@name' => $single_field_name_friendly)));
+
+    // Somehow clicking "save" isn't enough, and we have to do a
+    // node_types_rebuild().
+    node_types_rebuild();
+    menu_rebuild();
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $content_type_machine))->fetchField();
+    $this->assertTrue($type_exists, 'The new content type has been created in the database.');
+  }
+
+  protected function createNodeTypeUser($content_type_machine) {
+    $permission = 'create ' . $content_type_machine . ' content';
+    $permission_edit = 'edit ' . $content_type_machine . ' content';
+    // Reset the permissions cache.
+    $this->checkPermissions(array($permission), TRUE);
+
+    // Now that we have a new content type, create a user that has privileges
+    // on the content type.
+    $permissions = array_merge($this->permissions, array($permission));
+    $this->web_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->web_user);
+  }
+
+  protected function createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $title, $url, $node_title = '') {
+    $this->drupalGet('node/add/'. $content_type_machine);
+
+    if (!$node_title) {
+      $node_title = $this->randomName(20);
+    }
+    $edit = array(
+      'title' => $node_title,
+    );
+    if ($url) {
+      $edit['field_' . $single_field_name_machine . '[und][0][url]'] = $url;
+    }
+    if ($title) {
+      $edit['field_' . $single_field_name_machine . '[und][0][title]'] = $title;
+    }
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('@content_type_friendly @title has been created', array('@content_type_friendly' => $content_type_friendly, '@title' => $node_title)));
+
+  }
+
+  /**
+   * Test the link_plain formatter and it's output.
+   */
+  function testFormatterPlain() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->drupalCreateContentType(array(
+      'type' => $content_type_machine,
+      'name' => $content_type_friendly,
+    ));
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_plain',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+    
+    $link_tests = array(
+      'plain' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/',
+      ),
+      'query' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/?q=test',
+      ),
+      'fragment' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/#test',
+      ),
+    );
+
+    foreach ($link_tests as $key => $link_test) {
+      $link_text = $link_test['text'];
+      $link_url = $link_test['url'];
+      $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+  
+      $this->assertText($link_url);
+      $this->assertNoText($link_text);
+      $this->assertNoLinkByHref($link_url);
+    }
+  }
+
+  function testFormatterURL() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->drupalCreateContentType(array(
+      'type' => $content_type_machine,
+      'name' => $content_type_friendly,
+    ));
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_url',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+    
+    $link_tests = array(
+      'plain' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/',
+      ),
+      'query' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/?q=test',
+      ),
+      'fragment' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/#test',
+      ),
+    );
+
+    foreach ($link_tests as $key => $link_test) {
+      $link_text = $link_test['text'];
+      $link_url = $link_test['url'];
+      $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+  
+      $this->assertNoText($link_text);
+      $this->assertLinkByHref($link_url);
+    }
+  }
+
+  function testFormatterShort() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->drupalCreateContentType(array(
+      'type' => $content_type_machine,
+      'name' => $content_type_friendly,
+    ));
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_short',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_tests = array(
+      'plain' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/',
+      ),
+      'query' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/?q=test',
+      ),
+      'fragment' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/#test',
+      ),
+    );
+
+    foreach ($link_tests as $key => $link_test) {
+      $link_text = $link_test['text'];
+      $link_url = $link_test['url'];
+      $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+  
+      $this->assertText('Link');
+      $this->assertNoText($link_text);
+      $this->assertLinkByHref($link_url);
+    }
+  }
+
+  function testFormatterLabel() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->drupalCreateContentType(array(
+      'type' => $content_type_machine,
+      'name' => $content_type_friendly,
+    ));
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_label',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $link_tests = array(
+      'plain' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/',
+      ),
+      'query' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/?q=test',
+      ),
+      'fragment' => array(
+        'text' => 'Display',
+        'url' => 'http://www.example.com/#test',
+      ),
+    );
+
+    foreach ($link_tests as $key => $link_test) {
+      $link_text = $link_test['text'];
+      $link_url = $link_test['url'];  
+      $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+  
+      $this->assertNoText($link_text);
+      $this->assertText($single_field_name_friendly);
+      $this->assertLinkByHref($link_url);
+    }
+  }
+
+  function testFormatterSeparate() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+
+    $this->drupalCreateContentType(array(
+      'type' => $content_type_machine,
+      'name' => $content_type_friendly,
+    ));
+
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_separate',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $this->createNodeTypeUser($content_type_machine);
+
+    $plain_url = 'http://www.example.com/';
+    $link_tests = array(
+      'plain' => array(
+        'text' => $this->randomName(20),
+        'url' => $plain_url,
+      ),
+      'query' => array(
+        'text' => $this->randomName(20),
+        'url' => $plain_url . '?q=test',
+      ),
+      'fragment' => array(
+        'text' => $this->randomName(20),
+        'url' => $plain_url . '#test',
+      ),
+    );
+
+    foreach ($link_tests as $key => $link_test) {
+      $link_text = $link_test['text'];
+      $link_url = $link_test['url'];
+      $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+  
+      $this->assertText($link_text);
+      $this->assertLink($plain_url);
+      $this->assertLinkByHref($link_url);
+    }
+  }
+  
+  function testFormatterPlainTitle() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+    
+    $this->drupalCreateContentType(array(
+      'type' => $content_type_machine,
+      'name' => $content_type_friendly,
+    ));
+    
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    //$single_field_name = 'field_'. $single_field_name_machine;
+    $this->createSimpleLinkField($single_field_name_machine, $single_field_name_friendly, $content_type_machine);
+    
+    // Okay, now we want to make sure this display is changed:
+    $this->drupalGet('admin/structure/types/manage/'. $content_type_machine .'/display');
+    $edit = array(
+      'fields[field_'. $single_field_name_machine .'][label]' => 'above',
+      'fields[field_'. $single_field_name_machine .'][type]' => 'link_title_plain',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    
+    $this->createNodeTypeUser($content_type_machine);
+    
+    $link_text = 'Display';
+    $link_url = 'http://www.example.com/';
+    $this->createNodeForTesting($content_type_machine, $content_type_friendly, $single_field_name_machine, $link_text, $link_url);
+    
+    $this->assertText($link_text);
+    $this->assertNoText($link_url);
+    $this->assertNoLinkByHref($link_url);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/tests/link.crud.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Basic CRUD simpletests for the link module, based off of content.crud.test in CCK.
+ */
+
+class LinkContentCrudTest extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link CRUD - Basic API tests',
+      'description' => 'Tests the field CRUD (create, read, update, delete) API.',
+      'group' => 'Link',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('field_ui', 'link');
+  }
+
+  /**
+   * All we're doing here is creating a content type, creating a simple link field
+   * on that content type.
+   */
+  function testLinkCreateFieldAPI() {
+    $content_type_friendly = $this->randomName(20);
+    $content_type_machine = strtolower($this->randomName(10));
+    $title = $this->randomName(20);
+
+    // Create and login user.
+    $this->web_user = $this->drupalCreateUser(array('administer content types'));
+    $this->drupalLogin($this->web_user);
+
+    $this->drupalGet('admin/structure/types');
+
+    // Create the content type.
+    $this->clickLink(t('Add content type'));
+
+    $edit = array (
+      'name' => $content_type_friendly,
+      'type' => $content_type_machine,
+    );
+    $this->drupalPost(NULL, $edit, t('Save and add fields'));
+    $this->assertText(t('The content type @name has been added.', array('@name' => $content_type_friendly)));
+
+    //$field = $this->createField(array('type' => 'link', 'widget_type' => 'link'), 0);
+    // Now add a singleton field.
+    $single_field_name_friendly = $this->randomName(20);
+    $single_field_name_machine = strtolower($this->randomName(10));
+    $edit = array (
+      'fields[_add_new_field][label]' => $single_field_name_friendly,
+      'fields[_add_new_field][field_name]' => $single_field_name_machine,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // We'll go with the default settings for this run-through.
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+
+    // Using all the default settings, so press the button.
+    $this->drupalPost(NULL, array(), t('Save settings'));
+    $this->assertText(t('Saved @name configuration.', array('@name' => $single_field_name_friendly)));
+
+    // Somehow clicking "save" isn't enough, and we have to do a
+    // node_types_rebuild().
+    node_types_rebuild();
+    menu_rebuild();
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $content_type_machine))->fetchField();
+    $this->assertTrue($type_exists, 'The new content type has been created in the database.');
+
+    /*$table_schema = drupal_get_schema();
+    $this->assertEqual(1, 1, print_r(array_keys($table_schema), TRUE));
+    // Check the schema - the values should be in the per-type table.
+    $this->assertSchemaMatchesTables(array(
+      'per_type' => array(
+        $this->content_types[0]->type => array($field['field_name'] => array('url', 'title', 'attributes')),
+      ),
+    ));*/
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/tests/link.crud_browser.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,266 @@
+<?php
+
+/**
+ * @file
+ * Testing CRUD API in the browser.
+ */
+
+/**
+ * Testing that users can not input bad URLs or labels
+ */
+class LinkUITest extends DrupalWebTestcase {
+
+  /**
+   * Link supposed to be good
+   */
+  const LINK_INPUT_TYPE_GOOD = 0;
+
+  /**
+   * Link supposed to have a bad title
+   */
+  const LINK_INPUT_TYPE_BAD_TITLE = 1;
+
+  /**
+   * Link supposed to have a bad URL
+   */
+  const LINK_INPUT_TYPE_BAD_URL = 2;
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link CRUD - browser test',
+      'description' => 'Tests the field CRUD (create, read, update, delete) API 2.',
+      'group' => 'Link',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('field_ui', 'link');
+  }
+
+  /**
+   * Creates a link field for the "page" type and creates a page with a link.
+   */
+  function testLinkCreate() {
+    //libxml_use_internal_errors(true);
+    $this->web_user = $this->drupalCreateUser(array(
+      'administer content types',
+      'administer nodes',
+      'administer filters',
+      'access content',
+      'create page content',
+      'access administration pages'
+    ));
+    $this->drupalLogin($this->web_user);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    $permission = 'create page content';
+    $this->checkPermissions(array($permission), TRUE);
+
+    // create page form
+    //$this->drupalGet('node/add');
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField('edit-field-'. $name .'-und-0-title', 'Title found');
+    $this->assertField('edit-field-'. $name .'-und-0-url', 'URL found');
+
+    $input_test_cases = array(
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+        'msg' => 'Link found',
+        'type' => self::LINK_INPUT_TYPE_GOOD
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '<script>alert("hi");</script>',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '<script src="http://devil.site.com"></script>',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+      array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '" onmouseover="alert(\'hi\')',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+       array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName() . '\' onmouseover="alert(\'hi\')',
+        'msg' => 'js label',
+        'type' => self::LINK_INPUT_TYPE_BAD_TITLE
+      ),
+     array(
+        'href' => 'javascript:alert("http://example.com/' . $this->randomName() . '")',
+        'label' => $this->randomName(),
+        'msg' => 'js url',
+        'type' => self::LINK_INPUT_TYPE_BAD_URL
+      ),
+    );
+    $test_case = array(
+      'href' => 'www.example.com/'. $this->randomName(),
+      'label' => $this->randomName(),
+      'msg' => 'Link found',
+      'type' => self::LINK_INPUT_TYPE_GOOD,
+    );
+    $test_case['expected_href'] = 'http://'. $test_case['href'];
+    $input_test_cases[] = $test_case;
+
+    foreach ($input_test_cases as $input) {
+      $this->drupalLogin($this->web_user);
+      $this->drupalGet('node/add/page');
+
+      $edit = array(
+        'title' => $input['label'],
+        $field_name . '[und][0][title]' => $input['label'],
+        $field_name . '[und][0][url]' => $input['href'],
+      );
+      $this->drupalPost(NULL, $edit, t('Save'));
+      if ($input['type'] == self::LINK_INPUT_TYPE_BAD_URL) {
+        $this->assertRaw(t('The value provided for %field is not a valid URL.', array('%field' => $name)), 'Not a valid URL: ' . $input['href']);
+        continue;
+      }
+      else {
+        $this->assertRaw(t(' has been created.',
+                           array('@type' => 'Basic Page', '%title' => $edit['title'])),
+                         'Page created: ' . $input['href']);
+      }
+      $url = $this->getUrl();
+
+      // change to anonym user
+      $this->drupalLogout();
+
+      $this->drupalGet($url);
+      //debug($this);
+      // If simpletest starts using something to override the error system, this will flag
+      // us and let us know it's broken.
+      $this->assertFalse(libxml_use_internal_errors(TRUE));
+      if (isset($input['expected_href'])) {
+        $path = '//a[@href="'. $input['expected_href'] .'" and text()="'. $input['label'] .'"]';
+      }
+      else {
+        $path = '//a[@href="'. $input['href'] .'" and text()="'. $input['label'] .'"]';
+      }
+      //$this->pass(htmlentities($path));
+      $elements = $this->xpath($path);
+      libxml_use_internal_errors(FALSE);
+      $this->assertIdentical(isset($elements[0]), $input['type'] == self::LINK_INPUT_TYPE_GOOD, $input['msg']);
+    }
+    //libxml_use_internal_errors(FALSE);
+  }
+
+  /**
+   * Testing that if you use <strong> in a static title for your link, that the
+   * title actually displays <strong>.
+   */
+  function testStaticLinkCreate() {
+    $this->web_user = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($this->web_user);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $field_name = 'field_'. $name;
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(
+      'instance[settings][title]' => 'value',
+      'instance[settings][title_value]' => '<strong>'. $name .'</strong>'), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $this->assertField($field_name . '[und][0][url]', 'URL found');
+
+    $input = array(
+      'href' => 'http://example.com/' . $this->randomName()
+    );
+
+    $edit = array(
+      'title' => $name,
+      $field_name . '[und][0][url]' => $input['href'],
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l('<strong>'. $name .'</strong>', $input['href'], array('html' => TRUE)));
+  }
+
+  /**
+   * If we're creating a new field and just hit 'save' on the default options, we want to make
+   * sure they are set to the expected results.
+   */
+  function testCRUDCreateFieldDefaults() {
+    $this->web_user = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($this->web_user);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+    //_content_type_info(TRUE);
+    //$fields = content_fields();
+    //$field = $fields['field_'. $name];
+    //$field = field_info_field('field_'. $name);
+    _field_info_collate_fields(TRUE);
+    $instances = field_info_instances('node', 'page');
+    //$this->debug($instances);
+    //$this->assert('debug', '<pre>'. print_r($instances, TRUE) .'</pre>', 'Debug');
+    $instance = $instances['field_'. $name];
+    //$this->assertTrue(1 === $instance['validate_url'], 'Make sure validation is on.');
+    $this->assertFalse($instance['required'], 'Make sure field is not required.');
+    $this->assertEqual($instance['settings']['title'], 'optional', 'Title should be optional by default.');
+    $this->assertTrue($instance['settings']['enable_tokens'], 'Enable Tokens should be off by default.');
+    $this->assertEqual($instance['settings']['display']['url_cutoff'], 80, 'Url cutoff should be at 80 characters.');
+    $this->assertEqual($instance['settings']['attributes']['target'], 'default', 'Target should be "default"');
+    $this->assertFalse($instance['settings']['attributes']['rel'], 'Rel should be blank by default.');
+    $this->assertFalse($instance['settings']['attributes']['class'], 'By default, no class should be set.');
+    $this->assertFalse($instance['settings']['title_value'], 'By default, no title should be set.');
+
+    //$this->fail('<pre>'. print_r($fields['field_'. $name], TRUE) .'</pre>');
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/tests/link.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Link base test file - contains common functions for testing links.
+ */
+
+class LinkBaseTestClass extends DrupalWebTestCase {
+  protected $permissions = array(
+    'access content',
+    'administer content types',
+    'administer nodes',
+    'administer filters',
+    'access comments',
+    'post comments',
+    'access administration pages',
+    'create page content',
+  );
+
+  function setUp() {
+    $modules = func_get_args();
+    $modules = (isset($modules[0]) && is_array($modules[0]) ? $modules[0] : $modules);
+    $modules[] = 'field_ui';
+    $modules[] = 'link';
+    parent::setUp($modules);
+    
+    $this->web_user = $this->drupalCreateUser($this->permissions);
+    $this->drupalLogin($this->web_user);
+  }
+
+  protected function createLinkField($node_type = 'page', $settings = array()) {
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $field_name = 'field_'. $name;
+    $this->drupalPost('admin/structure/types/manage/'. $node_type .'/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, $settings, t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    return $field_name;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/tests/link.token.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,377 @@
+<?php
+
+/**
+ * @file
+ * Contains simpletests making sure token integration works.
+ */
+
+/**
+ * Testing that tokens can be used in link titles
+ */
+class LinkTokenTest extends LinkBaseTestClass {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link tokens - browser test',
+      'description' => 'Tests including tokens in link titles, making sure they appear in node views.',
+      'group' => 'Link',
+      'dependencies' => array('token'),
+    );
+  }
+
+  function setUp($modules = array()) {
+    parent::setUp(array('token'));
+  }
+
+  /**
+   * Creates a link field with a required title enabled for user-entered tokens.
+   * Creates a node with a token in the link title and checks the value.
+   */
+  function testUserTokenLinkCreate() {
+    // create field
+    $settings = array(
+      'instance[settings][enable_tokens]' => 1,
+    );
+    $field_name = $this->createLinkField('page',
+                                        $settings);
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    //$field_name = 'field_' . $name;
+    $this->assertField($field_name . '[und][0][title]', 'Title found');
+    $this->assertField($field_name . '[und][0][url]', 'URL found');
+
+    $input = array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+    );
+
+    //$this->drupalLogin($this->web_user);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $input['label'],
+      $field_name . '[und][0][title]' => $input['label'] . " [node:content-type:machine-name]",
+      $field_name . '[und][0][url]' => $input['href'],
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($input['label'] . ' page', $input['href']));
+  }
+
+
+  /**
+   * Creates a link field with a static title and an admin-entered token.
+   * Creates a node with a link and checks the title value.
+   */
+  function testStaticTokenLinkCreate() {
+
+    // create field
+    $name = $this->randomName();
+    $settings = array(
+      'instance[settings][title]' => 'value',
+      'instance[settings][title_value]' => $name .' [node:content-type:machine-name]');
+    $field_name = $this->createLinkField('page', $settings);
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $this->assertField($field_name . '[und][0][url]', 'URL found');
+
+    $input = array(
+      'href' => 'http://example.com/' . $this->randomName()
+    );
+
+    //$this->drupalLogin($this->web_user);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $name,
+      $field_name . '[und][0][url]' => $input['href'],
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($name . ' page', $input['href']));
+  }
+
+  /**
+   * Creates a link field with a static title and an admin-entered token.
+   * Creates a node with a link and checks the title value.
+   *
+   * Basically, I want to make sure the [title-raw] token works, because it's a
+   * token that changes from node to node, where [type]'s always going to be the
+   * same.
+   */
+  function testStaticTokenLinkCreate2() {
+
+    // create field
+    $name = $this->randomName();
+    $settings = array(
+      'instance[settings][title]' => 'value',
+      'instance[settings][title_value]' => $name .' [node:title]');
+    $field_name = $this->createLinkField('page', $settings);
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $this->assertField($field_name . '[und][0][url]', 'URL found');
+
+    $input = array(
+      'href' => 'http://example.com/' . $this->randomName()
+    );
+
+    //$this->drupalLogin($this->web_user);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $name,
+      $field_name . '[und][0][url]' => $input['href'],
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($name .' '. $name, $input['href']));
+  }
+
+  // This test doesn't seem to actually work, due to lack of 'title' in url.
+  function _test_Link_With_Title_Attribute_token_url_form() {
+   /* $this->loginWithPermissions($this->permissions);
+    $this->acquireContentTypes(1);
+    $field_settings = array(
+      'type' => 'link',
+      'widget_type' => 'link',
+      'type_name' => $this->content_types[0]->name,
+      'attributes' => array(
+        'class' => '',
+        'target' => 'default',
+        'rel' => 'nofollow',
+        'title' => '',
+      ),
+    );
+
+    $field = $this->createField($field_settings, 0);
+    //$this->fail('<pre>'. print_r($field, TRUE) .'</pre>');
+    $field_name = $field['field_name'];
+    $field_db_info = content_database_info($field);
+    $url_type = str_replace('_', '-', $this->content_types[0]->type);
+
+    $edit = array('attributes[title]' => '['. $field_name .'-url]',
+                  'enable_tokens' => TRUE);
+
+    $this->drupalPost('admin/content/node-type/'. $url_type .'/fields/'. $field['field_name'],
+                      $edit, t('Save field settings'));
+    $this->assertText(t('Saved field @field_name', array('@field_name' => $field['field_name'])));*/
+    $name = $this->randomName();
+    $settings = array(
+      'instance[settings][attributes][rel]' => 'nofollow',
+    );
+
+    $field_name = $this->createLinkField('page', $settings);
+
+    // So, having saved this field_name, let's see if it works...
+    //$this->acquireNodes(1);
+
+    //$node = node_load($this->nodes[0]->nid);
+
+    //$this->drupalGet('node/'. $this->nodes[0]->nid);
+
+    $edit = array();
+    $test_link_url = 'http://www.example.com/test';
+    $edit[$field_name .'[und][0][url]'] = $test_link_url;
+    $title = 'title_'. $this->randomName(20);
+    $edit[$field_name .'[und][0][title]'] = $title;
+    $edit['title'] = $name;
+
+    $this->drupalGet('node/add/page');
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Make sure we get a new version!
+    //$node = node_load($this->nodes[0]->nid, NULL, TRUE);
+    $this->assertText(t('Basic page @title has been updated.',
+                        array('@title' => $name)));
+
+    //$this->drupalGet('node/'. $node->nid);
+    $this->assertText($title, 'Make sure the link title/text shows');
+    $this->assertRaw(' title="'. $test_link_url .'"', "Do we show the link url as the title attribute?");
+    $this->assertNoRaw(' title="['. $field_name .'-url]"');
+    $this->assertTrue(module_exists('token'), t('Assure that Token Module is enabled.'));
+    //$this->fail($this->content);
+  }
+
+  /**
+   * If the title of the link is set to the title attribute, then the title
+   * attribute isn't supposed to show.
+   */
+  function _test_Link_With_Title_Attribute_token_title_form() {
+    $this->loginWithPermissions($this->permissions);
+    $this->acquireContentTypes(1);
+    $field_settings = array(
+      'type' => 'link',
+      'widget_type' => 'link',
+      'type_name' => $this->content_types[0]->name,
+      'attributes' => array(
+        'class' => '',
+        'target' => 'default',
+        'rel' => 'nofollow',
+        'title' => '',
+      ),
+    );
+
+    $field = $this->createField($field_settings, 0);
+    $field_name = $field['field_name'];
+    $field_db_info = content_database_info($field);
+    $url_type = str_replace('_', '-', $this->content_types[0]->type);
+
+    $edit = array('attributes[title]' => '['. $field_name .'-title]',
+                  'enable_tokens' => TRUE);
+
+    $this->drupalPost('admin/content/node-type/'. $url_type .'/fields/'. $field['field_name'],
+                      $edit, t('Save field settings'));
+    $this->assertText(t('Saved field @field_name', array('@field_name' => $field['field_name'])));
+
+    // So, having saved this field_name, let's see if it works...
+    $this->acquireNodes(1);
+
+    $node = node_load($this->nodes[0]->nid);
+
+    $this->drupalGet('node/'. $this->nodes[0]->nid);
+
+    $edit = array();
+    $edit[$field['field_name'] .'[0][url]'] = 'http://www.example.com/test';
+    $title = 'title_'. $this->randomName(20);
+    $edit[$field['field_name'] .'[0][title]'] = $title;
+
+    $this->drupalPost('node/'. $this->nodes[0]->nid .'/edit', $edit, t('Save'));
+
+    // Make sure we get a new version!
+    $node = node_load($this->nodes[0]->nid, NULL, TRUE);
+    $this->assertText(t('@type @title has been updated.',
+                        array('@title' => $node->title,
+                              '@type' => $this->content_types[0]->name)));
+
+    $this->drupalGet('node/'. $node->nid);
+    $this->assertText($title, 'Make sure the link title/text shows');
+    $this->assertNoRaw(' title="'. $title .'"', "We should not show the link title as the title attribute?");
+    $this->assertNoRaw(' title="['. $field_name .'-title]"');
+    //$this->fail($this->content);
+  }
+
+  /**
+   *  Trying to set the url to contain a token.
+   */
+  function _testUserTokenLinkCreateInURL() {
+    $this->web_user = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($this->web_user);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      '_add_new_field[label]' => $name,
+      '_add_new_field[field_name]' => $name,
+      '_add_new_field[type]' => 'link',
+      '_add_new_field[widget_type]' => 'link',
+    );
+    $this->drupalPost('admin/content/node-type/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(
+      'title' => 'required',
+      'enable_tokens' => 1), t('Save field settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Added field %label.', array('%label' => $name)), 'Field added');
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField($field_name . '[0][title]', 'Title found');
+    $this->assertField($field_name . '[0][url]', 'URL found');
+
+    $input = array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+    );
+
+    $this->drupalLogin($this->web_user);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $input['label'],
+      $field_name . '[0][title]' => $input['label'],
+      $field_name . '[0][url]' => $input['href'] . "/[type]",
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($input['label'], $input['href'] .'/page'));
+    //$this->fail($this->content);
+  }
+
+  /**
+   *  Trying to set the url to contain a token.
+   */
+  function _testUserTokenLinkCreateInURL2() {
+    $this->web_user = $this->drupalCreateUser(array('administer content types', 'access content', 'create page content'));
+    $this->drupalLogin($this->web_user);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      '_add_new_field[label]' => $name,
+      '_add_new_field[field_name]' => $name,
+      '_add_new_field[type]' => 'link',
+      '_add_new_field[widget_type]' => 'link',
+    );
+    $this->drupalPost('admin/content/node-type/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(
+      'title' => 'required',
+      'enable_tokens' => 1), t('Save field settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Added field %label.', array('%label' => $name)), 'Field added');
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField($field_name . '[0][title]', 'Title found');
+    $this->assertField($field_name . '[0][url]', 'URL found');
+
+    $input = array(
+        'href' => 'http://example.com/' . $this->randomName(),
+        'label' => $this->randomName(),
+    );
+
+    $this->drupalLogin($this->web_user);
+    $this->drupalGet('node/add/page');
+
+    $edit = array(
+      'title' => $input['label'],
+      $field_name . '[0][title]' => $input['label'],
+      $field_name . '[0][url]' => $input['href'] . "/[author-uid]",
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $url = $this->getUrl();
+
+    // change to anonymous user
+    $this->drupalLogout();
+    $this->drupalGet($url);
+
+    $this->assertRaw(l($input['label'], $input['href'] .'/'. $this->web_user->uid));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/tests/link.validate.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,494 @@
+<?php
+
+/**
+ * @file
+ * Tests that exercise the validation functions in the link module.
+ */
+
+class LinkValidateTestCase extends LinkBaseTestClass {
+
+  protected function createLink($url, $title, $attributes = array()) {
+    return array(
+      'url' => $url,
+      'title' => $title,
+      'attributes' => $attributes,
+    );
+  }
+
+  /**
+   * Takes a url, and sees if it can validate that the url is valid.
+   */
+  protected function link_test_validate_url($url) {
+
+    $field_name = $this->createLinkField();
+
+    $permission = 'create page content';
+    $this->checkPermissions(array($permission), TRUE);
+
+    $this->drupalGet('node/add/page');
+
+    $label = $this->randomName();
+    $edit = array(
+      'title' => $label,
+      $field_name . '[und][0][title]' => $label,
+      $field_name . '[und][0][url]' => $url,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertRaw(t(' has been created.'), 'Node created');
+
+    $nid = 1; //$matches[1];
+
+    $node = node_load($nid);
+
+    $this->assertEqual($url, $node->{$field_name}['und'][0]['url']);
+  }
+}
+
+class LinkValidateTest extends LinkValidateTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link Validation Tests',
+      'description' => 'Tests the field validation.',
+      'group' => 'Link',
+    );
+  }
+
+  function test_link_validate_basic_url() {
+    $this->link_test_validate_url('http://www.example.com');
+  }
+
+  /**
+   * Test if we're stopped from posting a bad url on default validation.
+   */
+  function test_link_validate_bad_url_validate_default() {
+    $this->web_user = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'administer filters',
+                                             'access content',
+                                             'create page content',
+                                             'access administration pages'));
+    $this->drupalLogin($this->web_user);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array(), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField('edit-field-'. $name .'-und-0-title', 'Title found');
+    $this->assertField('edit-field-'. $name .'-und-0-url', 'URL found');
+
+
+    $edit = array(
+      'title' => 'Simple Title',
+      $field_name .'[und][0][url]' => 'edik:naw',
+    );
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('The value provided for @field is not a valid URL.', array('@field' => $name)));
+  }
+
+  /**
+   * Test if we're stopped from posting a bad url with validation on.
+   */
+  function test_link_validate_bad_url_validate_on() {
+    $this->web_user = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'administer filters',
+                                             'access content',
+                                             'create page content',
+                                             'access administration pages'));
+    $this->drupalLogin($this->web_user);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array('instance[settings][validate_url]' => TRUE), t('Save settings'));
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField('edit-field-'. $name .'-und-0-title', 'Title found');
+    $this->assertField('edit-field-'. $name .'-und-0-url', 'URL found');
+
+
+    $edit = array(
+      'title' => 'Simple Title',
+      $field_name .'[und][0][url]' => 'edik:naw',
+    );
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertText(t('The value provided for @field is not a valid URL.', array('@field' => $name)));
+
+  }
+
+  /**
+   * Test if we can post a bad url if the validation is expressly turned off.
+   */
+  function test_link_validate_bad_url_validate_off() {
+    $this->web_user = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'administer filters',
+                                             'access content',
+                                             'create page content',
+                                             'access administration pages'));
+    $this->drupalLogin($this->web_user);
+
+    // create field
+    $name = strtolower($this->randomName());
+    $edit = array(
+      'fields[_add_new_field][label]' => $name,
+      'fields[_add_new_field][field_name]' => $name,
+      'fields[_add_new_field][type]' => 'link_field',
+      'fields[_add_new_field][widget_type]' => 'link_field',
+    );
+    $this->drupalPost('admin/structure/types/manage/page/fields', $edit, t('Save'));
+    $this->drupalPost(NULL, array(), t('Save field settings'));
+    $this->drupalPost(NULL, array('instance[settings][validate_url]' => FALSE), t('Save settings'));
+
+    /*$instance_details = db_query("SELECT * FROM {field_config_instance} WHERE field_name = :field_name AND bundle = 'page'", array(':field_name' => 'field_'. $name))->fetchObject();
+    $this->fail('<pre>'. print_r($instance_details, TRUE) .'</pre>');
+    $this->fail('<pre>'. print_r(unserialize($instance_details->data), TRUE) .'</pre>');*/
+
+    // Is field created?
+    $this->assertRaw(t('Saved %label configuration', array('%label' => $name)), 'Field added');
+    node_types_rebuild();
+    menu_rebuild();
+
+    // create page form
+    $this->drupalGet('node/add/page');
+    $field_name = 'field_' . $name;
+    $this->assertField('edit-field-'. $name .'-und-0-title', 'Title found');
+    $this->assertField('edit-field-'. $name .'-und-0-url', 'URL found');
+
+
+    $edit = array(
+      'title' => 'Simple Title',
+      $field_name .'[und][0][url]' => 'edik:naw',
+    );
+
+    $this->drupalPost(NULL, $edit, t('Save'));
+    $this->assertNoText(t('The value provided for @field is not a valid URL.', array('@field' => $name)));
+  }
+
+  /**
+   * Test if a bad url can sneak through un-filtered if we play with the validation...
+   */
+  function x_test_link_validate_switching_between_validation_status() {
+    $this->acquireContentTypes(1);
+    $this->web_user = $this->drupalCreateUser(array('administer content types',
+                                             'administer nodes',
+                                             'access administration pages',
+                                             'access content',
+                                             'create '. $this->content_types[0]->type .' content',
+                                             'edit any '. $this->content_types[0]->type .' content'));
+    $this->drupalLogin($this->web_user);
+    variable_set('node_options_'. $this->content_types[0]->name, array('status', 'promote'));
+    $field_settings = array(
+      'type' => 'link',
+      'widget_type' => 'link',
+      'type_name' => $this->content_types[0]->name,
+      'attributes' => array(), // <-- This is needed or we have an error
+      'validate_url' => 0,
+    );
+
+    $field = $this->createField($field_settings, 0);
+    //$this->fail('<pre>'. print_r($field, TRUE) .'</pre>');
+    $field_db_info = content_database_info($field);
+
+    $this->acquireNodes(2);
+
+    $node = node_load($this->nodes[0]->nid);
+
+    $this->drupalGet('node/'. $this->nodes[0]->nid);
+
+    $edit = array();
+    $title = $this->randomName();
+    $url = 'javascript:alert("http://example.com/' . $this->randomName() . '")';
+    $edit[$field['field_name'] .'[0][url]'] = $url;
+    $edit[$field['field_name'] .'[0][title]'] = $title;
+
+    $this->drupalPost('node/'. $this->nodes[0]->nid .'/edit', $edit, t('Save'));
+    //$this->pass($this->content);
+    $this->assertNoText(t('The value provided for %field is not a valid URL.', array('%field' => $name)));
+
+    // Make sure we get a new version!
+    $node = node_load($this->nodes[0]->nid, NULL, TRUE);
+    $this->assertEqual($url, $node->{$field['field_name']}[0]['url']);
+
+    $this->drupalGet('node/'. $node->nid);
+    $this->assertNoRaw($url, 'Make sure Javascript does not display.');
+
+    // Turn the array validation back _on_.
+    $edit = array('validate_url' => TRUE);
+    $node_type_link = str_replace('_', '-', $node->type);
+    //$this->drupalGet('admin/content/node-type/'. $node_type_link .'/fields'); ///'. $field['field_name']);
+    //$this->fail($this->content);
+    $this->drupalPost('admin/content/node-type/'. $node_type_link .'/fields/'. $field['field_name'], $edit, t('Save field settings'));
+
+    $this->drupalGet('node/'. $node->nid);
+    // This actually works because the display_url goes through the core
+    // url() function.  But we should have a test that makes sure it continues
+    // to work.
+    $this->assertNoRaw($url, 'Make sure Javascript does not display.');
+    //$this->fail($this->content);
+
+  }
+
+  // Validate that '<front>' is a valid url.
+  function test_link_front_url() {
+    $this->link_test_validate_url('<front>');
+  }
+
+  // Validate that an internal url would be accepted.
+  function test_link_internal_url() {
+    $this->link_test_validate_url('node/32');
+  }
+
+  // Validate a simple mailto.
+  function test_link_mailto() {
+    $this->link_test_validate_url('mailto:jcfiala@gmail.com');
+  }
+
+  function test_link_external_https() {
+    $this->link_test_validate_url('https://www.example.com/');
+  }
+
+  function test_link_ftp() {
+    $this->link_test_validate_url('ftp://www.example.com/');
+  }
+}
+
+class LinkValidateTestNews extends LinkValidateTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link News Validation Tests',
+      'description' => 'Tests the field validation for usenet urls.',
+      'group' => 'Link',
+    );
+  }
+
+  // Validate a news link to a message group
+  function test_link_news() {
+    $this->link_test_validate_url('news:comp.infosystems.www.misc');
+  }
+
+  // Validate a news link to a message id.  Said ID copied off of google groups.
+  function test_link_news_message() {
+    $this->link_test_validate_url('news:hj0db8$vrm$1@news.eternal-september.org');
+  }
+}
+
+class LinkValidateSpecificURL extends LinkValidateTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Link Specific URL Validation Tests',
+      'description' => 'Tests field validation with unusual urls',
+      'group' => 'Link',
+    );
+  }
+
+  // Lets throw in a lot of umlouts for testing!
+  function test_umlout_url() {
+    $this->link_test_validate_url('http://üÜü.exämple.com/nöde');
+  }
+
+  function test_umlout_mailto() {
+    $this->link_test_validate_url('mailto:Üser@exÅmple.com');
+  }
+
+  function test_german_b_url() {
+    $this->link_test_validate_url('http://www.test.com/ßstuff');
+  }
+
+  function test_special_n_url() {
+    $this->link_test_validate_url('http://www.testÑñ.com/');
+  }
+
+  function test_curly_brackets_in_query() {
+    $this->link_test_validate_url('http://www.healthyteennetwork.org/index.asp?Type=B_PR&SEC={2AE1D600-4FC6-4B4D-8822-F1D5F072ED7B}&DE={235FD1E7-208D-4363-9854-4E6775EB8A4C}');
+  }
+
+  /**
+   * Here, we're testing that a very long url is stored properly in the db.
+   *
+   * Basicly, trying to test http://drupal.org/node/376818
+   */
+  function testLinkURLFieldIsBig() {
+    $long_url = 'http://th.wikipedia.org/wiki/%E0%B9%82%E0%B8%A3%E0%B8%87%E0%B9%80%E0%B8%A3%E0%B8%B5%E0%B8%A2%E0%B8%99%E0%B9%80%E0%B8%9A%E0%B8%8D%E0%B8%88%E0%B8%A1%E0%B8%A3%E0%B8%B2%E0%B8%8A%E0%B8%B9%E0%B8%97%E0%B8%B4%E0%B8%A8_%E0%B8%99%E0%B8%84%E0%B8%A3%E0%B8%A8%E0%B8%A3%E0%B8%B5%E0%B8%98%E0%B8%A3%E0%B8%A3%E0%B8%A1%E0%B8%A3%E0%B8%B2%E0%B8%8A';
+    $this->link_test_validate_url($long_url);
+  }
+
+}
+
+/**
+ * A series of tests of links, only going against the link_validate_url function in link.module.
+ *
+ * Validation is guided by the rules in http://tools.ietf.org/html/rfc1738 !
+ */
+class LinkValidateUrlLight extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Link Light Validation Tests',
+      'description' => 'Tests the link_validate_url() function by itself, without invoking the full drupal/cck lifecycle.',
+      'group' => 'Link',
+    );
+  }
+
+  /**
+   * Translates the LINK type constants to english for display and debugging of tests
+   */
+  function name_Link_Type($type) {
+    switch ($type) {
+      case LINK_FRONT:
+        return "Front";
+      case LINK_EMAIL:
+        return "Email";
+      case LINK_NEWS:
+        return "Newsgroup";
+      case LINK_INTERNAL:
+        return "Internal Link";
+      case LINK_EXTERNAL:
+        return "External Link";
+      case FALSE:
+        return "Invalid Link";
+      default:
+        return "Bad Value:". $type;
+    }
+  }
+
+  // Make sure that a link labelled <front> works.
+  function testValidateFrontLink() {
+    $valid = link_validate_url('<front>');
+    $this->assertEqual(LINK_FRONT, $valid, 'Make sure that front link is verfied and identified');
+  }
+
+  function testValidateEmailLink() {
+    $valid = link_validate_url('mailto:bob@example.com');
+    $this->assertEqual(LINK_EMAIL, $valid, "Make sure a basic mailto is verified and identified");
+  }
+
+  function testValidateEmailLinkBad() {
+    $valid = link_validate_url(':bob@example.com');
+    $this->assertEqual(FALSE, $valid, 'Make sure just a bad address is correctly failed');
+  }
+
+  function testValidateNewsgroupLink() {
+    $valid = link_validate_url('news:comp.infosystems.www.misc');
+    $this->assertEqual(LINK_NEWS, $valid, 'Make sure link to newsgroup validates as news.');
+  }
+
+  function testValidateNewsArticleLink() {
+    $valid = link_validate_url('news:hj0db8$vrm$1@news.eternal-september.org');
+    $this->assertEqual(LINK_NEWS, $valid, 'Make sure link to specific article valiates as news.');
+  }
+
+  function testValidateBadNewsgroupLink() {
+    $valid = link_validate_url('news:comp.bad_name.misc');
+    $this->assertEqual(FALSE, $valid, 'newsgroup names can\'t contain underscores, so it should come back as invalid.');
+  }
+
+  function testValidateInternalLinks() {
+    $links = array(
+      'node/5',
+      'rss.xml',
+      'files/test.jpg',
+      '/var/www/test',
+    );
+    
+    foreach ($links as $link) {
+      $valid = link_validate_url($link);
+      $this->assertEqual(LINK_INTERNAL, $valid, 'Test ' . $link . ' internal link.');
+    }
+  }
+
+  function testValidateExternalLinks() {
+    $links = array(
+      'http://localhost:8080/',
+      'www.example.com',
+      'www.example.com/',
+      'http://username:p%40ssw0rd!@www.example.com/',
+      'http://@www.example.com/',
+      'http://username:@www.example.com/',
+      'http://username:password@www.example.com:8080/',
+      'http://127.0.0.1:80/',
+      'http://127.173.24.255:4723/',
+      '127.173.24.255:4723/',
+      'http://255.255.255.255:4823/',
+      'www.test-site.com',
+      'http://example.com/index.php?q=node/123',
+      'http://example.com/index.php?page=this\that',
+      'http://example.com/?first_name=Joe Bob&last_name=Smith',
+      // Anchors
+      'http://www.example.com/index.php#test',
+      'http://www.example.com/index.php#this@that.',
+      'http://www.example.com/index.php#',
+      'http://www.cnn.com/video/#/video/politics/2008/12/09/intv.madeleine.albright.cnn',
+      'http://www.archive.org/stream/aesopsfables00aesorich#page/n7/mode/2up',
+      'http://www.example.com/blah/#this@that?',
+    );
+    // Test all of the protocols.
+    $allowed_protocols = variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'));
+    foreach ($allowed_protocols as $protocol) {
+      if ($protocol !== 'news' && $protocol !== 'mailto') {
+        $links[] = $protocol .'://www.example.com';
+      }
+    }
+    foreach ($links as $link) {
+      $valid = link_validate_url($link);
+      $this->assertEqual(LINK_EXTERNAL, $valid, 'Testing that '. $link .' is a valid external link.');
+      // The following two lines are commented out and only used for comparisons.
+      //$valid2 = valid_url($link, TRUE);
+      //$this->assertEqual(TRUE, $valid2, "Using valid_url() on $link.");
+    }
+    // Test if we can make a tld valid:
+    variable_set('link_extra_domains', array('frog'));
+    $valid = link_validate_url('http://www.example.frog');
+    $this->assertEqual(LINK_EXTERNAL, $valid, "Testing that http://www.example.frog is a valid external link if we've added 'frog' to the list of valid domains.");
+  }
+
+  function testInvalidExternalLinks() {
+    $links = array(
+      'http://www.ex ample.com/',
+      'http://25.0.0/', // bad ip!
+      'http://4827.0.0.2/',
+      '//www.example.com/',
+      'http://www.testß.com/', // ß not allowed in domain names!
+      'http://www.example.frog/', // Bad TLD
+      //'http://www.-fudge.com/', // domains can't have sections starting with a dash.
+    );
+    foreach ($links as $link) {
+      $valid = link_validate_url($link);
+      $this->assertEqual(FALSE, $valid, 'Testing that '. $link .' is not a valid link.');
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/views/link.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,113 @@
+<?php
+/**
+ * @file
+ * Contains functions handling views integration.
+ */
+
+/**
+ * Implementation of hook_views_handlers().
+ */
+/*function link_views_handlers() {
+  return array(
+    'info' => array(
+      'path' => drupal_get_path('module', 'link') .'/views',
+    ),
+    'handlers' => array(
+      'link_views_handler_argument_target' => array(
+        'parent' => 'views_handler_argument',
+      ),
+      'link_views_handler_filter_protocol' => array(
+        'parent' => 'views_handler_filter_string',
+      ),
+    ),
+  );
+}*/
+
+/**
+ * Return CCK Views data for the link_field_settings($op == 'views data').
+ *
+ * @TODO: Is there some way to tell views I have formatters for it?
+ */
+/*function link_views_content_field_data($field) {
+  // Build the automatic views data provided for us by CCK.
+  // This creates all the information necessary for the "url" field.
+  $data = content_views_field_views_data($field);
+
+  $db_info = content_database_info($field);
+  $table_alias = content_views_tablename($field);
+  $field_types = _content_field_types();
+
+  // Tweak the automatic views data for the link "url" field.
+  // Set the filter title to "@label URL"
+  $data[$table_alias][$field['field_name'] .'_url']['filter']['title'] = t('@label URL', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']);
+  // Remove the argument handling for URLs.
+  unset($data[$table_alias][$field['field_name'] .'_url']['argument']);
+
+  // Build out additional views data for the link "title" field.
+  $data[$table_alias][$field['field_name'] .'_title'] = array(
+    'group' => t('Content'),
+    'title' => t('@label title', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+    'help' =>  $data[$table_alias][$field['field_name'] .'_url']['help'],
+    'argument' => array(
+      'field' => $db_info['columns']['title']['column'],
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_argument_string',
+      'click sortable' => TRUE,
+      'name field' => '', // TODO, mimic content.views.inc :)
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+    'filter' => array(
+      'field' => $db_info['columns']['title']['column'],
+      'title' => t('@label title', array('@label' => t($field_types[$field['type']]['label']))),
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_filter_string',
+      'additional fields' => array(),
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+    'sort' => array(
+      'field' => $db_info['columns']['title']['column'],
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_sort',
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+  );
+
+  // Build out additional Views filter for the link "protocol" pseudo field.
+  // TODO: Add a protocol argument.
+  $data[$table_alias][$field['field_name'] .'_protocol'] = array(
+    'group' => t('Content'),
+    'title' => t('@label protocol', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+    'help' =>  $data[$table_alias][$field['field_name'] .'_url']['help'],
+    'filter' => array(
+      'field' => $db_info['columns']['url']['column'],
+      'title' => t('@label protocol', array('@label' => t($field_types[$field['type']]['label']))),
+      'tablename' => $db_info['table'],
+      'handler' => 'link_views_handler_filter_protocol',
+      'additional fields' => array(),
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+  );
+
+  // Build out additional Views argument for the link "target" pseudo field.
+  // TODO: Add a target filter.
+  $data[$table_alias][$field['field_name'] .'_target'] = array(
+    'group' => t('Content'),
+    'title' => t('@label target', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+    'help' =>  $data[$table_alias][$field['field_name'] .'_url']['help'],
+    'argument' => array(
+      'field' => $db_info['columns']['attributes']['column'],
+      'title' => t('@label target', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+      'tablename' => $db_info['table'],
+      'handler' => 'link_views_handler_argument_target',
+      'additional fields' => array(),
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+  );
+
+  return $data;
+}*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/views/link_views_handler_argument_target.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * @file
+ * Argument handler to filter results by target.
+ */
+
+/**
+ * Argument handler to filter results by target.
+ */
+class link_views_handler_argument_target extends views_handler_argument {
+
+  /**
+   * Provide defaults for the argument when a new one is created.
+   */
+  function options(&$options) {
+    parent::options($options);
+  }
+
+  /**
+   * Provide a default options form for the argument.
+   */
+  function options_form(&$form, &$form_state) {
+    $defaults = $this->default_actions();
+
+    $form['title'] = array(
+      '#prefix' => '<div class="clear-block">',
+      '#suffix' => '</div>',
+      '#type' => 'textfield',
+      '#title' => t('Title'),
+      '#default_value' => $this->options['title'],
+      '#description' => t('The title to use when this argument is present; it will override the title of the view and titles from previous arguments. You can use percent substitution here to replace with argument titles. Use "%1" for the first argument, "%2" for the second, etc.'),
+    );
+
+    $form['clear_start'] = array(
+      '#value' => '<div class="clear-block">',
+    );
+
+    $form['defaults_start'] = array(
+      '#value' => '<div class="views-left-50">',
+    );
+
+    $form['default_action'] = array(
+      '#type' => 'radios',
+      '#title' => t('Action to take if argument is not present'),
+      '#default_value' => $this->options['default_action'],
+    );
+
+    $form['defaults_stop'] = array(
+      '#value' => '</div>',
+    );
+
+    $form['wildcard'] = array(
+      '#prefix' => '<div class="views-right-50">',
+      // prefix and no suffix means these two items will be grouped together.
+      '#type' => 'textfield',
+      '#title' => t('Wildcard'),
+      '#size' => 20,
+      '#default_value' => $this->options['wildcard'],
+      '#description' => t('If this value is received as an argument, the argument will be ignored; i.e, "all values"'),
+    );
+
+    $form['wildcard_substitution'] = array(
+      '#suffix' => '</div>',
+      '#type' => 'textfield',
+      '#title' => t('Wildcard title'),
+      '#size' => 20,
+      '#default_value' => $this->options['wildcard_substitution'],
+      '#description' => t('The title to use for the wildcard in substitutions elsewhere.'),
+    );
+
+    $form['clear_stop'] = array(
+      '#value' => '</div>',
+    );
+
+    $options = array();
+    $validate_options = array();
+    foreach ($defaults as $id => $info) {
+      $options[$id] = $info['title'];
+      if (empty($info['default only'])) {
+        $validate_options[$id] = $info['title'];
+      }
+      if (!empty($info['form method'])) {
+        $this->{$info['form method']}($form, $form_state);
+      }
+    }
+
+    $form['default_action']['#options'] = $options;
+
+    $form['validate_type'] = array(
+      '#type' => 'select',
+      '#title' => t('Validator'),
+      '#default_value' => $this->options['validate_type'],
+    );
+
+    $validate_types = array('none' => t('- Basic validation -'));
+    $plugins = views_fetch_plugin_data('argument validator');
+    foreach ($plugins as $id => $info) {
+      $valid = TRUE;
+      if (!empty($info['type'])) {
+        $valid = FALSE;
+        if (empty($this->definition['validate type'])) {
+          continue;
+        }
+        foreach ((array) $info['type'] as $type) {
+          if ($type == $this->definition['validate type']) {
+            $valid = TRUE;
+            break;
+          }
+        }
+      }
+
+      // If we decide this validator is ok, add it to the list.
+      if ($valid) {
+        $plugin = views_get_plugin('argument validator', $id);
+        if ($plugin) {
+          $plugin->init($this->view, $this, $id);
+          if ($plugin->access()) {
+            $plugin->validate_form($form, $form_state, $id);
+            $validate_types[$id] = $info['title'];
+          }
+        }
+      }
+    }
+
+    asort($validate_types);
+    $form['validate_type']['#options'] = $validate_types;
+    // Show this gadget if *anything* but 'none' is selected
+
+    $form['validate_fail'] = array(
+      '#type' => 'select',
+      '#title' => t('Action to take if argument does not validate'),
+      '#default_value' => $this->options['validate_fail'],
+      '#options' => $validate_options,
+    );
+  }
+
+  /**
+   * Set up the query for this argument.
+   *
+   * The argument sent may be found at $this->argument.
+   */
+  function query($group_by = FALSE) {
+    $this->ensure_my_table();
+    // Because attributes are stored serialized, our only option is to also
+    // serialize the data we're searching for and use LIKE to find similar data.
+    $this->query->add_where(0, $this->table_alias . '.' . $this->real_field . " LIKE '%%%s%'", serialize(array('target' => $this->argument)));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/link/views/link_views_handler_filter_protocol.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,107 @@
+<?php
+
+/**
+ * @file
+ * Contains filter handlers for protocol filters with views.
+ */
+
+/**
+ * Filter handler for limiting a view to URLs of a certain protocol.
+ */
+class link_views_handler_filter_protocol extends views_handler_filter_string {
+  /**
+   * Set defaults for the filter options.
+   */
+  function options(&$options) {
+    parent::options($options);
+    $options['operator'] = 'OR';
+    $options['value'] = 'http';
+    $options['case'] = 0;
+  }
+
+  /**
+   * Define the operators supported for protocols.
+   */
+  function operators() {
+    $operators = array(
+      'OR' => array(
+        'title' => t('Is one of'),
+        'short' => t('='),
+        'method' => 'op_protocol',
+        'values' => 1,
+      ),
+    );
+
+    return $operators;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['case'] = array(
+      '#type' => 'value',
+      '#value' => 0,
+    );
+  }
+
+  /**
+   * Provide a select list to choose the desired protocols.
+   */
+  function value_form(&$form, &$form_state) {
+    // We have to make some choices when creating this as an exposed
+    // filter form. For example, if the operator is locked and thus
+    // not rendered, we can't render dependencies; instead we only
+    // render the form items we need.
+    $which = 'all';
+    if (!empty($form_state['exposed']) && empty($this->options['expose']['operator'])) {
+      $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $form['value'] = array(
+        '#type' => 'select',
+        '#title' => t('Protocol'),
+        '#default_value' => $this->value,
+        '#options' => drupal_map_assoc(variable_get('filter_allowed_protocols', array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'))),
+        '#multiple' => 1,
+        '#size' => 4,
+        '#description' => t('The protocols displayed here are those globally available. You may add more protocols by modifying the <em>filter_allowed_protocols</em> variable in your installation.'),
+      );
+    }
+  }
+
+  /**
+   * Filter down the query to include only the selected protocols.
+   */
+  function op_protocol($field, $upper) {
+    $db_type = db_driver();
+
+    $protocols = $this->value;
+
+    $where_conditions = array();
+    foreach ($protocols as $protocol) {
+      // Simple case, the URL begins with the specified protocol.
+      $condition = $field . ' LIKE \'' . $protocol . '%\'';
+
+      // More complex case, no protocol specified but is automatically cleaned up
+      // by link_cleanup_url(). RegEx is required for this search operation.
+      if ($protocol == 'http') {
+        $LINK_DOMAINS = _link_domains();
+        if ($db_type == 'pgsql') {
+          // PostGreSQL code has NOT been tested. Please report any problems to the link issue queue.
+          // pgSQL requires all slashes to be double escaped in regular expressions.
+          // See http://www.postgresql.org/docs/8.1/static/functions-matching.html#FUNCTIONS-POSIX-REGEXP
+          $condition .= ' OR ' . $field .' ~* \''.'^(([a-z0-9]([a-z0-9\\-_]*\\.)+)(' . $LINK_DOMAINS . '|[a-z][a-z]))' . '\'';
+        }
+        else {
+          // mySQL requires backslashes to be double (triple?) escaped within character classes.
+          // See http://dev.mysql.com/doc/refman/5.0/en/string-comparison-functions.html#operator_regexp
+          $condition .= ' OR ' . $field . ' REGEXP \''.'^(([a-z0-9]([a-z0-9\\\-_]*\.)+)(' . $LINK_DOMAINS . '|[a-z][a-z]))' . '\'';
+        }
+      }
+
+      $where_conditions[] = $condition;
+    }
+
+    $this->query->add_where($this->options['group'], implode(' ' . $this->operator . ' ', $where_conditions));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pathologic/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pathologic/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,21 @@
+Pathologic
+----------
+
+Project Page:
+http://drupal.org/project/pathologic
+
+By Garrett Albright
+http://drupal.org/user/191212
+
+Originally sponsored by Precision Intermedia
+http://www.precisionintermedia.com/
+
+Thanks to all who have used this module over the years and provided bug reports
+and suggestions via email and the issue queue! I love you all.
+
+Installation & Configuration
+----------------------------
+
+For full installation and configuration instructions, please see this page in
+the Drupal online manual:
+http://drupal.org/node/257026
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pathologic/pathologic.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by Pathologic.
+ *
+ * @ingroup pathologic
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Allow modules to alter a URL Pathologic is about to create.
+ *
+ * This hook is invoked after Pathologic has torn apart a URL it thinks it can
+ * alter properly and is just about to call the url() function to construct the
+ * new URL. Modules can alter the values that Pathologic is about to send to
+ * url(), or even stop Pathologic from altering a URL entirely.
+ *
+ * @param $url_params
+ *   An array with 'path' and 'options' values, which correspond to the $path
+ *   and $options parameters of the url() function. The 'options' array has an
+ *   extra parameter labeled 'use_original' which is set to FALSE by default.
+ *   This parameter is ignored by url(), but if its value is set to TRUE after
+ *   all alter hook invocations, Pathologic will return the original, unaltered
+ *   path it found in the content instead of calling url() and generating a new
+ *   one. Thus, it provides a way for modules to halt the alteration of paths
+ *   which Pathologic has incorrectly decided should be altered.
+ * @param $parts
+ *   This array contains the result of running parse_url() on the path that
+ *   Pathologic found in content, though Pathologic likely altered some of the
+ *   values in this array since. It contains another parameter, 'original',
+ *   which contains the original URL Pathologic found in the content, unaltered.
+ *   You should not alter this value in any way; to alter how Pathologic
+ *   constructs the new URL, alter $url_params instead.
+ * @param $settings
+ *   This contains the settings Pathologic is using to decide how to alter the
+ *   URL; some settings are from the graphical filter form and alterable by the
+ *   user, while others are determined programmatically. If you're looking for
+ *   the filter settings which Pathologic is currently using (if you've altered
+ *   your own field onto the filter settings form, for example), try looking in
+ *   $settings['current_settings'].
+ *
+ * @see url()
+ * @see parse_url()
+ * @see pathologic_replace()
+ * @see http://drupal.org/node/1762022
+ */
+function hook_pathologic_alter(&$url_params, $parts, $settings) {
+  // If we're linking to the "bananas" subdirectory or something under it, then
+  // have Pathologic pass through the original URL, without altering it.
+  if (preg_match('~^bananas(/.*)?$~', $url_params['path'])) {
+    $url_params['options']['use_original'] = TRUE;
+  }
+
+  // If we're linking to a path like "article/something.html", then prepend
+  // "magazine" to the path, but remove the ".html". The end result will look
+  // like "magazine/article/something".
+  if (preg_match('~^article/(.+)\.html$~', $url_params['path'], $matches)) {
+    $url_params['path'] = 'magazine/article/' . $matches[1];
+  }
+
+  // If the URL doesn't have a "foo" query parameter, then add one.
+  if (!is_array($url_params['options']['query'])) {
+    $url_params['options']['query'] = array();
+  }
+  if (empty($url_params['options']['query']['foo'])) {
+    $url_params['options']['query']['foo'] = 'bar';
+  }
+
+  // If it's a path to a local image, make sure it's using our CDN server.
+  if (preg_match('~\.(png|gif|jpe?g)$', $url_params['path'])) {
+    $url_params['path'] = 'http://cdn.example.com/' . $url_params['path'];
+    $url_params['options']['external'] = TRUE;
+  }
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pathologic/pathologic.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Pathologic
+description = Helps avoid broken links and incorrect paths in content.
+package = "Input filters"
+dependencies[] = filter
+core = 7.x
+files[] = pathologic.test
+
+; Information added by drupal.org packaging script on 2013-07-09
+version = "7.x-2.11"
+core = "7.x"
+project = "pathologic"
+datestamp = "1373385363"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pathologic/pathologic.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * .install file for Pathologic.
+ */
+
+/**
+ * Re-enable Pathologic under Drupal 7, preserving settings from Drupal 6.
+ */
+function pathologic_update_7000($sandbox) {
+  // Make sure {d6_upgrade_filter} exists. It won't exist for people upgrading
+  // from beta versions of the D7 version of Pathologic on native D7 sites (not
+  // upgraded from D6).
+  if (db_table_exists('d6_upgrade_filter')) {
+    // Get all Pathologic data from {d6_upgrade_filter}.
+    $rez = db_select('d6_upgrade_filter', 'dup')
+      ->fields('dup')
+      ->condition('module', 'pathologic')
+      ->execute();
+    while ($instance = $rez->fetchObject()) {
+      // Load the format
+      if ($format = filter_format_load($instance->format)) {
+        // Load filters.
+        $format->filters = array();
+        // Add the filters
+        foreach (filter_list_format($instance->format) as $filter_name => $filter) {
+          $format->filters[$filter_name] = (array)$filter;
+        }
+        // Add Pathologic
+        $format->filters['pathologic'] = array(
+          'weight' => $instance->weight,
+          'status' => 1,
+          'settings' => array(
+            'absolute' => variable_get('filter_pathologic_absolute_' . $instance->format, TRUE),
+            'local_paths' => variable_get('filter_pathologic_local_paths_' . $instance->format, ''),
+          ),
+        );
+        // Save the format
+        filter_format_save($format);
+        // Unset old variables
+        variable_del('filter_pathologic_absolute_' . $instance->format);
+        variable_del('filter_pathologic_local_paths_' . $instance->format);
+      }
+    }
+    // Delete Pathologic data from {d6_upgrade_filter}…?
+    // No, maybe we don't want to actually do that…?
+  }
+}
+
+/**
+ * Convert obsolete "absolute" setting to modern "protocol_style" setting for
+ * each filter instance.
+ */
+function pathologic_update_7200(&$sandbox) {
+  foreach (filter_formats() as $format) {
+    // @see http://drupal.org/node/1304930
+    if (empty($format->filters)) {
+      $format->filters = array();
+      // Add the filters
+      foreach (filter_list_format($format->format) as $filter_name => $filter) {
+        $format->filters[$filter_name] = (array)$filter;
+      }
+    }
+    if (isset($format->filters['pathologic'])) {
+      $format->filters['pathologic']['settings']['protocol_style'] = $format->filters['pathologic']['settings']['absolute'] ? 'full' : 'path';
+      unset($format->filters['pathologic']['settings']['absolute']);
+      filter_format_save($format);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pathologic/pathologic.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,448 @@
+<?php
+
+/**
+ * @file
+ * Pathologic text filter for Drupal.
+ *
+ * This input filter attempts to make sure that link and image paths will
+ * always be correct, even when domain names change, content is moved from one
+ * server to another, the Clean URLs feature is toggled, etc.
+ */
+
+/**
+ * Implements hook_filter_info().
+ */
+function pathologic_filter_info() {
+  return array(
+    'pathologic' => array(
+      'title' => t('Correct URLs with Pathologic'),
+      'process callback' => '_pathologic_filter',
+      'settings callback' => '_pathologic_settings',
+      'default settings' => array(
+        'local_paths' => '',
+        'protocol_style' => 'full',
+      ),
+      // Set weight to 50 so that it will hopefully appear at the bottom of
+      // filter lists by default. 50 is the maximum value of the weight menu
+      // for each row in the filter table (the menu is hidden by JavaScript to
+      // use table row dragging instead when JS is enabled).
+      'weight' => 50,
+    )
+  );
+}
+
+/**
+ * Settings callback for Pathologic.
+ */
+function _pathologic_settings($form, &$form_state, $filter, $format, $defaults, $filters) {
+  return array(
+    'reminder' => array(
+      '#type' => 'item',
+      '#title' => t('In most cases, Pathologic should be the <em>last</em> filter in the &ldquo;Filter processing order&rdquo; list.'),
+      '#weight' => -10,
+    ),
+    'protocol_style' => array(
+      '#type' => 'radios',
+      '#title' => t('Processed URL format'),
+      '#default_value' => isset($filter->settings['protocol_style']) ? $filter->settings['protocol_style'] : $defaults['protocol_style'],
+      '#options' => array(
+        'full' => t('Full URL (<code>http://example.com/foo/bar</code>)'),
+        'proto-rel' => t('Protocol relative URL (<code>//example.com/foo/bar</code>)'),
+        'path' => t('Path relative to server root (<code>/foo/bar</code>)'),
+      ),
+      '#description' => t('The <em>Full URL</em> option is best for stopping broken images and links in syndicated content (such as in RSS feeds), but will likely lead to problems if your site is accessible by both HTTP and HTTPS. Paths output with the <em>Protocol relative URL</em> option will avoid such problems, but feed readers and other software not using up-to-date standards may be confused by the paths. The <em>Path relative to server root</em> option will avoid problems with sites accessible by both HTTP and HTTPS with no compatibility concerns, but will absolutely not fix broken images and links in syndicated content.'),
+      '#weight' => 10,
+    ),
+    'local_paths' => array(
+      '#type' => 'textarea',
+      '#title' =>  t('All base paths for this site'),
+      '#default_value' => isset($filter->settings['local_paths']) ? $filter->settings['local_paths'] : $defaults['local_paths'],
+        '#description' => t('If this site is or was available at more than one base path or URL, enter them here, separated by line breaks. For example, if this site is live at <code>http://example.com/</code> but has a staging version at <code>http://dev.example.org/staging/</code>, you would enter both those URLs here. If confused, please read <a href="!docs">Pathologic&rsquo;s documentation</a> for more information about this option and what it affects.', array('!docs' => 'http://drupal.org/node/257026')),
+      '#weight' => 20,
+    ),
+  );
+}
+
+/**
+ * Pathologic filter callback.
+ *
+ * Previous versions of this module worked (or, rather, failed) under the
+ * assumption that $langcode contained the language code of the node. Sadly,
+ * this isn't the case.
+ * @see http://drupal.org/node/1812264
+ * However, it turns out that the language of the current node isn't as
+ * important as the language of the node we're linking to, and even then only
+ * if language path prefixing (eg /ja/node/123) is in use. REMEMBER THIS IN THE
+ * FUTURE, ALBRIGHT.
+ *
+ * @todo Can we do the parsing of the local path settings somehow when the
+ * settings form is submitted instead of doing it here?
+ */
+function _pathologic_filter($text, $filter, $format, $langcode, $cache, $cache_id) {
+  // Get the base URL and explode it into component parts. We add these parts
+  // to the exploded local paths settings later.
+  global $base_url;
+  $base_url_parts = parse_url($base_url . '/');
+  // Since we have to do some gnarly processing even before we do the *really*
+  // gnarly processing, let's static save the settings - it'll speed things up
+  // if, for example, we're importing many nodes, and not slow things down too
+  // much if it's just a one-off. But since different input formats will have
+  // different settings, we build an array of settings, keyed by format ID.
+  $settings = &drupal_static(__FUNCTION__, array());
+  if (!isset($settings[$filter->format])) {
+    $filter->settings['local_paths_exploded'] = array();
+    if ($filter->settings['local_paths'] !== '') {
+      // Build an array of the exploded local paths for this format's settings.
+      // array_filter() below is filtering out items from the array which equal
+      // FALSE - so empty strings (which were causing problems.
+      // @see http://drupal.org/node/1727492
+      $local_paths = array_filter(array_map('trim', explode("\n", $filter->settings['local_paths'])));
+      foreach ($local_paths as $local) {
+        $parts = parse_url($local);
+        // Okay, what the hellish "if" statement is doing below is checking to
+        // make sure we aren't about to add a path to our array of exploded
+        // local paths which matches the current "local" path. We consider it
+        // not a match, if…
+        // @todo: This is pretty horrible. Can this be simplified?
+        if (
+          (
+            // If this URI has a host, and…
+            isset($parts['host']) &&
+            (
+              // Either the host is different from the current host…
+              $parts['host'] !== $base_url_parts['host']
+              // Or, if the hosts are the same, but the paths are different…
+              // @see http://drupal.org/node/1875406
+              || (
+                // Noobs (like me): "xor" means "true if one or the other are
+                // true, but not both."
+                (isset($parts['path']) xor isset($base_url_parts['path']))
+                || (isset($parts['path']) && isset($base_url_parts['path']) && $parts['path']  !== $base_url_parts['path'])
+              )
+            )
+          ) ||
+          // Or…
+          (
+            // The URI doesn't have a host…
+            !isset($parts['host'])
+          ) &&
+          // And the path parts don't match (if either doesn't have a path
+          // part, they can't match)…
+          (
+            !isset($parts['path']) ||
+            !isset($base_url_parts['path']) ||
+            $parts['path'] !== $base_url_parts['path']
+          )
+        ) {
+          // Add it to the list.
+          $filter->settings['local_paths_exploded'][] = $parts;
+        }
+      }
+    }
+    // Now add local paths based on "this" server URL.
+    $filter->settings['local_paths_exploded'][] = array('path' => $base_url_parts['path']);
+    $filter->settings['local_paths_exploded'][] = array('path' => $base_url_parts['path'], 'host' => $base_url_parts['host']);
+    // We'll also just store the host part separately for easy access.
+    $filter->settings['base_url_host'] = $base_url_parts['host'];
+
+    $settings[$filter->format] = $filter->settings;
+  }
+  // Get the language code for the text we're about to process.
+  $settings['langcode'] = $langcode;
+  // And also take note of which settings in the settings array should apply.
+  $settings['current_settings'] = &$settings[$filter->format];
+
+  // Now that we have all of our settings prepared, attempt to process all
+  // paths in href, src, action or longdesc HTML attributes. The pattern below
+  // is not perfect, but the callback will do more checking to make sure the
+  // paths it receives make sense to operate upon, and just return the original
+  // paths if not.
+  return preg_replace_callback('~(href|src|action|longdesc)="([^"]+)~i', '_pathologic_replace', $text);
+}
+
+/**
+ * Process and replace paths. preg_replace_callback() callback.
+ */
+function _pathologic_replace($matches) {
+  // Get the settings for the filter. Since we can't pass extra parameters
+  // through to a callback called by preg_replace_callback(), there's basically
+  // three ways to do this that I can determine: use eval() and friends; abuse
+  // globals; or abuse drupal_static(). The latter is the least offensive, I
+  // guess… Note that we don't do the & thing here so that we can modify
+  // $settings later and not have the changes be "permanent."
+  $settings = drupal_static('_pathologic_filter');
+  // If it appears the path is a scheme-less URL, prepend a scheme to it.
+  // parse_url() cannot properly parse scheme-less URLs. Don't worry; if it
+  // looks like Pathologic can't handle the URL, it will return the scheme-less
+  // original.
+  
+  // @see https://drupal.org/node/1617944
+  // @see https://drupal.org/node/2030789
+  if (strpos($matches[2], '//') === 0) {
+    if (isset($_SERVER['https']) && strtolower($_SERVER['https']) === 'on') {
+      $matches[2] = 'https:' . $matches[2];
+    }
+    else {
+      $matches[2] = 'http:' . $matches[2];
+    }
+  }
+  // Now parse the URL after reverting HTML character encoding.
+  // @see http://drupal.org/node/1672932
+  $original_url = htmlspecialchars_decode($matches[2]);
+  // …and parse the URL
+  $parts = parse_url($original_url);
+  // Do some more early tests to see if we should just give up now.
+  if (
+    // If parse_url() failed, give up.
+    $parts === FALSE
+    || (
+      // If there's a scheme part and it doesn't look useful, bail out.
+      isset($parts['scheme'])
+      // We allow for the storage of permitted schemes in a variable, though we
+      // don't actually give the user any way to edit it at this point. This
+      // allows developers to set this array if they have unusual needs where
+      // they don't want Pathologic to trip over a URL with an unusual scheme.
+      // @see http://drupal.org/node/1834308
+      // "files" and "internal" are for Path Filter compatibility.
+      && !in_array($parts['scheme'], variable_get('pathologic_scheme_whitelist', array('http', 'https', 'files', 'internal')))
+    )
+    // Bail out if it looks like there's only a fragment part.
+    || (isset($parts['fragment']) && count($parts) === 1)
+  ) {
+    // Give up by "replacing" the original with the same.
+    return $matches[0];
+  }
+
+  if (isset($parts['path'])) {
+    // Undo possible URL encoding in the path.
+    // @see http://drupal.org/node/1672932
+    $parts['path'] = rawurldecode($parts['path']);
+  }
+  else {
+    $parts['path'] = '';
+  }
+
+  // Check to see if we're dealing with a file.
+  // @todo Should we still try to do path correction on these files too?
+  if (isset($parts['scheme']) && $parts['scheme'] === 'files') {
+    // Path Filter "files:" support. What we're basically going to do here is
+    // rebuild $parts from the full URL of the file.
+    $new_parts = parse_url(file_create_url(file_default_scheme() . '://' . $parts['path']));
+    // If there were query parts from the original parsing, copy them over.
+    if (!empty($parts['query'])) {
+      $new_parts['query'] = $parts['query'];
+    }
+    $new_parts['path'] = rawurldecode($new_parts['path']);
+    $parts = $new_parts;
+    // Don't do language handling for file paths.
+    $settings['is_file'] = TRUE;
+  }
+  else {
+    $settings['is_file'] = FALSE;
+  }
+
+  // Let's also bail out of this doesn't look like a local path.
+  $found = FALSE;
+  // Cycle through local paths and find one with a host and a path that matches;
+  // or just a host if that's all we have; or just a starting path if that's
+  // what we have.
+  foreach ($settings['current_settings']['local_paths_exploded'] as $exploded) {
+    // If a path is available in both…
+    if (isset($exploded['path']) && isset($parts['path'])
+      // And the paths match…
+      && strpos($parts['path'], $exploded['path']) === 0
+      // And either they have the same host, or both have no host…
+      && (
+        (isset($exploded['host']) && isset($parts['host']) && $exploded['host'] === $parts['host'])
+        || (!isset($exploded['host']) && !isset($parts['host']))
+      )
+    ) {
+      // Remove the shared path from the path. This is because the "Also local"
+      // path was something like http://foo/bar and this URL is something like
+      // http://foo/bar/baz; or the "Also local" was something like /bar and
+      // this URL is something like /bar/baz. And we only care about the /baz
+      // part.
+      $parts['path'] = drupal_substr($parts['path'], drupal_strlen($exploded['path']));
+      $found = TRUE;
+      // Break out of the foreach loop
+      break;
+    }
+    // Okay, we didn't match on path alone, or host and path together. Can we
+    // match on just host? Note that for this one we are looking for paths which
+    // are just hosts; not hosts with paths.
+    elseif ((isset($parts['host']) && !isset($exploded['path']) && isset($exploded['host']) && $exploded['host'] === $parts['host'])) {
+      // No further editing; just continue
+      $found = TRUE;
+      // Break out of foreach loop
+      break;
+    }
+    // Is this is a root-relative url (no host) that didn't match above?
+    // Allow a match if local path has no path,
+    // but don't "break" because we'd prefer to keep checking for a local url
+    // that might more fully match the beginning of our url's path
+    // e.g.: if our url is /foo/bar we'll mark this as a match for
+    // http://example.com but want to keep searching and would prefer a match
+    // to http://example.com/foo if that's configured as a local path
+    elseif (!isset($parts['host']) && (!isset($exploded['path']) || $exploded['path'] == '/')) {
+      $found = TRUE;
+    }
+  }
+
+  // If the path is not within the drupal root return original url, unchanged
+  if (!$found) {
+    return $matches[0];
+  }
+
+  // Okay, format the URL.
+  // If there's still a slash lingering at the start of the path, chop it off.
+  $parts['path'] = ltrim($parts['path'],'/');
+
+  // Examine the query part of the URL. Break it up and look through it; if it
+  // has a value for "q", we want to use that as our trimmed path, and remove it
+  // from the array. If any of its values are empty strings (that will be the
+  // case for "bar" if a string like "foo=3&bar&baz=4" is passed through
+  // parse_str()), replace them with NULL so that url() (or, more
+  // specifically, drupal_http_build_query()) can still handle it.
+  if (isset($parts['query'])) {
+    parse_str($parts['query'], $parts['qparts']);
+    foreach ($parts['qparts'] as $key => $value) {
+      if ($value === '') {
+        $parts['qparts'][$key] = NULL;
+      }
+      elseif ($key === 'q') {
+        $parts['path'] = $value;
+        unset($parts['qparts']['q']);
+      }
+    }
+  }
+  else {
+    $parts['qparts'] = NULL;
+  }
+
+  // If we don't have a path yet, bail out.
+  if (!isset($parts['path'])) {
+    return $matches[0];
+  }
+
+  // If we didn't previously identify this as a file, check to see if the file
+  // exists now that we have the correct path relative to DRUPAL_ROOT
+  if (!$settings['is_file']){
+    $settings['is_file'] = !empty($parts['path']) && is_file(DRUPAL_ROOT . '/'. $parts['path']);
+  }
+
+  // Okay, deal with language stuff.
+  if ($settings['is_file']) {
+    // If we're linking to a file, use a fake LANGUAGE_NONE language object.
+    // Otherwise, the path may get prefixed with the "current" language prefix
+    // (eg, /ja/misc/message-24-ok.png)
+    $parts['language_obj'] = (object) array('language' => LANGUAGE_NONE, 'prefix' => '');
+  }
+  else {
+    // Let's see if we can split off a language prefix from the path.
+    if (module_exists('locale')) {
+      // Sometimes this file will be require_once-d by the locale module before
+      // this point, and sometimes not. We require_once it ourselves to be sure.
+      require_once DRUPAL_ROOT . '/includes/language.inc';
+      list($language_obj, $path) = language_url_split_prefix($parts['path'], language_list());
+      if ($language_obj) {
+        $parts['path'] = $path;
+        $parts['language_obj'] = $language_obj;
+      }
+    }
+  }
+
+  // If we get to this point and $parts['path'] is now an empty string (which
+  // will be the case if the path was originally just "/"), then we
+  // want to link to <front>.
+  if ($parts['path'] === '') {
+    $parts['path'] = '<front>';
+  }
+  // Build the parameters we will send to url()
+  $url_params = array(
+    'path' => $parts['path'],
+    'options' => array(
+      'query' => $parts['qparts'],
+      'fragment' => isset($parts['fragment']) ? $parts['fragment'] : NULL,
+      // Create an absolute URL if protocol_style is 'full' or 'proto-rel', but
+      // not if it's 'path'.
+      'absolute' => $settings['current_settings']['protocol_style'] !== 'path',
+      // If we seem to have found a language for the path, pass it along to
+      // url(). Otherwise, ignore the 'language' parameter.
+      'language' => isset($parts['language_obj']) ? $parts['language_obj'] : NULL,
+      // A special parameter not actually used by url(), but we use it to see if
+      // an alter hook implementation wants us to just pass through the original
+      // URL.
+      'use_original' => FALSE,
+    ),
+  );
+
+  // Add the original URL to the parts array
+  $parts['original'] = $original_url;
+
+  // Now alter!
+  // @see http://drupal.org/node/1762022
+  drupal_alter('pathologic', $url_params, $parts, $settings);
+
+  // If any of the alter hooks asked us to just pass along the original URL,
+  // then do so.
+  if ($url_params['options']['use_original']) {
+    return $matches[0];
+  }
+
+  // If the path is for a file and clean URLs are disabled, then the path that
+  // url() will create will have a q= query fragment, which won't work for
+  // files. To avoid that, we use this trick to temporarily turn clean URLs on.
+  // This is horrible, but it seems to be the sanest way to do this.
+  // @see http://drupal.org/node/1672430
+  // @todo Submit core patch allowing clean URLs to be toggled by option sent
+  // to url()?
+  if (!empty($settings['is_file'])) {
+    $settings['orig_clean_url'] = !empty($GLOBALS['conf']['clean_url']);
+    if (!$settings['orig_clean_url']) {
+      $GLOBALS['conf']['clean_url'] = TRUE;
+    }
+  }
+
+  // Now for the url() call. Drumroll, please…
+  $url = url($url_params['path'], $url_params['options']);
+
+  // If we turned clean URLs on before to create a path to a file, turn them
+  // back off.
+  if ($settings['is_file'] && !$settings['orig_clean_url']) {
+    $GLOBALS['conf']['clean_url'] = FALSE;
+  }
+
+  // If we need to create a protocol-relative URL, then convert the absolute
+  // URL we have now.
+  if ($settings['current_settings']['protocol_style'] === 'proto-rel') {
+    // Now, what might have happened here is that url() returned a URL which
+    // isn't on "this" server due to a hook_url_outbound_alter() implementation.
+    // We don't want to convert the URL in that case. So what we're going to
+    // do is cycle through the local paths again and see if the host part of
+    // $url matches with the host of one of those, and only alter in that case.
+    $url_parts = parse_url($url);
+    if (!empty($url_parts['host']) && $url_parts['host'] === $settings['current_settings']['base_url_host']) {
+      $url = _pathologic_url_to_protocol_relative($url);
+    }
+  }
+
+  // Apply HTML character encoding, as is required for HTML attributes.
+  // @see http://drupal.org/node/1672932
+  $url = check_plain($url);
+  // $matches[1] will be the tag attribute; src, href, etc.
+  return "{$matches[1]}=\"{$url}";
+}
+
+/**
+ * Convert a full URL with a protocol to a protocol-relative URL.
+ *
+ * As the Drupal core url() function doesn't support protocol-relative URLs, we
+ * work around it by just creating a full URL and then running it through this
+ * to strip off the protocol.
+ *
+ * Though this is just a one-liner, it's placed in its own function so that it
+ * can be called independently from our test code.
+ */
+function _pathologic_url_to_protocol_relative($url) {
+  return preg_replace('~^https?://~', '//', $url);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pathologic/pathologic.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,276 @@
+<?php
+
+/**
+ * @file
+ * Pathologic behavior testing.
+ */
+
+/**
+ * Tests that Pathologic ain't broke.
+ *
+ * We extend FilterUnitTestCase because it has some nice methods that we also
+ * want to be able to use.
+ *
+ * Note to self: The method to pass bits of text through are fail() or pass().
+ */
+class PathologicTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Pathologic path filtering',
+      'description' => 'Test Pathologic&rsquo;s path translation and conversion.',
+      'group' => 'Filter',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('pathologic');
+  }
+
+  function testPathologic() {
+    // Start by testing our function to build protocol-relative URLs
+    $this->assertEqual(
+      _pathologic_url_to_protocol_relative('http://example.com/foo/bar'),
+      '//example.com/foo/bar',
+      t('Protocol-relative URL creation with http:// URL')
+    );
+    $this->assertEqual(
+      _pathologic_url_to_protocol_relative('https://example.org/baz'),
+      '//example.org/baz',
+      t('Protocol-relative URL creation with https:// URL')
+    );
+
+    // Build a phony filter
+    $filter = new stdClass;
+    $filter->callback = '_pathologic';
+    $filter->settings = array(
+      'protocol_style' => 'full',
+      'local_paths' => '',
+    );
+    $filter->format = 0;
+
+    // Build some paths to check against
+    $test_paths = array(
+      'foo' => array(
+        'path' => 'foo',
+        'opts' => array()
+      ),
+      'foo/bar' => array(
+        'path' => 'foo/bar',
+        'opts' => array()
+      ),
+      'foo/bar?baz' => array(
+        'path' => 'foo/bar',
+        'opts' => array('query' => array('baz' => NULL))
+      ),
+      'foo/bar?baz=qux' => array(
+        'path' => 'foo/bar',
+        'opts' => array('query' => array('baz' => 'qux'))
+      ),
+      'foo/bar#baz' => array(
+        'path' => 'foo/bar',
+        'opts' => array('fragment' => 'baz'),
+      ),
+      'foo/bar?baz=qux&amp;quux=quuux#quuuux' => array(
+        'path' => 'foo/bar',
+        'opts' => array(
+          'query' => array('baz' => 'qux', 'quux' => 'quuux'),
+          'fragment' => 'quuuux',
+        ),
+      ),
+      'foo%20bar?baz=qux%26quux' => array(
+        'path' => 'foo bar',
+        'opts' => array(
+          'query' => array('baz' => 'qux&quux'),
+        ),
+      ),
+      '/' => array(
+        'path' => '<front>',
+        'opts' => array(),
+      ),
+    );
+
+    // Run tests with clean URLs both enabled and disabled
+    foreach (array(TRUE, FALSE) as $clean_url) {
+      variable_set('clean_url', $clean_url);
+      // Run tests with absoulte filtering enabled and disabled
+      foreach (array('full', 'proto-rel', 'path') as $protocol_style) {
+        $filter->settings['protocol_style'] = $protocol_style;
+        $filter->format++;
+        $paths = array();
+        foreach ($test_paths as $path => $args) {
+          $args['opts']['absolute'] = $protocol_style !== 'path';
+          $paths[$path] = _pathologic_content_url($args['path'], $args['opts']);
+          if ($protocol_style === 'proto-rel') {
+            $paths[$path] = _pathologic_url_to_protocol_relative($paths[$path]);
+          }
+        }
+        $t10ns = array(
+          '!clean' => $clean_url ? t('Yes') : t('No'),
+          '!ps' => $protocol_style,
+        );
+
+        $this->assertEqual(
+          _pathologic_filter('<a href="foo"><img src="foo/bar" /></a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+          '<a href="' . $paths['foo'] . '"><img src="' . $paths['foo/bar'] . '" /></a>',
+          t('Simple paths. Clean URLs: !clean; protocol style: !ps.', $t10ns)
+        );
+        $this->assertEqual(
+          _pathologic_filter('<form action="foo/bar?baz"><IMG LONGDESC="foo/bar?baz=qux" /></a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+          '<form action="' . $paths['foo/bar?baz'] . '"><IMG LONGDESC="' . $paths['foo/bar?baz=qux'] . '" /></a>',
+          t('Paths with query string. Clean URLs: !clean; protocol style: !ps.', $t10ns)
+        );
+        $this->assertEqual(
+          _pathologic_filter('<a href="foo/bar#baz">', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+          '<a href="' . $paths['foo/bar#baz'] . '">',
+          t('Path with fragment. Clean URLs: !clean; protocol style: !ps.', $t10ns)
+        );
+        $this->assertEqual(
+          _pathologic_filter('<a href="#foo">', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+          '<a href="#foo">',
+          t('Fragment-only links. Clean URLs: !clean; protocol style: !ps.', $t10ns)
+        );
+        $this->assertEqual(
+          _pathologic_filter('<a href="foo/bar?baz=qux&amp;quux=quuux#quuuux">', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+          '<a href="' . $paths['foo/bar?baz=qux&amp;quux=quuux#quuuux'] . '">',
+          t('Path with query string and fragment. Clean URLs: !clean; protocol style: !ps.', $t10ns)
+        );
+        $this->assertEqual(
+          _pathologic_filter('<a href="foo%20bar?baz=qux%26quux">', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+          '<a href="' . $paths['foo%20bar?baz=qux%26quux'] . '">',
+          t('Path with URL encoded parts')
+        );
+        $this->assertEqual(
+          _pathologic_filter('<a href="/"></a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+          '<a href="' . $paths['/'] . '"></a>',
+          t('Path with just slash. Clean URLs: !clean; protocol style: !ps', $t10ns)
+        );
+      }
+    }
+
+    global $base_path;
+    $this->assertEqual(
+      _pathologic_filter('<a href="' . $base_path . 'foo">bar</a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="' . _pathologic_content_url('foo', array('absolute' => FALSE)) .'">bar</a>',
+      t('Paths beginning with $base_path (like WYSIWYG editors like to make)')
+    );
+    global $base_url;
+    $this->assertEqual(
+      _pathologic_filter('<a href="' . $base_url . '/foo">bar</a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="' . _pathologic_content_url('foo', array('absolute' => FALSE)) .'">bar</a>',
+      t('Paths beginning with $base_url')
+    );
+
+    // @see http://drupal.org/node/1617944
+    $this->assertEqual(
+      _pathologic_filter('<a href="//example.com/foo">bar</a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="//example.com/foo">bar</a>',
+      t('Off-site schemeless URLs (//example.com/foo) ignored')
+    );
+
+    // Test internal: and all base paths
+    $filter->settings = array(
+      'protocol_style' => 'full',
+      'local_paths' => "http://example.com/qux\nhttp://example.org\n/bananas",
+    );
+    $filter->format++;
+
+    // @see https://drupal.org/node/2030789
+    $this->assertEqual(
+      _pathologic_filter('<a href="//example.org/foo">bar</a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="' . _pathologic_content_url('foo', array('absolute' => TRUE)) . '">bar</a>',
+      t('On-site schemeless URLs processed')
+    );
+    $this->assertEqual(
+      _pathologic_filter('<a href="internal:foo">', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="' . _pathologic_content_url('foo', array('absolute' => TRUE)) . '">',
+      t('Path Filter compatibility (internal:)')
+    );
+    $this->assertEqual(
+      _pathologic_filter('<a href="files:image.jpeg">', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="' . _pathologic_content_url(file_create_url('public://image.jpeg'), array('absolute' => TRUE, 'is_file' => TRUE)) . '">',
+      t('Path Filter compatibility (files:)')
+    );
+    $this->assertEqual(
+      _pathologic_filter('<a href="http://example.com/qux/foo"><img src="http://example.org/bar.jpeg" longdesc="/bananas/baz" /></a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="' . _pathologic_content_url('foo', array('absolute' => TRUE)) . '"><img src="' . _pathologic_content_url('bar.jpeg', array('absolute' => TRUE)) . '" longdesc="' . _pathologic_content_url('baz', array('absolute' => TRUE)) . '" /></a>',
+      t('"All base paths for this site" functionality')
+    );
+    $this->assertEqual(
+      _pathologic_filter('<a href="webcal:foo">bar</a>', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="webcal:foo">bar</a>',
+      t('URLs with likely protocols are ignored')
+    );
+    // Test hook_pathologic_alter() implementation.
+    $this->assertEqual(
+      _pathologic_filter('<a href="foo?test=add_foo_qpart">', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="' . _pathologic_content_url('foo', array('absolute' => TRUE, 'query' => array('test' => 'add_foo_qpart', 'foo' => 'bar'))) . '">',
+      t('hook_pathologic_alter(): Alter $url_params')
+    );
+    $this->assertEqual(
+      _pathologic_filter('<a href="bar?test=use_original">', $filter, NULL, LANGUAGE_NONE, NULL, NULL),
+      '<a href="bar?test=use_original">',
+      t('hook_pathologic_alter(): Passthrough with use_original option')
+    );
+
+    // Test paths to existing files when clean URLs are disabled.
+    // @see http://drupal.org/node/1672430
+    variable_set('clean_url', FALSE);
+    $filtered_tag = _pathologic_filter('<img src="misc/druplicon.png" />', $filter, NULL, LANGUAGE_NONE, NULL, NULL);
+    $this->assertTrue(
+      strpos($filtered_tag, 'q=') === FALSE,
+      t('Paths to files don\'t have ?q= when clean URLs are off')
+    );
+
+
+  }
+}
+
+/**
+ * Wrapper around url() which does HTML entity decoding and encoding.
+ *
+ * Since Pathologic works with paths in content, it needs to decode paths which
+ * have been HTML-encoded, and re-encode them when done. This is a wrapper
+ * around url() which does the same thing so that we can expect the results
+ * from it and from Pathologic to still match in our tests.
+ *
+ * @see url()
+ * @see http://drupal.org/node/1672932
+ * @see http://www.w3.org/TR/xhtml1/guidelines.html#C_12
+ */
+function _pathologic_content_url($path, $options) {
+  // If we should pretend this is a path to a file, temporarily enable clean
+  // URLs if necessary.
+  // @see _pathologic_replace()
+  // @see http://drupal.org/node/1672430
+  if (!empty($options['is_file'])) {
+    $options['orig_clean_url'] = !empty($GLOBALS['conf']['clean_url']);
+    if (!$options['orig_clean_url']) {
+      $GLOBALS['conf']['clean_url'] = TRUE;
+    }
+  }
+
+  $url = check_plain(url(htmlspecialchars_decode($path), $options));
+
+  if (!empty($options['is_file']) && !$options['orig_clean_url']) {
+    $GLOBALS['conf']['clean_url'] = FALSE;
+  }
+  return $url;
+}
+
+/**
+ * Implements hook_pathologic_alter(), for testing that functionality.
+ */
+function pathologic_pathologic_alter(&$url_params, $parts, $settings) {
+  if (is_array($parts['qparts']) && isset($parts['qparts']['test'])) {
+    if ($parts['qparts']['test'] === 'add_foo_qpart') {
+      // Add a "foo" query part
+      if (empty($url_params['options']['query'])) {
+        $url_params['options']['query'] = array();
+      }
+      $url_params['options']['query']['foo'] = 'bar';
+    }
+    elseif ($parts['qparts']['test'] === 'use_original') {
+      $url_params['options']['use_original'] = TRUE;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,100 @@
+= PDF To Image =
+
+The PDF To Image module provides automatic conversion of
+uploaded PDF files to images.
+It can be used either to create a snapshot of the front page,
+or to generate a gallery of images from each page in the document.
+
+The module provides a new widget for managing PDF file uploads.
+It places generated images into a nominated Image field on the same content 
+type.
+
+== Requirements ==
+
+  * File field, Image field and (optionally) Imagemagick module.
+  
+  * ImageMagick toolkit to be available on server via command-line interface.
+    http://drupal.org/project/imagemagick
+
+If the Drupal imagemagick.module is not available, the process will still run, 
+however imagemagick is recommended for win32 installations and it has better
+diagnostics available.
+
+== Installation ==
+
+You must have the imagemagick tools available on your server, and able to
+be called from the commandline.
+Running 
+  which convert
+on your server should tell you if and where the binary exists.
+
+Once the module is enabled, check your site status at /admin/reports/status
+You should see a message that will tell you if your system is ready to run.
+"Imagemagick support for PDF to Image"
+If not, you need to check the requirements, and the ImageMagick settings
+at admin/config/media/image-toolkit.
+See the ImageMagick project docs for troubleshooting that.
+
+If ImageMagick appears to be available but still does not convert PDFs, it
+could be it wasn't installed with 'Ghostscript' libraries or other required
+dependencies. You'l have to go to the ImageMagick forums for help with that.
+
+== Configuration ==
+
+=== Quickstart ===
+
+A 'feature' has been provided that will ato-configure a demonstration content 
+type with some default settings applied.
+
+- Download and enabled 'features' module.
+- Enable 'PDF document'
+
+You should now be able to "Add content » Document" and try out the function.
+To work this into your own site structure, see below.
+
+=== Manual configuration ===
+
+- First, add an image field on your chosen content type. This is where the
+  generated images will be stored.
+- Set the allowed fields to 1 if you just want a cover page, direct number to
+  store only some count of pages or 'unlimited' if you want all pages
+  to be generated.
+- Next add a filefield to your chosen content type and choose
+  'PDF to Image' as the widget.
+  This filefield should be configured to only accept PDF file types.
+- When configuring this field, you will be required to link the uploaded file
+  field with the target image field.
+- You can add image style handling to the image field rendering as normal to
+  adjust the size of the results and how they display on the page.
+
+== Processing ==
+
+Processing of PDF may take some time.
+
+Larger documents use the 'batch' process to generate each page.
+
+== Use of ImageMagick ==
+
+Actual processing is perfomed using ImageAPI's ImageMagick toolkit.
+GD is not supported.
+
+== Field paths and tokens ==
+
+This module SHOULD be compatable with http://drupal.org/project/filefield_paths
+which allows you to customize the file folders and file names of the uploaded
+and generated images. A custom token
+  [node:p2i-source-filename] 
+is available to allow you to name the derived images after the source PDF 
+if you wish.
+
+=== Dev notes ===
+
+The only candidate function from ImageAPI which may perform PDF to image
+convertion is _imageapi_imagemagick_convert(). Unfortunately, it can't pass
+arguments to 'convert' tool of ImageMagick *before* source file specification,
+which is needed to change default density of 100x100dpi.
+On this reason, a custom functionis included in the module's source:
+
+function pdf_to_image_generate_page($params, $page_number = 0) {
+  . . .
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/pdf_document/pdf_document.features.field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,249 @@
+<?php
+/**
+ * @file
+ * pdf_document.features.field.inc
+ */
+
+/**
+ * Implements hook_field_default_fields().
+ */
+function pdf_document_field_default_fields() {
+  $fields = array();
+
+  // Exported field: 'node-document-body'
+  $fields['node-document-body'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(
+        0 => 'node',
+      ),
+      'field_name' => 'body',
+      'foreign keys' => array(
+        'format' => array(
+          'columns' => array(
+            'format' => 'format',
+          ),
+          'table' => 'filter_format',
+        ),
+      ),
+      'indexes' => array(
+        'format' => array(
+          0 => 'format',
+        ),
+      ),
+      'module' => 'text',
+      'settings' => array(),
+      'translatable' => '0',
+      'type' => 'text_with_summary',
+    ),
+    'field_instance' => array(
+      'bundle' => 'document',
+      'default_value' => NULL,
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'hidden',
+          'module' => 'text',
+          'settings' => array(),
+          'type' => 'text_default',
+          'weight' => '0',
+        ),
+        'teaser' => array(
+          'label' => 'hidden',
+          'module' => 'text',
+          'settings' => array(
+            'trim_length' => 600,
+          ),
+          'type' => 'text_summary_or_trimmed',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'body',
+      'label' => 'Body',
+      'required' => FALSE,
+      'settings' => array(
+        'display_summary' => TRUE,
+        'text_processing' => 1,
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'module' => 'text',
+        'settings' => array(
+          'rows' => 20,
+          'summary_rows' => 5,
+        ),
+        'type' => 'text_textarea_with_summary',
+        'weight' => '1',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-document-field_document'
+  $fields['node-document-field_document'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_document',
+      'foreign keys' => array(
+        'fid' => array(
+          'columns' => array(
+            'fid' => 'fid',
+          ),
+          'table' => 'file_managed',
+        ),
+      ),
+      'indexes' => array(
+        'fid' => array(
+          0 => 'fid',
+        ),
+      ),
+      'module' => 'file',
+      'settings' => array(
+        'display_default' => 1,
+        'display_field' => 0,
+        'uri_scheme' => 'public',
+      ),
+      'translatable' => '0',
+      'type' => 'file',
+    ),
+    'field_instance' => array(
+      'bundle' => 'document',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'file',
+          'settings' => array(),
+          'type' => 'file_default',
+          'weight' => '2',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_document',
+      'label' => 'Document',
+      'required' => 0,
+      'settings' => array(
+        'description_field' => 0,
+        'file_directory' => 'documents',
+        'file_extensions' => 'pdf',
+        'max_filesize' => '',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'pdf_to_image',
+        'settings' => array(
+          'pdf_to_image' => array(
+            'density' => '25x25',
+            'extra_args' => '',
+            'hide_imagefield' => 0,
+            'target_field' => 'field_image',
+          ),
+          'progress_indicator' => NULL,
+        ),
+        'type' => 'pdf_to_image',
+        'weight' => '2',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-document-field_image'
+  $fields['node-document-field_image'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_image',
+      'foreign keys' => array(
+        'fid' => array(
+          'columns' => array(
+            'fid' => 'fid',
+          ),
+          'table' => 'file_managed',
+        ),
+      ),
+      'indexes' => array(
+        'fid' => array(
+          0 => 'fid',
+        ),
+      ),
+      'module' => 'image',
+      'settings' => array(
+        'default_image' => 0,
+        'uri_scheme' => 'public',
+      ),
+      'translatable' => '0',
+      'type' => 'image',
+    ),
+    'field_instance' => array(
+      'bundle' => 'document',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'image',
+          'settings' => array(
+            'image_link' => '',
+            'image_style' => '',
+          ),
+          'type' => 'image',
+          'weight' => '1',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_image',
+      'label' => 'Image',
+      'required' => 0,
+      'settings' => array(
+        'alt_field' => 0,
+        'default_image' => 0,
+        'file_directory' => 'document_images',
+        'file_extensions' => 'png gif jpg jpeg',
+        'max_filesize' => '',
+        'max_resolution' => '',
+        'min_resolution' => '',
+        'title_field' => 0,
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'image',
+        'settings' => array(
+          'preview_image_style' => 'thumbnail',
+          'progress_indicator' => 'throbber',
+        ),
+        'type' => 'image_image',
+        'weight' => '3',
+      ),
+    ),
+  );
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('Body');
+  t('Document');
+  t('Image');
+
+  return $fields;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/pdf_document/pdf_document.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,22 @@
+<?php
+/**
+ * @file
+ * pdf_document.features.inc
+ */
+
+/**
+ * Implements hook_node_info().
+ */
+function pdf_document_node_info() {
+  $items = array(
+    'document' => array(
+      'name' => t('Document'),
+      'base' => 'node_content',
+      'description' => t('A PDF document, with preview.'),
+      'has_title' => '1',
+      'title_label' => t('Title'),
+      'help' => '',
+    ),
+  );
+  return $items;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/pdf_document/pdf_document.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+name = PDF Document
+description = Document type containing a PDF attachment and a preview image. Demonstrates PDF_to_Image functionality.
+core = 7.x
+package = Testing
+dependencies[] = features
+dependencies[] = field_sql_storage
+dependencies[] = file
+dependencies[] = image
+dependencies[] = node
+dependencies[] = pdf_to_image
+dependencies[] = text
+features[features_api][] = api:1
+features[field][] = node-document-body
+features[field][] = node-document-field_document
+features[field][] = node-document-field_image
+features[node][] = document
+
+; Information added by drupal.org packaging script on 2013-07-25
+version = "7.x-3.2"
+core = "7.x"
+project = "pdf_to_imagefield"
+datestamp = "1374721625"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/pdf_document/pdf_document.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,7 @@
+<?php
+/**
+ * @file
+ * Code for the pdf_document feature.
+ */
+
+include_once 'pdf_document.features.inc';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/pdf_to_image.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,11 @@
+name = PDF to Image
+description = Imports PDF file and split pages into image field files
+core = 7.x
+;dependencies[] = imagemagick
+
+; Information added by drupal.org packaging script on 2013-07-25
+version = "7.x-3.2"
+core = "7.x"
+project = "pdf_to_imagefield"
+datestamp = "1374721625"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/pdf_to_image.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * PDF to Image install and enable hooks.
+ */
+
+
+/**
+ * Implements hook_requirements().
+ */
+function pdf_to_image_requirements($phase) {
+  $requirements = array();
+  // Ensure translations don't break at install time
+  $t = get_t();
+
+  if ($phase == 'runtime') {
+    if ($response = pdf_to_image_check_imagemagick()) {
+      $requirements['pdf_to_image_check_imagemagick'] = array(
+        'title' => $t('Imagemagick support for PDF to Image'),
+        'value' => $response,
+        'severity' => REQUIREMENT_OK,
+      );
+    }
+    else {
+      $requirements['pdf_to_image_check_imagemagick'] = array(
+        'title' => $t('Imagemagick support for PDF to Image'),
+        'description' => $t('Imagemagick must be installed and the <a href="!admin_path">path on the server set</a> for PDFs to be processed.', array('!admin_path' => url('admin/config/media/image-toolkit'))),
+        'value' => $t("Imagemagick doesn't seem to be available at %path.", array('%path' => variable_get('imagemagick_convert', '/usr/bin/convert'))),
+        'severity' => REQUIREMENT_WARNING,
+      );
+    }
+  }
+
+  return $requirements;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/pdf_to_image.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,770 @@
+<?php
+
+/**
+ * @file
+ *   Extends file fields with a process that generates a thumbnail image
+ *   or multiple image pages from an uploaded PDF
+ *
+ * @author dman dan@coders.co.nz
+ *
+ * Based on earlier worn by Elaman, fatcrobat, InternetDevels.Com, and others
+ */
+
+/**
+ * Announces that we have additional widget options that extend file fields.
+ *
+ * @see file_field_widget_info()
+ *
+ * Implements hook_field_widget_info().
+ */
+function pdf_to_image_field_widget_info() {
+  return array(
+    'pdf_to_image' => array(
+      'label'       => t('PDF to Image'),
+      'field types' => array('file'),
+      'settings'    => array(
+        'pdf_to_image' => array(
+          'target_field'        => NULL,
+          'density'             => '25x25',
+          'extra_args'          => '',
+        ),
+      ),
+      'behaviors'   => array(
+        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+        'default value' => FIELD_BEHAVIOR_NONE,
+      ),
+    ),
+  );
+}
+
+
+/**
+ * Adds options to the field configuration form in the content type admin setup.
+ *
+ * Implements hook_field_widget_settings_form().
+ */
+function pdf_to_image_field_widget_settings_form($field, $instance) {
+  $widget = $instance['widget'];
+  $pdf_to_image_settings = $widget['settings']['pdf_to_image'];
+
+  // Use the file widget settings form.
+  $form = file_field_widget_settings_form($field, $instance);
+
+  // Plus our own extras
+  $form['pdf_to_image'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('PDF conversion options'),
+  );
+
+  $fields = field_info_instances($instance['entity_type'], $instance['bundle']);
+  $options = array();
+  foreach ((array) $fields as $field) {
+    $field_info = field_info_field($field['field_name']);
+    if ($field_info['type'] == 'image') {
+      $options[$field['field_name']] = $field['label'];
+    }
+  }
+
+  // @TODO: make this field required.
+  $form['pdf_to_image']['target_field'] = array(
+    '#title'         => t('Target Image Field'),
+    '#type'          => 'select',
+    '#empty_option'  => '<' . (count($options) ? t('No Image Field selected') : t('No Image Field found')) . '>',
+    '#default_value' => $pdf_to_image_settings['target_field'],
+    '#description'   => t('PDF to Image field processing requires an image field where the resulting images of extracted PDF pages should be stored. The image field must be assigned to the same node type. For all pages to be processed, the image field should allow multiple uploads. If the image field allows only one item, only the cover page will be processed.'),
+    '#options'       => $options,
+  );
+
+  $form['pdf_to_image']['density'] = array(
+    '#title'            => t('Density used for rendering PDF'),
+    '#description'      => t('Horizontal and vertical density of the image XxY (e.g. 100x100). Default is 25x25 (25%). <em>This is not image dimensions!</em> It\'s the sampling quality of the generated image. 100x100 means the generated image will be "full size" compared to a PDF viewed at 100%. If you are only wanting preview thumbnails, you might be fine (and a LOT faster) with just 20x20 (20% size) images. Only generate full-size (100x100) images if you intend to display full-size pages. To adjust the <b>display</b> sizes on the web page, manage the display of the image field as usual.'),
+    '#type'             => 'textfield',
+    '#default_value'    => $pdf_to_image_settings['density'],
+    '#element_validate' => array('pdf_to_image_validate_density'),
+    '#size'             => 15,
+    '#maxlength'        => 10,
+  );
+
+  $form['pdf_to_image']['extra_args'] = array(
+    '#title'         => t('Extra conversion arguments'),
+    '#type'          => 'textfield',
+    '#description'   => t('Enter optional <a href="http://imagemagick.org/Usage/formats/#ps">additional parameters to be used by the imagemagick conversion</a> if needed.<br/>eg <code>-trim +repage</code>'),
+    '#default_value' => !empty($pdf_to_image_settings['extra_args']) ? $pdf_to_image_settings['extra_args'] : '',
+    '#size'          => 20,
+  );
+
+  // @TODO: implement this.
+  $form['pdf_to_image']['extra_args']['#description'] .= '<br />' . t('WARNING! not working feature now.');
+
+  $form['pdf_to_image']['hide_imagefield'] = array(
+    '#type'          => 'checkbox',
+    '#title'         => t('Hide target image field on edit form'),
+    '#default_value' => !empty($pdf_to_image_settings['hide_imagefield']),
+    '#description'   => t('If rendering the preview image in place of the uploaded file, you may want to hide the image field from the edit form entirely to prevent editors from adding their own.'),
+  );
+
+  // @TODO: add radiobuttons to choose way of pages generating,
+  // means batch (be default now) or queue or runtime,
+  // and implements this ways.
+  return $form;
+}
+
+
+/**
+ * Validate string for density settings.
+ */
+function pdf_to_image_validate_density($element, &$form_state) {
+  $value = $element['#value'];
+  if (!empty($value) && !preg_match('/^[0-9]+x[0-9]+$/', $value)) {
+    form_set_error('density', t('Please specify a density in the format XxY (e.g. 100x100).'));
+  }
+}
+
+
+
+/**
+ * Adds another method for displaying PDF files - embedded live preview.
+ *
+ * Implements hook_field_formatter_info().
+ */
+function pdf_to_image_field_formatter_info() {
+  $formatters = array(
+    'pdf_view' => array(
+      'label'       => t('PDF preview'),
+      'field types' => array('file'),
+      'settings'    => array(
+        'pdf_width'  => '100%',
+        'pdf_height' => '450',
+      ),
+    ),
+  );
+  return $formatters;
+}
+
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function pdf_to_image_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display  = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  if ($display['type'] == 'pdf_view') {
+    $summary  = t('Region of @width to @height, and text at download link - "@alt"', array(
+      '@width'  => $settings['pdf_width'],
+      '@height' => $settings['pdf_height'],
+      '@alt'    => $settings['pdf_alt'],
+    ));
+    return $summary;
+  }
+}
+
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function pdf_to_image_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  if (!isset($items[0])) {
+    return;
+  }
+
+  // @TOFO fix public / private handlers, apply stream wrappers functions.
+  global $base_url;
+  $path     = $base_url . '/' . variable_get('file_public_path') . substr($items[0]['uri'], 8);
+
+  if ($display['type'] == 'pdf_view') {
+    $width    = $display['settings']['pdf_width'];
+    $height   = $display['settings']['pdf_height'];
+    $alt      = $display['settings']['pdf_alt'];
+    $object   = '<object width="' . $width . '" height="' . $height . '" type="application/pdf" data="' . $path . '"><a href="' . $path . '">' . $alt . '</a></object>';
+  }
+
+  if ($display['type'] == 'pdf_link') {
+    // @TODO add title support.
+    $object = l(t('Download file'), $path);
+  }
+
+  $element  = array();
+  $element[0]['#markup'] = $object;
+
+  return $element;
+}
+
+
+/**
+ * Implements hook_form_alter().
+ *
+ * Hides the target image field from editors, if you don't want them to provide
+ * their own snapshot.
+ *
+ * Should be able to run on any fielded entity type edit form, not just nodes.
+ */
+function pdf_to_image_form_alter(&$form, &$form_state, $form_id) {
+  if (!isset($form['#entity_type']) || !isset($form['#bundle'])) {
+    return;
+  }
+
+  // Find if this entity has any fields that use the pdf_to_image widget.
+  $fields_pdf = pdf_to_image_source_fields($form['#entity_type'], $form['#bundle']);
+  // If so, do they want us to hide anything?
+  if (count($fields_pdf)) {
+    foreach ($fields_pdf as $field) {
+      if (!empty($field['widget']['settings']['pdf_to_image']['hide_imagefield'])) {
+        $target_field = $field['widget']['settings']['pdf_to_image']['target_field'];
+        if (isset($form[$target_field])) {
+          $form[$target_field]['#access'] = FALSE;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Returns a list of field names that are used as source files for pdf conversion.
+ *
+ * @param $entity_type eg 'node'
+ * @param $bundle eg 'document'
+ */
+function pdf_to_image_source_fields($entity_type, $bundle) {
+  // Find if this entity has any fields that use the pdf_to_image widget.
+  $fields = field_info_instances($entity_type, $bundle);
+  $pdf_fields = array();
+  foreach ((array) $fields as $field) {
+    if ($field['widget']['type'] == 'pdf_to_image') {
+      $pdf_fields[$field['field_name']] = $field;
+    }
+  }
+  return $pdf_fields;
+}
+
+/**
+ * Adds config options to settings form at /admin/config/media/image-toolkit
+ *
+ * @param array $form
+ * @param array $form_state
+ */
+function pdf_to_image_form_system_image_toolkit_settings_alter(&$form, &$form_state) {
+  // We have better diagnostics if imagemagick is used,
+  // but it's not a hard dependency.
+  // It's still handy to expose the path configuration for it though.
+  // Do this here if the imagemagick module isn't doing it.
+  if (! module_exists('imagemagick')) {
+    $form['imagemagick_convert'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Path to the "convert" binary'),
+      '#default_value' => variable_get('imagemagick_convert', 'convert'),
+      '#required' => TRUE,
+      '#element_validate' => array('pdf_to_image_is_executable_validate'),
+      '#description' => t('The complete path and filename of the ImageMagick <kbd>convert</kbd> binary used by pdf_to_image. For example: <kbd>/usr/bin/convert</kbd> or <kbd>C:\Program Files\ImageMagick-6.3.4-Q16\convert.exe</kbd>'),
+    );
+  }
+  $form['gs_path'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Path to the ghostscript "gs" binary'),
+    '#default_value' => variable_get('gs_path', '/usr/local/bin/gs'),
+    '#required' => FALSE,
+    '#element_validate' => array('pdf_to_image_is_executable_validate'),
+    '#description' => t('The complete path and filename of the Ghostscript <kbd>gs</kbd> binary used by pdf_to_image. For example: <kbd>/usr/local/bin/gs</kbd>. This is optional, but if available may be a little faster.'),
+  );
+}
+
+
+/**
+ * Adds extra options to file upload widget.
+ *
+ * It's basically a stub around file_field_widget_form().
+ *
+ * Implements hook_field_widget_form().
+ */
+function pdf_to_image_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+
+  // This is a file widget, plus extra options.
+  $elements = file_field_widget_form($form, $form_state, $field, $instance, $langcode, $items, $delta, $element);
+  $settings = $instance['settings'];
+
+  foreach (element_children($elements) as $delta) {
+    // If not using custom extension validation, ensure this is a pdf.
+    $elements[$delta]['#upload_validators']['file_validate_extensions'][0] = 'pdf';
+    // File fields need extra processing. Our one even more so.
+    #$elements[$delta]['#process'][] = 'pdf_to_image_field_widget_process';
+  }
+  $elements[0]['#description'] .= '<br/>' . t('This file will produce an image thumbnail and store it in %target_field when uploaded', array('%target_field' => $instance['widget']['settings']['pdf_to_image']['target_field']));
+
+  return $elements;
+}
+
+
+/**
+ * A field widget process callback, triggered when a form containing our widget type
+ * of file is geting rendered.
+ *
+ * @see file_field_widget_process.
+ */
+function pdf_to_image_field_widget_process($element, &$form_state, $form) {
+  /*
+  $item = $element['#value'];
+  $item['fid'] = $element['fid']['#value'];
+
+  $field = field_widget_field($element, $form_state);
+  $instance = field_widget_instance($element, $form_state);
+  $settings = $instance['widget']['settings'];
+
+  dpm('could show a thumbnail here');
+  */
+  return $element;
+}
+
+/**
+ * hook_entity_insert()
+ *
+ * Update any of our fields when a fieldable entity is being updated.
+ *
+ * @param stdclass $entity
+ * @param string $entity_type
+ */
+function pdf_to_image_entity_insert($entity, $entity_type) {
+  return pdf_to_image_entity_update($entity, $entity_type);
+}
+
+/**
+ * When a fieldable entity is being updated, regenerate the files if appropriate
+ *
+ * This is the first step where generation really starts happening.
+ *
+ * @param stdclass $entity
+ * @param string $type
+ */
+function pdf_to_image_entity_update($entity, $entity_type) {
+  // What is this thing?
+  $info = entity_get_info($entity_type);
+  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+  $pdf_fields = pdf_to_image_source_fields($entity_type, $bundle);
+  foreach ($pdf_fields as $field_id => $field_instance) {
+    pdf_to_image_generate_process($entity_type, $entity, $field_id, $field_instance);
+  }
+}
+
+/**
+ * Processing pdf file creation.
+ *
+ * This sets up the batch job with all the neccessary parameters
+ */
+function pdf_to_image_generate_process($entity_type, $entity, $field_id, $field_instance) {
+  $field_lang = field_language($entity_type, $entity, $field_id);
+  list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+  $items = $entity->{$field_id};
+
+  if (empty($items[$field_lang][0]['fid'])) {
+    // No file attachment found in the source field.
+    // Do nothing.
+    return;
+  }
+  $pdf_file = file_load($items[$field_lang][0]['fid']);
+  $pdf_realpath = file_stream_wrapper_get_instance_by_uri($pdf_file->uri)->realpath();
+  $count = pdf_to_image_count_pages($pdf_realpath);
+  if (!empty($field_instance['widget']['settings']['pdf_to_image']['target_field'])) {
+    $target_field = $field_instance['widget']['settings']['pdf_to_image']['target_field'];
+  }
+  // Should I check if the target field is already populated and stop then?
+
+  if ($target_field && $count) {
+    // Arguments to give to the batch job.
+    $params = array(
+      'entity' => $entity, // Don't actually need the whole thing, just the id really.
+      'entity_type' => $entity_type,
+      'entity_id' => $id,
+      'image'  => array(
+        'field'    => field_info_field($target_field),
+        'instance' => field_info_instance($entity_type, $target_field, $field_instance['bundle']),
+      ),
+      'pdf'    => array(
+        'instance' => $field_instance,
+        'file'     => $pdf_file,
+      ),
+    );
+
+    // Prepare count parameter.
+    if ($params['image']['field']['cardinality'] != -1 && $count > $params['image']['field']['cardinality']) {
+      $count = $params['image']['field']['cardinality'];
+    }
+    $operations = array(
+      array('pdf_to_image_generate_process_page', array($params, 0)),
+    );
+
+    watchdog('pdf_to_image', 'Starting a process to convert attached PDF %file to image previews', array('%file' => $params['pdf']['file']->uri), WATCHDOG_INFO);
+    for ($page = 1; $page < $count; $page++) {
+      $operations[] = array('pdf_to_image_generate_process_page', array($params, $page));
+    }
+    batch_set(array(
+      'title'            => t('Converting PDF, %count pages', array('%count' => $count)),
+      'operations'       => $operations,
+      'finished'         => 'pdf_to_image_generate_process_attach',
+      'progress_message' => t('Processed @current out of @total.'),
+    ));
+    // @TODO: save node with one entity without batch.
+    // else {
+    // $file = pdf_to_image_generate_page($params, 0);
+    // }
+  }
+  else {
+    // No target image field set, or invalid count from the PDF.
+  }
+}
+
+
+/**
+ * Generate a single page (of the given index) inside a batch process.
+ *
+ * A batch task, no return.
+ */
+function pdf_to_image_generate_process_page($params, $page_number, &$context) {
+  $context['results']['params'] = $params;
+  if (!isset($context['results']['files'])) {
+    $context['results']['files'] = array();
+  }
+  $file = pdf_to_image_generate_page($params, $page_number);
+  if (is_object($file) && isset($file->fid)) {
+    $context['results']['files'][$page_number] = $file;
+  }
+}
+
+
+/**
+ * Generate a single page for the given pdf file.
+ */
+function pdf_to_image_generate_page($params, $page_number = 0) {
+  $source_file = drupal_realpath($params['pdf']['file']->uri);
+  if (!file_exists($source_file)) {
+    watchdog('pdf_to_image', 'Invalid file given to convert. Could not read %file (%source_file)', array('%file' => $params['pdf']['file']->uri, '%source_file' => $source_file), WATCHDOG_ERROR);
+    return NULL;
+  }
+
+  $density = "-density " . $params['pdf']['instance']['widget']['settings']['pdf_to_image']['density'];
+  $extra_args = isset($params['pdf']['instance']['widget']['settings']['pdf_to_image']['extra_args']) ? $params['pdf']['instance']['widget']['settings']['pdf_to_image']['extra_args'] : "";
+
+  // We need to know both the uri and realpath versions of the paths we want to
+  // work with.
+  $image_dir_uri = file_stream_wrapper_uri_normalize($params['image']['field']['settings']['uri_scheme'] . '://' . $params['image']['instance']['settings']['file_directory']);
+  file_prepare_directory($image_dir_uri, FILE_CREATE_DIRECTORY);
+  $image_uri = $image_dir_uri . '/' . $params['pdf']['file']->fid . "-" . $page_number . '.jpg';
+  $image_realpath = drupal_realpath($image_uri);
+
+  if (empty($image_uri)) {
+    watchdog('pdf_to_image', 'Failed to calculate a destination filename for conversion', array(), WATCHDOG_ERROR);
+    return FALSE;
+  }
+
+  // Check to see if the target image file already exists, is registered in the
+  // database. Why?
+  $query = db_select('file_managed', 'f')
+    ->fields('f', array('fid'))
+    ->condition('uri', $image_uri)
+    ->execute()->fetchCol();
+  if (!empty($query)) {
+    $file = file_load(array_shift($query));
+    watchdog('pdf_to_image', 'PDF preview %image already exists. Re-attaching it.', array('%image' => $image_uri), WATCHDOG_INFO);
+    return $file;
+  }
+
+  watchdog('pdf_to_image', 'Converting PDF: %file page %page_number: to image: %image', array(
+      '%file' => $params['pdf']['file']->uri,
+      '%page_number' => $page_number,
+      '%image' => $image_uri,
+    ), WATCHDOG_INFO
+  );
+
+  pdf_to_image_convert_exec($source_file . '[' . $page_number . ']', $image_realpath, array(), array($density, $extra_args));
+
+  if (file_exists($image_realpath)) {
+    watchdog('pdf_to_image', 'PDF preview %image created', array(
+        '%image' => $image_uri,
+      ), WATCHDOG_INFO
+    );
+
+    global $user;
+    $file = (object) array(
+      'uid'       => $user->uid,
+      'filename'  => basename($image_uri),
+      'uri'       => $image_uri,
+      'filemime'  => file_get_mimetype($image_uri),
+      'filesize'  => @filesize($image_uri),
+      'timestamp' => REQUEST_TIME,
+      'status'    => FALSE,
+      'is_new'    => TRUE,
+    );
+    file_save($file);
+    return $file;
+  }
+  watchdog('pdf_to_image', 'Failed to generate image', array(), WATCHDOG_ERROR);
+  return FALSE;
+}
+
+
+/**
+ * Attach generated files to the content entity (node) at the end of batch mode.
+ */
+function pdf_to_image_generate_process_attach($success, $results, $operations) {
+  if (!(isset($results['files']) && count($results['files']))) {
+    watchdog('pdf_to_image', 'No files produced from processing document', array(), WATCHDOG_NOTICE);
+    return;
+  }
+
+  $field_name = $results['params']['image']['field']['field_name'];
+  $entity_id = $results['params']['entity_id'];
+  $entity_type = $results['params']['entity_type'];
+
+  if (isset($entity_id) && is_numeric($entity_id)) {
+    // Don't use the entity as given, load it again as things may have happened
+    // to it since the batch job began.
+    $entity = entity_load_unchanged($entity_type, $entity_id);
+    if (is_object($entity)) {
+      $field_lang = field_language($entity_type, $entity, $field_name);
+      // This removes the existing images by emptying the list.
+      // The (re?) attaches the generated ones.
+      $entity->{$field_name}[$field_lang] = array();
+      ksort($results['files'], SORT_NUMERIC);
+      foreach ($results['files'] as $file) {
+        #$entity->{$field_name}[$field_lang][]['fid'] = $file->fid;
+        $entity->{$field_name}[$field_lang][] = (array) $file;
+      }
+      watchdog('pdf_to_image', 'Attached converted images to content.', array(), WATCHDOG_INFO);
+      $saved = pdf_to_image_entity_save($entity_type, $entity);
+    }
+    else {
+      watchdog('pdf_to_image', 'Invalid content object. Cannot attach generated images to it.', array(), WATCHDOG_ERROR);
+    }
+  }
+  else {
+    watchdog('pdf_to_image', 'Invalid content id given to attach generated images to.', array(), WATCHDOG_ERROR);
+  }
+}
+
+/**
+ * Why is there no entity_save in core??
+ * Stolen this from contrib entity.module!
+ *
+ * Needed this to allow any entity, not just node to use these fields.
+ */
+function pdf_to_image_entity_save($entity_type, $entity) {
+  $info = entity_get_info($entity_type);
+  if (method_exists($entity, 'save')) {
+    return $entity->save();
+  }
+  elseif (isset($info['save callback'])) {
+    $info['save callback']($entity);
+  }
+  elseif (in_array('EntityAPIControllerInterface', class_implements($info['controller class']))) {
+    return entity_get_controller($entity_type)->save($entity);
+  }
+  elseif (function_exists("{$entity_type}_save")) {
+    $func = "{$entity_type}_save";
+    return $func($entity);
+  }
+  else {
+    return FALSE;
+  }
+}
+
+
+/**
+ * Use imagemagick routine to count the number of pages in a given PDF
+ */
+function pdf_to_image_count_pages($filepath) {
+  // Assume the 'identify' binary lives next to the 'convert' binary.
+  $convert_path  = variable_get('imagemagick_convert', '/usr/bin/convert');
+  $identify_path = dirname($convert_path) . '/identify';
+
+  // Identify renders every page in the pdf to count the number of pages which
+  // can be a problem (server timeout) when processing a pdf with many pages.
+  // The better command commented because it working very slow.
+  // "{$identify_path} -format %n " . escapeshellarg($fpath) . ' 2> /dev/null';
+
+  // Apparently this method is even faster, from
+  // http://drupal.org/node/1537658
+  // Though we'll only use it if ghostscript is present and configured.
+  $gs_path = variable_get('gs_path', '/usr/local/bin/gs');
+  if (is_executable($gs_path)) {
+    $command = "{$gs_path} -q -dNODISPLAY -c \"(". trim(escapeshellcmd($filepath),"'") .") (r) file runpdfbegin pdfpagecount = quit\"";
+  }
+  else {
+    // This one instead asks for more pages than the document has, then reads the
+    // error message that tells us what the last page number was instead :-}
+    $command = "{$identify_path} " . escapeshellarg($filepath) . '[9999] | grep "Requested FirstPage" | cut -d : -f2';
+  }
+
+  $count = pdf_to_image_shell_exec($command);
+  return (int) trim($count);
+}
+
+/**
+ * Check the binary path of 'convert' on the server.
+ *
+ * Returns NULL if it failed, the version info of ImageMagick if it succeeds.
+ */
+function pdf_to_image_check_imagemagick() {
+  static $response;
+  if (isset($response)) {
+    return $response;
+  }
+  $convert_path  = variable_get('imagemagick_convert', '/usr/bin/convert');
+  $response = pdf_to_image_shell_exec($convert_path . ' -version');
+  return $response;
+}
+
+
+/**
+ * Verifies that the given path to a binary exists and is executable.
+ */
+function pdf_to_image_is_executable_validate($element, &$form_state,  $form) {
+  $path = $element['#value'];
+  if (!empty($path) && ! is_executable($path)) {
+    form_set_error($element['#name'], t('%title : %path was not found, valid or executable. Check to see if this exists on your system in that location', array('%title' => $element['#title'], '%path' => $element['#value'])));
+  }
+}
+
+/**
+ * FWIW, may not need imagemagick module, just for this one func.
+ * If you want debugging and Win32 support, use imagemagick.module.
+ * Otherwise, here's a short and dirty version of the same thing.
+ *
+ */
+function pdf_to_image_convert_exec($source, $dest, $args = array(), $extra = array()) {
+  $args['quality'] = '-quality ' . escapeshellarg(variable_get('imagemagick_quality', 75));
+  $command = implode(' ', $extra) . ' ' . escapeshellarg($source) . ' ' . implode(' ', $args) . ' ' . escapeshellarg($dest);
+
+  if (function_exists('imagemagick_convert_exec')) {
+    if (_imagemagick_convert_exec($command, $output, $errors) !== TRUE) {
+      $errors_txt = '<pre>' . (is_array($errors) ? implode("\n", $errors) : $errors) . '</pre>';
+      watchdog('pdf to image : imageapi imagemagick', $errors_txt, array(), WATCHDOG_ERROR);
+      return FALSE;
+    }
+    return file_exists($dest);
+  }
+
+  // Else do it myself.
+  // Paranoia.
+  if (! pdf_to_image_check_imagemagick()) {
+    drupal_set_message(t('Imagemagick must be installed and the <a href="!admin_path">path on the server set</a> for PDFs to be processed.', array('!admin_path' => url('admin/config/media/image-toolkit'))), 'error');
+    return FALSE;
+  }
+
+  $convert_path  = variable_get('imagemagick_convert', '/usr/bin/convert');
+  $response = pdf_to_image_shell_exec($convert_path . ' ' . $command);
+  return file_exists($dest);
+}
+
+/**
+ * Run the given command (expected to be an imageMagick Commandline)
+ * Wrapped in a bugfix workaround.
+ *
+ * @param string $command
+ */
+function pdf_to_image_shell_exec($command) {
+  // Horrible bug. If running on Acquia dev desktop, it sets a custom path for
+  // the dynamic link library. But 2012-04 that was OLDER than the libraries
+  // My OS expected to use to run graphics utilities with.
+  // Reason: Incompatible library version: dot requires version 10.0.0 or later, but libltdl.7.dylib provides version 9.0.0
+  // UNSET the Acquia DYLD_LIBRARY_PATH before dropping to commandline to run.
+  $DYLD_LIBRARY_PATH = getenv("DYLD_LIBRARY_PATH");
+  putenv("DYLD_LIBRARY_PATH=");
+
+  watchdog('pdf_to_image', 'Running commandline %command', array('%command' => $command), WATCHDOG_DEBUG);
+
+  $response = shell_exec($command);
+
+  // Put it back just in case it matters
+  putenv("DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH");
+
+  return $response;
+}
+
+
+/**
+ * To enhance filefield_paths, publish the filename of the source document that could be used to create the filepath of the derived document.
+ *
+ * Implements hook_token_info().
+ */
+function pdf_to_image_token_info() {
+  $info['tokens']['node']['pdf-source-filename'] = array(
+    'name' => t("File name"),
+    'description' => t("File name of the source PDF without extension."),
+  );
+
+  /*
+  // Provide tokens for any fields that are used as pdf sources.
+  // Do a complex lookup here to avoid having to do it in the token call itself.
+  $all_fields = field_info_instances();
+  // All entities, all bundles.
+  foreach ($all_fields as $entity_type => $entity_fields) {
+    foreach ($entity_fields as $bundle_id => $bundle_fields) {
+      foreach (pdf_to_image_source_fields($entity_type, $bundle_id) as $field_id => $field_instance) {
+        // THIS is a field I need to provide a token from
+        // TODO - I really should index by field ID so the token generator
+        // knows what to look for without analyzing the content type each time.
+        // $info['tokens'][$entity_type][$field_id . ':pdf-filename'] = array(
+        // But how...
+        $info['tokens'][$entity_type]['pdf-source-filename'] = array(
+          'name' => $field['label'],
+          'description' => t("File name of the source PDF without extension."),
+        );
+      }
+
+    }
+  }
+  // Fail. If I encode the field name into the token, then I can't scan for it
+  // later until I know what the field name is. So no win there.
+  */
+  return $info;
+}
+
+/**
+ * Fills in a token with the filename of the source pdf field that may be
+ * attached to an entity. Not very well-structured here yet.
+ *
+ * Implements hook_tokens().
+ */
+function pdf_to_image_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $sanitize = !empty($options['sanitize']);
+
+  $replacements = array();
+  if ($type == 'entity' && !empty($data['entity'])) {
+    $entity = $data['entity'];
+    $entity_type = $data['entity_type'];
+    list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+
+    // Find any fields on this entity that may be source files for a PDF conversion.
+    $pdf_fields = pdf_to_image_source_fields($entity_type, $bundle);
+    foreach ($pdf_fields as $field_id => $field) {
+      if (isset($entity->{$field_id})) {
+        $source_field_values = $entity->{$field_id};
+        $field_lang = field_language($data['entity_type'], $entity, $field_id);
+        $source_values = $source_field_values[$field_lang];
+        // Assumed to be multiple
+        foreach ($source_values as $delta => $file_info) {
+          // fall-through. We've found $file_info now. Messy, but dunno what to do with multiple sources.
+        }
+      }
+    }
+
+    // This looks like a slow way to do things, no?
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        case 'pdf-source-filename':
+          $info = pathinfo($file_info['filename']);
+          $replacements[$original] = $info['filename'];
+          break;
+      }
+    }
+  }
+
+  return $replacements;
+}
+
+/**
+* Implements hook_filefield_sources_widgets().
+*
+* Adds PDF to Image to the list of  widgets compatible with FileField Sources.
+*/
+function pdf_to_image_filefield_sources_widgets() {
+  return array('pdf_to_image');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/pdf_to_imagefield/pdf_to_image_demo.make.stub	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,35 @@
+; Makefile to assist creating a new Drupal site to demonstrate pdf_to_imagefield module.
+; Get this file, then change to an empty directory and run
+;   drush make --working-copy {path/to/}pdf_to_imagefield.make.stub
+;
+; This will download all the dependencies required to run pdf_to_imagefield 
+; and the demo feature pdf_document. 
+; 
+; This --working-copy command will actually git clone the working copy of the module, 
+; ready for test and development. It's optional.
+;  
+
+api = 2
+
+; Required version of Drupal core.
+projects[] = drupal
+core = 7.x
+
+; Basic Drupal contributed projects.
+; Get 'features' so we can turn on the demo content type immediately.
+projects[features][subdir] = contrib
+; Get 'filefield_paths' and token to test out the filename changes.
+projects[filefield_paths][subdir] = contrib
+projects[token][subdir] = contrib
+
+; And now get the pdf_to_imagefield checkout, latest version
+projects[pdf_to_imagefield][subdir] = dev
+;projects[pdf_to_imagefield][download][type] = "git"
+;projects[pdf_to_imagefield][download][url] = "git@git.drupal.org:project/pdf_to_imagefield.git"
+;projects[pdf_to_imagefield][download][branch] = "7.x-3.x"
+
+;projects[pdf_to_imagefield][download][type] = "git"
+;projects[pdf_to_imagefield][download][url] = "http://git.drupal.org/project/pdf_to_imagefield.git"
+;projects[pdf_to_imagefield][download][branch] = "7.x-3.x"
+
+projects[pdf_to_imagefield][version] = "7.x-3.x"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/prepopulate/CHANGELOG.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,26 @@
+
+PREPOPULATE CHANGELOG
+=====================
+**** DRUPAL 6.x-2 ****
+FEATURE: #101916: Prepopulate any form, not just node edit forms.
+
+**** DRUPAL 6.x-1 ****
+6.x-1.0 (May 3, 2008)
+First 6.x release.
+
+6.x-1.x-dev (March 16, 2008)
+Initial upgrade to 6.
+
+**** DRUPAL 5 ****
+5.x-1.3 (March 12, 2008)
+BUG #146072: SQL string incompatible with PostgreSQL.
+BUG #216472: fixed regression that removed content type checkboxes.
+
+5.x-1.2 (January 14, 2008)
+FEATURE: Added USAGE.txt documentation.
+
+5.x-1.1 (January 28, 2007)
+BUG #113460: where the node type edit form didn't have the option of turning it off per content type.
+
+5.x-1.0 (January 27, 2007)
+First release compatible with Drupal 5.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/prepopulate/INSTALL.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,10 @@
+
+INSTALLING PREPOPULATE MODULE
+=============================
+
+1. Copy the prepopulate/ directory into your Drupal installation's
+modules directory (normally at sites/all/modules.)
+
+2. Enable the prepopulate module in admin/build/modules.
+
+3. Refer to the USAGE.txt file or the online handbook at http://drupal.org/node/228167 for URL examples.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/prepopulate/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/prepopulate/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+
+PREPOPULATE MODULE
+==================
+By ea.Farris, based on an idea from chx.
+Maintained by Addison Berry (add1sun).
+
+Prepopulate is an attempt to solve the problem that resulted from
+the discussion at http://www.drupal.org/node/27155 where the $node object,
+it was (correctly, I believe) decided, should
+not be prefilled from the $_GET variables, and instead, the power of the
+FormsAPI should be used to modify the #default_value of the form
+elements themselves.
+
+This functionality will make things like bookmarklets easier to write,
+since it basically allows forms to be prefilled from the URL, using a
+syntax like:
+
+http://www.example.com/node/add/blog?edit[title]=this is the title&edit[body]=body goes here
+
+Refer to the USAGE.txt file or the online handbook at http://drupal.org/node/228167 for more examples.
+
+Please report any bugs or feature requests to the Prepopulate issue queue:
+http://drupal.org/project/issues/prepopulate
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/prepopulate/USAGE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,176 @@
+
+See README.txt for a description of this module.
+See this documentation online at http://drupal.org/node/228167.
+
+USING PREPOPULATE MODULE
+========================
+
+Simple Usage
+------------
+
+Prepopulate the title field on a node creation form:
+  http://www.example.com/node/add/content?edit[title]=This is the title
+With 'non-clean' urls:
+  http://www.example.com?q=node/add/content&edit[title]=This is the title
+
+
+POST Requests
+-------------
+Since Prepopulate uses the $_REQUEST variable, you have access to prepopulate
+form values from either GET request in the URL, or the form POST requests. In
+the below example, we prepopulate a node form's title based on a POST Request:
+
+<html><body>
+  <form method="post" action="http://example.com/node/add/story">
+    Title: <input type="text" size="12" maxlength="12" name="edit[title]">
+    <input type="submit">
+  </form>
+</body></html>
+
+
+POST Requests
+-------------
+Since Prepopulate uses the $_REQUEST variable, you have access to prepopulate
+form values from either GET request in the URL, or the form POST requests. In
+the below example, we prepopulate a node form's title based on a POST Request:
+
+<html><body>
+  <form method="post" action="http://example.com/node/add/story">
+    Title: <input type="text" size="12" maxlength="12" name="edit[title]">
+    <input type="submit">
+  </form>
+</body></html>
+
+
+How to find what variable to set
+--------------------------------
+
+This can be tricky, but there are a few things to keep in mind that
+should help.
+
+Prepopulate.module is quite simple. It looks through the form, looking
+for a variable that matches the name given on the URL, and puts the
+value in when it finds a match. Drupal keeps HTML form entities in an
+edit[] array structure. All your variables will be contained within the
+edit[] array.
+
+A good starting point is to look at the HTML code of a rendered Drupal
+form. Once you find the appropriate <input /> (or <textarea>...</textarea>
+tag, use the value of the name attribute in your URL, contained in the
+edit array. For example, if the <input /> tag looks like this:
+
+  <input id="edit-title" class="form-text required" type="text" value=""
+  size="60" name="title" maxlength="128"/>
+
+then try this URL:
+
+  http://www.example.com/node/add/content?edit[title]=Automatic filled in title
+
+CCK fields are a bit more complicated:
+
+  <input id="edit-field-office-0-node-name" class="form-text
+  form-autocomplete" type="text" value="" size="60"
+  name="field_office[0][node_name]" maxlength="128" autocomplete="OFF"/>
+
+The key is to put this in the edit[] array nested, like this:
+
+  http://www.example.com/node/add/content?edit[field_office][0][node_name]=AL-235
+
+Another example:
+
+  <textarea id="edit-field-content-0-value" class="form-textarea
+  resizable processed" name="field_content[0][value]" rows="10"
+  cols="60"/>
+
+would be:
+
+  http://www.example.com/node/add/content?edit[field_content][0][value]=A long text string
+
+and, again, for non-clean URLs, it's:
+
+  http://www.example.com?q=node/add/content&edit[field_content][0][value]=A long text string
+
+
+CCK fields will vary a bit depending on how the input widgets are
+configured. Here are some examples.
+
+	Date fields with a separate time entry would look like:
+
+		edit[field_date][0][value][date]=11%20Aug%202010&edit[field_date][0][value][time]=12:00PM
+
+	Select Lists:
+	
+		edit[field_selectList][value]=1
+
+	Note that in this example "1" is the key value for the select field.
+		
+	Node Reference:
+	
+		edit[field_nodereference][0][nid][nid]=[nid: #]
+
+Some Non-CCK examples:
+
+	Taxomony Tags:
+	
+		edit[taxonomy][tags][1]=myTag
+
+
+Body fields
+-----------
+
+Body fields are different. Though their HTML entity looks like this:
+  <textarea id="edit-body" class="form-textarea resizable processed"
+  name="body" rows="20" cols="60"/>
+
+You can't just take the name "body," throw it into a edit[body] and
+expect it to work. Drupal wraps the body field into a "body_field"
+array when it gets processed. So, for body fields, a URL like:
+
+  http://www.example.com/node/add/content?edit[body_field][body]=This is the body
+
+ought to do the trick.
+
+
+Multiple fields
+---------------
+
+Prepopulate can handle pre-filling multiple fields from one URL. Just
+separate the edit variables with an ampersand:
+
+  http://www.example.com/node/add/content?edit[title]=The title&edit[body_field][body]=The body
+
+You're already using the ampersand with non-clean URLs:
+
+  http://www.example.com?q=node/add/content&edit[title]=The title&edit[body_field][body]=The body
+
+
+Escaping special characters
+---------------------------
+
+Some characters can't be put into URLs. Spaces, for example, work
+mostly, but occasionally they'll have to be replaced with the string %20.
+This is known as "percent encoding." Wikipedia has a partial list of
+percent codes at:
+  http://en.wikipedia.org/wiki/Percent-encoding
+
+If you're having trouble getting content into field names, or are
+getting 'page not found' errors from Drupal, you should check to ensure
+that illegal characters are properly encoded.
+
+
+Bookmarklets
+------------
+
+Prepopulate.module was created for bookmarklets. Here is a bookmarklet for
+posting web links to a site:
+
+javascript:u=document.location.href;t=document.title;s=window.getSelection();void(window.open(%22http://example.com/node/add/content-web-link?edit[title]=%22+escape(t)+'&edit[body_field][body]='+escape(s)+'&edit[field_url][0][value]='+escape(u),'_blank','width=1024,height=500,status=yes,resizable=yes,scrollbars=yes'));
+
+This turns into a URL like this:
+
+http://example.com/node/add/content-web-link?edit[title]=drupal.org%20%7C%20Community%20plumbing&edit[body_field][body]=&edit[field_url][0][value]=http%3A//drupal.org/
+
+Selecting some text on the page first would put that text into the
+body of the node.
+
+Happy prepopulating!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/prepopulate/prepopulate.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,10 @@
+name = Prepopulate
+description = Allows form elements to be prepopulated from the URL.
+core = 7.x
+
+; Information added by drupal.org packaging script on 2013-05-25
+version = "7.x-2.x-dev"
+core = "7.x"
+project = "prepopulate"
+datestamp = "1369450574"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/prepopulate/prepopulate.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * Implementation of hook_install().
+ */
+function prepopulate_install() {
+  $ret = array();
+  // Ensure that prepopulate sinks to the bottom during hook calls
+  // there should be a UI for this at some point.
+  $ret[] = db_query("UPDATE {system} SET weight = 10 WHERE name = 'prepopulate'");
+  return $ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/prepopulate/prepopulate.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Fill form elements with data from GET or POST values.
+ *
+ * Originally written by ea. Farris <eafarris@gmail.com>
+ * Based on an idea from chx, from the conversation at
+ * http://www.drupal.org/node/27155.
+ */
+
+/**
+ * Implementation of hook_help().
+ */
+function prepopulate_help($path, $arg) {
+  switch ($path) {
+    case 'admin/modules#description':
+      return t('Pre-populates forms with HTTP GET or POST data');
+      break;
+  }
+}
+
+/**
+ * Implementation of hook_form_alter().
+ */
+function prepopulate_form_alter(&$form, $form_state, $form_id) {
+  // Provide for accepting base64 encoded fields.
+  if (isset($_REQUEST['pp'])) {
+    parse_str(base64_decode($_REQUEST['pp']), $_REQUEST);
+  }
+  if (isset($_REQUEST['edit'])) {
+    $form['#after_build'][] = 'prepopulate_after_build';
+  }
+}
+
+/**
+ * An #after_build function to set the values prepopulated in the request.
+ */
+function prepopulate_after_build($form, &$form_state) {
+  if (isset($_REQUEST['pp'])) {
+    parse_str(base64_decode($_REQUEST['pp']), $_REQUEST);
+  }
+  if (isset($_REQUEST['edit'])) {
+    $request = (array)$_REQUEST['edit'];
+    _prepopulate_request_walk($form, $request);
+  }
+  return $form;
+}
+
+/**
+ * Internal helper to set element values from the $_REQUEST variable.
+ *
+ * @param &$form
+ *   Array. A form element.
+ * @param &$requestslice
+ *   String or array. Value(s) to be applied to the element.
+ */
+function _prepopulate_request_walk(&$form, &$requestslice) {
+  $limited_types = array('value', 'hidden', 'button', 'image_button');
+  if (is_array($requestslice)) {
+    foreach (array_keys($requestslice) as $requestvar) {
+      if (element_child($requestvar) && !empty($form[$requestvar]) &&
+       (!isset($form[$requestvar]['#type']) || !in_array($form[$requestvar]['#type'], $limited_types))) {
+        if (!isset($form[$requestvar]['#access']) || $form[$requestvar]['#access'] != FALSE) {
+          _prepopulate_request_walk($form[$requestvar], $requestslice[$requestvar]);
+        }
+      }
+    }
+    if (!empty($form['#default_value']) && is_array($form['#default_value'])) {
+      $form['#default_value'] = array_merge($form['#default_value'], $requestslice);
+    }
+  }
+  else {
+    if ($form['#type'] == 'markup' || empty($form['#type']) ) {
+      $form['#value'] = check_plain($requestslice);
+    }
+    else {
+      $form['#value'] = $requestslice;
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdf_example/rdf_example.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,5 @@
+name = RDF Example
+description = Demonstrates an RDF mapping using the RDF mapping API.
+core = 7.x
+dependencies[] = richsnippets
+dependencies[] = field_collection
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdf_example/rdf_example.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,130 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Install file for RDF Example module.
+ *
+ * To demonstrate hook_rdf_mapping, this module creates it's own node type. For
+ * more information on creating node types, see Node Example in the Examples
+ * project, http://drupal.org/project/examples.
+ */
+
+/**
+ * Implements hook_install().
+ *
+ * - Create photo, summary, nutrition info, serving size, and calorie fields.
+ * - Create photo, summary, nutrition info, serving size, and calorie instances.
+ */
+function rdf_example_install() {
+  // use get_t() to get the name of our localization function for translation
+  // during install, when t() is not available.
+  $t = get_t();
+
+  // Define the node type.
+  $rdf_example = array(
+    'type' => 'recipe',
+    'name' => $t('Recipe'),
+    'base' => 'node_content',
+    'description' => $t('The recipe node is defined to demonstrate RDF mapping.'),
+  );
+
+  // Set additional defaults and save the content type.
+  $content_type = node_type_set_defaults($rdf_example);
+  node_type_save($content_type);
+
+  // Create all the fields we are adding to our content type.
+  // http://api.drupal.org/api/function/field_create_field/7
+  foreach (_rdf_example_installed_fields() as $field) {
+    field_create_field($field);
+  }
+
+  // Create all the instances for our fields.
+  // http://api.drupal.org/api/function/field_create_instance/7
+  foreach (_rdf_example_installed_instances() as $bundle_name => $bundle) {
+    foreach ($bundle as $instance) {
+      $instance['entity_type'] = $bundle_name == 'recipe' ? 'node' : 'field_collection_item';
+      $instance['bundle'] = $bundle_name;
+      field_create_instance($instance);
+    }
+  }
+}
+
+/**
+ * Return a structured array defining the fields created by this content type.
+ */
+function _rdf_example_installed_fields() {
+  $t = get_t();
+  $return = array(
+    'recipe_photo' => array(
+      'field_name' => 'recipe_photo',
+      'cardinality' => 1,
+      'type'        => 'image',
+    ),
+    'recipe_summary' => array(
+      'field_name'  => 'recipe_summary',
+      'cardinality' => 1,
+      'type'        => 'text',
+      'settings'    => array(
+        'max_length' => 500,
+      ),
+    ),
+    'recipe_nutrition' => array(
+      'field_name'  => 'recipe_nutrition',
+      'cardinality' => 1,
+      'type'        => 'field_collection',
+    ),
+    'recipe_serving_size' => array(
+      'field_name'  => 'recipe_serving_size',
+      'cardinality' => 1,
+      'type'        => 'text',
+    ),
+    'recipe_calories' => array(
+      'field_name'  => 'recipe_calories',
+      'cardinality' => 1,
+      'type'        => 'number_integer',
+    ),
+  );
+
+  return $return;
+}
+
+/**
+ * Return a structured array defining the instances for this content type and
+ * related field collections.
+ */
+function _rdf_example_installed_instances() {
+  $t = get_t();
+  $instances = array();
+  $instances['recipe'] = array(
+    'recipe_photo' => array(
+      'field_name'  => 'recipe_photo',
+      'label'       => $t('Photo of the prepared dish'),
+    ),
+    'recipe_summary' => array(
+      'field_name' => 'recipe_summary',
+      'label'       => $t('Short summary describing the dish'),
+      'widget'      => array(
+        'type'    => 'text_textarea',
+      ),
+    ),
+    'recipe_nutrition' => array(
+      'field_name' => 'recipe_nutrition',
+      'label'      => $t('Recipe Nutrition Information'),
+    ),
+  );
+  // We attach some fields directly to the field collections. The field
+  // collection bundles are created automatically with the field definition.
+  $instances['recipe_nutrition'] = array(
+    'recipe_serving_size' => array(
+      'field_name' => 'recipe_serving_size',
+      'label'       => $t('Serving size'),
+    ),
+    'recipe_calories' => array(
+      'field_name' => 'recipe_calories',
+      'label'       => $t('Calories'),
+    )
+  );
+
+  return $instances;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdf_example/rdf_example.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,77 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * This is an example outlining how a module can be used to define RDF mappings.
+ * We define mappings for a node type defined in this module.
+ */
+
+/**
+ * Implements hook_rdf_mapping().
+ *
+ * This hook should only be used to define the RDF mapping for an entity or
+ * bundle that has been defined by this module. On installation, this mapping
+ * will be saved to the database. To alter anything in this mapping after module
+ * installation (or to alter bundles defined in another module), the RDF CRUD
+ * functions should be used.
+ */
+function rdf_example_rdf_mapping() {
+  return array(
+    'recipe' => array(
+      'type' => 'node',
+      'bundle' => 'recipe',
+      'mapping' => array(
+        'rdftype' => array('v:Recipe'),
+        // We don't use the default bundle mapping for title. Instead, we add
+        // the v:name property. We still want to use dc:title as well, though,
+        // so we include it in the array.
+        'title' => array(
+          'predicates' => array('dc:title', 'v:name'),
+        ),
+        'recipe_summary' => array(
+          'predicates' => array('v:summary'),
+        ),
+        // The photo URI isn't a string but instead points to a resource, so we
+        // indicate that the attribute type is rel. If type isn't specified, it
+        // defaults to property, which is used for string values.
+        'recipe_photo' => array(
+          'predicates' => array('v:photo'),
+          'type' => 'rel',
+        ),
+        'recipe_nutrition' => array(
+          'predicates' => array('v:nutrition'),
+          'type' => 'rel',
+        ),
+      ),
+    ),
+    'nutrition' => array(
+      'type' => 'field_collection_item',
+      'bundle' => 'recipe_nutrition',
+      'mapping' => array(
+        'rdftype' => array('v:Nutrition'),
+        'recipe_serving_size' => array(
+          'predicates' => array('v:servingSize'),
+        ),
+        'recipe_calories' => array(
+          'predicates' => array('v:calories'),
+        ),
+      ),
+    ),
+  );
+}
+
+/*
+ * Implements hook_rdf_namespaces().
+ *
+ * This hook should be used to define any prefixes used by this module that are
+ * not already defined in core by rdf_rdf_namespaces.
+ *
+ * http://api.drupal.org/api/drupal/modules--rdf--rdf.api.php/function/hook_rdf_namespaces/7
+ */
+function rdf_example_rdf_namespaces() {
+  return array(
+    // Google's namespace for their custom vocabularies.
+    'v' => 'http://rdf.data-vocabulary.org/#', 
+  );
+}
\ No newline at end of file
Binary file sites/all/modules/rdfx/.DS_Store has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,68 @@
+RDF is a W3C standard for modeling and sharing distributed knowledge based on a
+decentralized open-world assumption. This RDF Extensions (RDFx) package for
+Drupal 7 includes several modules to enhance the RDF and RDFa functionality
+which are part of Drupal 7 core.
+
+This project includes the following modules:
+
+* RDFx: extends core RDF support by providing extra APIs and additional
+  serialization formats such as RDF/XML, NTriples, Turtle... (requires the
+  RESTful Web Services module). Browse to node/1.rdf or node/1.nt to export RDF.
+* RDF UI: allows site administrators to manage the RDF mappings of their site:
+  alter default core mappings or specify mappings for the new content types and
+  fields they create.
+* Evoc: enables the import of RDF vocabularies (such as FOAF, SIOC, etc.) which
+  the site administrator can use to map Drupal data to RDF.
+
+
+== Dependencies ==
+
+This project requires the Entity API module:
+http://drupal.org/project/entity
+
+
+== Related projects ==
+
+Download the following modules to avail more RDF features:
+
+* RESTful Web Services module for RDF serializations
+  http://drupal.org/project/restws
+
+* The site RDF data can be made available in a SPARQL endpoint with the
+  SPARQL module.
+  http://drupal.org/project/sparql
+
+
+== Install the RDF Extensions (RDFx) module ==
+
+  1. Copy all the module files into a subdirectory called
+     sites/all/modules/rdfx/ under your Drupal installation directory.
+
+  2. Go to Administer >> Site building >> Modules and enable the RDFx module and
+     any other module you would like. You will find them in the "RDF" section.
+
+  3. Install the ARC2 library following one of these 2 options:
+       - run "drush rdf-download" (recommended, it will download the right
+         package and extract it at the right place for you.)
+       - manual install: download the library from
+       http://github.com/semsol/arc2/tarball/master and extract it in the rdfx
+       module directory such that you end up with the following file structure:
+       sites/all/modules/rdfx/vendor/arc/ARC2.php
+
+
+== Bug reports ==
+
+Post bug reports and feature requests to the issue tracking system at:
+<http://drupal.org/node/add/project_issue/rdf>
+
+
+== Credits ==
+The original RDF module was written for Drupal 6 by Arto Bendiken. It has been
+refactored for Drupal 7 by Stéphane Corlosquet, Lin Clark and Richard Cyganiak,
+based on the RDF CCK and Evoc modules, which are now part of the main RDF
+package for Drupal 7.
+
+
+== Current maintainers ==
+  Stéphane "scor" Corlosquet - <http://openspring.net/>
+  Lin Clark - <http://lin-clark.com/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/drush/rdfx.drush.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ *   drush integration for rdfx.
+ */
+
+/**
+ * Implementation of hook_drush_command().
+ *
+ * In this hook, you specify which commands your
+ * drush module makes available, what it does and
+ * description.
+ *
+ * Notice how this structure closely resembles how
+ * you define menu hooks.
+ *
+ * @See drush_parse_command() for a list of recognized keys.
+ *
+ * @return
+ *   An associative array describing your command(s).
+ */
+function rdfx_drush_command() {
+  $items = array();
+
+  $items['rdf-download'] = array(
+    'callback' => 'rdfx_drush_arc2_download',
+    'description' => dt('Downloads the required ARC2 library from http://github.com/semsol/arc2'),
+    'aliases' => array('rdfdl'),
+    'arguments' => array(
+      'path' => dt('Optional. A path to the rdfx module. If omitted Drush will use the default location.'),
+    ),
+  );
+  return $items;
+}
+
+/**
+ * Implementation of hook_drush_help().
+ *
+ * This function is called whenever a drush user calls
+ * 'drush help <name-of-your-command>'
+ *
+ * @param
+ *   A string with the help section (prepend with 'drush:')
+ *
+ * @return
+ *   A string with the help text for your command.
+ */
+function rdfx_drush_help($section) {
+  switch ($section) {
+    case 'drush:rdf-download':
+      return dt("Downloads the required ARC2 library from http://github.com/semsol/arc2. Include the optional path.");
+  }
+}
+
+/**
+ * Example drush command callback.
+ *
+ * This is where the action takes place.
+ *
+ * In this function, all of Drupals API is (usually) available, including
+ * any functions you have added in your own modules/themes.
+ *
+ * To print something to the terminal window, use drush_print().
+ *
+ */
+function rdfx_drush_arc2_download() {
+  $args = func_get_args();
+  if ($args[0]) {
+    $path = $args[0];
+  }
+  else {
+    $path = drush_get_context('DRUSH_DRUPAL_ROOT');
+    if (module_exists('libraries')) {
+      $path .= '/' . libraries_get_path('ARC2');
+    }
+    else {
+      $path .= '/' . drupal_get_path('module', 'rdfx') . '/vendor';
+    }
+  }
+
+  // Create the path if it does not exist yet.
+  if (!is_dir($path)) {
+    drush_mkdir($path);
+  }
+
+  if (is_dir($path . '/arc')) {
+    drush_log('ARC2 already present. No download required.', 'ok');
+  }
+  elseif (drush_op('chdir', $path) &&
+      drush_shell_exec('wget --no-check-certificate -O arc.tar.gz http://github.com/semsol/arc2/tarball/master') &&
+      drush_shell_exec('tar zxvf arc.tar.gz') &&
+      drush_shell_exec('mv semsol-arc2-* arc') &&
+      drush_shell_exec('rm arc.tar.gz')) {
+    drush_log(dt('The latest ARC2 library has been downloaded to @path', array('@path' => $path)), 'success');
+  }
+  else {
+    drush_log(dt('Drush was unable to download the ARC2 library to @path', array('@path' => $path)), 'error');
+  }
+}
+
+/**
+ * Implements drush_MODULE_post_COMMAND().
+ */
+function drush_rdfx_post_pm_enable() {
+  $extensions = func_get_args();
+  // Deal with comma delimited extension list.
+  if (strpos($extensions[0], ',') !== FALSE) {
+    $extensions = explode(',', $extensions[0]);
+  }
+
+  if (in_array('rdfx', $extensions) && !drush_get_option('skip')) {
+    rdfx_drush_arc2_download();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/evoc/evoc.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+name = External RDF Vocabulary Importer
+description = Allows to import external Vocabularies in order to map them to Drupal data structure.
+dependencies[] = rdfx
+package = RDF
+version = VERSION
+core = 7.x
+files[] = evoc.module
+files[] = evoc.pages.inc
+files[] = evoc.load_vocab.inc
+files[] = evoc.install
+files[] = evoc.test
+
+; Information added by drupal.org packaging script on 2011-10-01
+version = "7.x-2.0-alpha4"
+core = "7.x"
+project = "rdfx"
+datestamp = "1317447407"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/evoc/evoc.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the evoc module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function evoc_install() {
+  drupal_set_message('You can now ' . l('import the core RDF vocabularies', 'evoc/import_core') . '.');
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/evoc/evoc.load_vocab.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,22 @@
+<?php
+
+function _evoc_load__error_handler($errno, $errstr) {
+    throw new Exception($errstr);
+}
+
+function _evoc_query_for_term_description(&$model, $uri) {
+  $label = _rdfx_query_find_literal($model, array(
+    array($uri, 'http://www.w3.org/2000/01/rdf-schema#label', '?')
+  ));
+
+  $comment = _rdfx_query_find_literal($model, array(
+    array($uri, 'http://www.w3.org/2004/02/skos/core#definition', '?'),
+    array($uri, 'http://www.w3.org/2000/01/rdf-schema#comment', '?'),
+  ));
+
+  return array(
+      'uri' => $uri,
+      'label' => $label,
+      'comment' => $comment,
+  );
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/evoc/evoc.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Allows to import external Vocabularies in order to map them to Drupal data
+ * structure.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function evoc_menu() {
+  $items['evoc/import'] = array(
+    'title' => 'Import external RDF vocabulary',
+    'description' => 'Import RDF terms of an external vocabulary.',
+    'page callback' => 'evoc_import',
+    'access arguments' => array('administer content types'),
+    'file' => 'evoc.pages.inc',
+  );
+  $items['evoc/import_core'] = array(
+    'title' => 'Import core RDF vocabularies',
+    'description' => 'Perform a batch import of the vocabularies used by core.',
+    'page callback' => 'evoc_import_core',
+    'access arguments' => array('administer content types'),
+    'file' => 'evoc.pages.inc',
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function evoc_rdf_namespaces() {
+  $ns_mappings = array();
+  $query = db_select('rdfx_vocabulary_graphs', 'g');
+  $query->fields('n', array('prefix', 'uri'));
+  $query->join('rdfx_namespaces', 'n', 'g.main_ns = n.nsid');
+  $query->orderBy('n.prefix');
+  $namespaces = $query->execute()->fetchAll();
+  foreach ((array) $namespaces as $namespace) {
+    $ns_mappings[$namespace->prefix] = $namespace->uri;
+  }
+  return $ns_mappings;
+}
+
+/*
+ * Import function for the evoc module.
+ */
+function evoc_import_vocabulary($vocabulary_uri, $vocabulary_prefix) {
+  // Fetch the defined terms and a list of the defined namespaces.
+  $fetched_vocab = evoc_fetch_vocabulary($vocabulary_uri, $vocabulary_prefix);
+  rdfx_save_terms($vocabulary_uri, $vocabulary_prefix, $fetched_vocab);
+
+  // Refresh the static variable that holds the array of namespaces.
+  drupal_static_reset('rdfx_get_namespaces');
+  //_evoc_save_rdf_terms($vocabulary_uri, $vocabulary_prefix, $fetched_terms);
+}
+
+/**
+ * Fetches the classes and properties of an external RDF vocabulary.
+ *
+ * @param $vocabulary_uri
+ *   The namespace of the vocabulary to be fetched. Note most of the time this
+ *   URI should end with / or #, e.g. http://rdfs.org/sioc/ns#
+ * @param $vocabulary_prefix
+ *   Prefix used system-wide for referring to this namespace.
+ * @param $vocabulary_location
+ *   URL of the vocabulary if the vocabulary namespace does not dereference and
+ *   is not available at the namespace. Optionnal.
+ * @return
+ *   An array of fetched terms.
+ */
+function evoc_fetch_vocabulary($vocabulary_uri, $vocabulary_prefix, $vocabulary_location = NULL) {
+  // Uses the vocabulary namespace URI if no specific location is given.
+  $vocabulary_location = $vocabulary_location ? $vocabulary_location : $vocabulary_uri;
+
+  module_load_include('inc', 'evoc', 'evoc.load_vocab');
+  list($triples, $namespaces) = rdfx_fetch_rdf($vocabulary_uri, $vocabulary_prefix);
+  $vocabulary = _rdfx_extract_schema($triples, $namespaces, $vocabulary_prefix, $vocabulary_uri);
+  return $vocabulary;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/evoc/evoc.pages.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,166 @@
+<?php
+
+/**
+ * @file
+ * Page callbacks for importing a vocabulary.
+ */
+
+/**
+ * Present a node submission form or a set of links to such forms.
+ */
+function evoc_import() {
+  return drupal_get_form('evoc_import_form');
+}
+
+
+function evoc_import_form($form_state) {
+  // Retrieves all the imported namespaces from the database.
+  $query = db_select('rdfx_vocabulary_graphs', 'g');
+  $query->fields('n', array('prefix', 'uri'));
+  $query->join('rdfx_namespaces', 'n', 'g.main_ns = n.nsid');
+  $query->orderBy('n.prefix');
+  $namespaces = $query->execute()->fetchAll();
+
+  if (count($namespaces) == 0) {
+    $namespace_msg = '<p>No RDF vocabularies have been imported. It is recommended that you ' . l('import the core RDF vocabularies', 'evoc/import_core') . '.</p>';
+  }
+  else {
+    $table_variables = array();
+    foreach ($namespaces as $namespace) {
+      $table_variables['rows'][] = array($namespace->prefix, $namespace->uri);
+    }
+    $namespace_msg = theme('table', $table_variables);
+  }
+
+  $form['help'] = array(
+    '#type' => 'item',
+    '#markup' => '<p>This form allows you to import external RDF vocabularies into your site.
+    These can later be used by other modules such as <a href="http://drupal.org/project/rdf">RDF UI</a> or <a href="http://drupal.org/project/neologism">Neologism</a>.</p>',
+  );
+  $form['namespace_box'] = array(
+    '#type' => 'fieldset',
+    '#title' => 'Imported vocabularies',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+  $form['namespace_box']['namespaces'] = array(
+    '#type' => 'item',
+    '#markup' => $namespace_msg,
+  );
+  $form['prefix'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Prefix'),
+    '#required' => TRUE,
+    '#default_value' => isset($form_state['values']['prefix']) ? $form_state['values']['prefix'] : NULL,
+    '#description' => "Choose a prefix for this vocabulary. Example: dc, foaf, sioc etc. This prefix will later be used in the system to refer to this vocabulary.",
+  );
+  $form['ns_uri'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Vocabulary URI'),
+    '#required' => TRUE,
+    '#default_value' => isset($form_state['values']['ns_uri']) ? $form_state['values']['ns_uri'] : NULL,
+    '#description' => "Enter the URI of the vocabulary to import. Make sure it finishes by either / or #.",
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Submit',
+  );
+  return $form;
+}
+
+function evoc_import_form_validate($form, &$form_state) {
+  // Load the XML Namespace regular expression patterns.
+  module_load_include('inc', 'rdfx');
+
+  $prefix = $form_state['values']['prefix'];
+  $ns_uri = $form_state['values']['ns_uri'];
+
+  // Ensure the that namespace is a valid URI.
+  if (!valid_url($ns_uri, $absolute = TRUE)) {
+    form_set_error('ns_uri', t('The Vocabulary URI must be a valid URI.'));
+  }
+  // Ensure the namespace URI ends in either a / or a #.
+  if (!preg_match('/(\/|\#)$/', $ns_uri)) {
+    form_set_error('ns_uri', t('The Vocabulary URI must end in either a / or a #.'));
+  }
+  // Ensure the prefix is well formed according to the specification.
+  if (!preg_match('/^' . PREFIX .'$/', $prefix)) {
+    form_set_error('prefix', t('The prefix must follow the !link.', array('!link' => '<a href="http://www.w3.org/TR/xml-names11/#NT-NCName">XML Namespace Specification</a>')));
+  }
+}
+
+function evoc_import_form_submit($form, &$form_state) {
+// @todo is that still the best way to keep the value when the form is reloaded?
+  $form_state['storage']['values'] = $form_state['values'];
+  $form_state['rebuild'] = true;
+
+  evoc_import_vocabulary($form_state['values']['ns_uri'], $form_state['values']['prefix']);
+
+  drupal_set_message(t('The @voc vocabulary has been imported.', array('@voc' => $form_state['values']['prefix'])));
+}
+
+/**
+ * Provide a callback for batch importing the vocabularies used in core.
+ */
+function evoc_import_core() {
+  $vocabularies = rdf_rdf_namespaces();
+  $operations = array();
+  foreach ($vocabularies as $prefix => $namespace_uri) {
+    $operations[] = array(
+      '_evoc_install_batch_process',
+      array(
+        $namespace_uri,
+        $prefix,
+      ),
+    );
+  }
+  $batch = array(
+    'title' => t('Downloading RDF vocabularies'),
+    'init_message' => t('Preparing to download the core RDF vocabularies'),
+    'operations' => $operations,
+    'finished' => '_evoc_install_batch_finished',
+    'file' => drupal_get_path('module', 'evoc') . '/evoc.pages.inc',
+  );
+  batch_set($batch);
+  batch_process('evoc/import');
+}
+
+/*
+ * Evoc Install batch process.
+ */
+function _evoc_install_batch_process($namespace_uri, $prefix, &$context) {
+  if (!isset($context['sandbox']['progress'])) {
+    $context['sandbox']['progress'] = 0;
+    $context['message'] = t('Downloading %prefix', array('%prefix' => $prefix));
+    $context['finished'] = 0;
+    return;
+  }
+
+  evoc_import_vocabulary($namespace_uri, $prefix);
+
+  // Store result for post-processing in the finished callback.
+  $context['results'][] = $prefix;
+
+  // Update our progress information.
+  $context['sandbox']['progress']++;
+
+  $context['finished'] = 1;
+}
+
+/**
+ * Evoc Install batch 'finished' callback.
+ */
+function _evoc_install_batch_finished($success, $results, $operations) {
+  if ($success) {
+    drupal_set_message(t('The RDF vocabularies ' . implode(', ', $results) . ' have been imported.'));
+    return;
+  }
+  else {
+    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
+    $message = format_plural(count($results), '1 item successfully processed:', '@count items successfully processed:');
+    $message .= theme('item_list', array('items' => $results));
+    drupal_set_message($message);
+    return;
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/evoc/evoc.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * @file
+ * Tests Evoc functionality.
+ */
+
+class VocabularyImportTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Vocab import',
+      'description' => 'Test vocabulary import.',
+      'group' => 'Evoc',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rdf', 'rdfx', 'evoc', 'evoc_test');
+    $this->prefix = array();
+    $this->vocab_uri = array();
+  }
+
+  /**
+   * Functional test for vocabulary import.
+   *
+   * NOTE: This test requires having evoc_test manually enabled. Even when it is
+   * enabled in setUp, the parser fails to intialize. It may be that the headers
+   * aren't sent properly when accessed within site.
+   */
+  function testImport() {
+    $format = 'rdf_xml';
+    $this->importVocabulary($format);
+    $namespaces = array(
+      $this->prefix[$format] => $this->vocab_uri[$format],
+      'xml' => 'http://www.w3.org/XML/1998/namespace',
+      'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+      'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
+      'owl' => 'http://www.w3.org/2002/07/owl#',
+      'vs' => 'http://www.w3.org/2003/06/sw-vocab-status/ns#',
+      'foaf' => 'http://xmlns.com/foaf/0.1/',
+      'dc' => 'http://purl.org/dc/elements/1.1/',
+    );
+    // Test that namespaces have been imported and placed in correct
+    // vocabulary graph.
+    foreach ($namespaces as $prefix => $namespace) {
+      $records = db_query("SELECT uri, prefix, gid FROM {rdfx_namespaces} WHERE uri='$namespace' AND prefix='$prefix'")->fetchAll();
+      if (count($records) == 1) {
+        $record = $records[0];
+        $this->assertEqual($record->gid, 1, t("Vocabulary $record->prefix is imported as part of correct vocabulary graph."));
+      }
+      else {
+        $this->assert(FALSE, t("Vocabulary $record->prefix is imported ."));
+      }
+    }
+
+    // Test that user defined prefix was used, per issue #925520.
+    $records = db_query("SELECT uri, prefix, gid FROM {rdfx_namespaces} WHERE prefix='doap'")->fetchAll();
+    $this->assert(count($records) == 0, t('The user defined prefix was used.'));
+  }
+
+  /*
+   * Test that vocabulary is updated.
+   */
+  function testUpdate() {
+  }
+  
+  protected function importVocabulary($format) {
+    $absolute_url = $this->getAbsoluteUrl("evoc_test/vocabulary_$format");
+    $this->vocab_uri[$format] = "$absolute_url#";
+    $this->prefix[$format] = "test_$format";
+    $this->edit = array(
+      'prefix' => $this->prefix[$format],
+      'ns_uri' => $this->vocab_uri[$format] ,
+    );
+    $user = $this->drupalCreateUser(array('administer content types'));
+    $this->drupalLogin($user);
+    $this->drupalPost('evoc/import', $this->edit, t('Submit'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/evoc/tests/evoc_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Evoc Test
+description = Provides vocabularies for import testing.
+core = 7.x
+package = RDF
+
+files[] = evoc_test.module
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2011-10-01
+version = "7.x-2.0-alpha4"
+core = "7.x"
+project = "rdfx"
+datestamp = "1317447407"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/evoc/tests/evoc_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Test vocabulary import.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function evoc_test_menu() {
+  $items['evoc_test/vocabulary_rdf_xml'] = array(
+    'title'           => 'RDF/XML vocabulary',
+    'description'     => 'Fake RDF/XML vocabulary for import testing.',
+    'page callback'   => '_vocabulary_rdf_xml',
+    'access callback' => TRUE,
+  );
+  $items['evoc_test/vocabulary_n3'] = array(
+    'title'           => 'N3 vocabulary',
+    'description'     => 'Fake N3 vocabulary for import testing.',
+    'page callback'   => '_vocabulary_n3',
+    'access callback' => TRUE,
+  );
+  return $items;
+}
+function _vocabulary_n3() {
+  global $base_url;
+  $vocab_uri = $base_url . '/evoc_test/vocabulary_n3#';
+  // We fake an n3 vocabulary to feed into the importer.
+  print '@prefix : <' . $vocab_uri . '> .
+     @prefix dc: <http://purl.org/dc/elements/1.1/> .
+     @prefix foaf: <http://xmlns.com/foaf/0.1/> .
+     @prefix owl: <http://www.w3.org/2002/07/owl#> .
+     @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+     @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+     @prefix vs: <http://www.w3.org/2003/06/sw-vocab-status/ns#> .
+    
+    :     a owl:Ontology;
+         dc:description "El vocabulario Descripti\u00F3n of a Project (DOAP, Descripci\u00F3n de un Proyecto), descrito usando RDF Schema de W3C y Web Ontology Language."@es,
+                "The Description of a Project (DOAP) vocabulary, described using W3C RDF Schema and the Web Ontology Language.";
+         dc:title "Description of a Project (DOAP) vocabulary" .
+    
+    :Project     a rdfs:Class;
+         rdfs:isDefinedBy :;
+         rdfs:label "Project"@en,
+                "Proyecto"@es;
+         rdfs:subClassOf foaf:Project,
+                <http://xmlns.com/wordnet/1.6/Project> .
+    
+    :homepage     a rdf:Property,
+                owl:InverseFunctionalProperty;
+         rdfs:comment "El URL de la p\u00E1gina de un proyecto, asociada con exactamente un proyecto."@es,
+                "URL of a project\'s homepage, associated with exactly one project."@en;
+         rdfs:domain <http://usefulinc.com/ns/doap#Project>;
+         rdfs:isDefinedBy :;
+         rdfs:label "homepage"@en,
+                "p\u00E1gina web"@es;
+         rdfs:subPropertyOf foaf:homepage .';
+  return;
+}
+/**
+ * Menu callback ( see evoc_test_menu() ).
+ */
+function _vocabulary_rdf_xml() {
+  global $base_url;
+  $vocab_uri = $base_url . '/evoc_test/vocabulary_rdf_xml#';
+  // We fake an RDF/XML vocabulary to feed into the importer.
+  drupal_add_http_header('Content-Type', 'application/rdf+xml; charset=utf-8');
+  print '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+    xmlns:owl="http://www.w3.org/2002/07/owl#"
+    xmlns:vs="http://www.w3.org/2003/06/sw-vocab-status/ns#"
+    xmlns:foaf="http://xmlns.com/foaf/0.1/"
+    xmlns:dc="http://purl.org/dc/elements/1.1/"
+    xmlns:doap="' . $vocab_uri . '"
+    >
+      <owl:Ontology rdf:about="' . $vocab_uri . '">
+        <dc:title>Description of a Project (DOAP) vocabulary</dc:title>
+	<dc:description>The Description of a Project (DOAP) vocabulary, described using W3C RDF Schema and the Web Ontology Language.</dc:description>
+        <dc:description xml:lang="es">El vocabulario Descripti&#243;n of a Project (DOAP, Descripci&#243;n de un Proyecto), descrito usando RDF Schema de W3C y Web Ontology Language.</dc:description>
+      </owl:Ontology>
+      <rdfs:Class rdf:about="' . $vocab_uri . 'Project">
+	<rdfs:isDefinedBy rdf:resource="' . $vocab_uri . '" />
+	<rdfs:label xml:lang="en">Project</rdfs:label>
+	<rdfs:label xml:lang="es">Proyecto</rdfs:label>
+	<rdfs:subClassOf rdf:resource="http://xmlns.com/wordnet/1.6/Project" />
+	<rdfs:subClassOf rdf:resource="http://xmlns.com/foaf/0.1/Project" />
+      </rdfs:Class>
+
+      <rdf:Property rdf:about="' . $vocab_uri . 'homepage">
+	<rdfs:isDefinedBy rdf:resource="' . $vocab_uri . '" />
+	<rdfs:label xml:lang="en">homepage</rdfs:label>
+	<rdfs:label xml:lang="es">p&#225;gina web</rdfs:label>
+	<rdfs:comment xml:lang="en">URL of a project\'s homepage, associated with exactly one project.</rdfs:comment>
+	<rdfs:comment xml:lang="es">El URL de la p&#225;gina de un proyecto, asociada con exactamente un proyecto.</rdfs:comment>
+	<rdf:type rdf:resource="http://www.w3.org/2002/07/owl#InverseFunctionalProperty" />
+	<rdfs:domain rdf:resource="http://usefulinc.com/ns/doap#Project" />
+	<rdfs:subPropertyOf rdf:resource="http://xmlns.com/foaf/0.1/homepage" />
+      </rdf:Property>
+    </rdf:RDF>';
+return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfui/css/rdfui.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,42 @@
+/*
+ * 3 field widget display
+ */
+.term {
+  padding: 2px;
+  margin-right: 10px;
+  background-color: #eeeeee;
+}
+
+.term-add {
+  margin-right: 5px;
+  margin-left: 5px;
+}
+
+.term-holder {
+  margin-top: 10px;
+  margin-bottom: 10px;
+}
+
+.term-remove {
+  cursor: pointer;
+  color: red;
+  font-weight: bold;
+}
+
+/*
+ * Terms autocomplete on administrative screens.
+ */
+.rdf-term-autocomplete {
+  margin: 0;
+  padding: 0;
+  white-space: normal;
+}
+
+.rdf-comment-autocomplete {
+  border-bottom: 1px solid #ccc;
+  color: #666;
+  font-size: .9em;
+  font-style: italic;
+  margin: 0;
+  padding-bottom: 10px;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfui/rdfui.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = RDF UI
+description = User interface for altering the RDF mapping of Drupal data structure.
+package = RDF
+version = VERSION
+core = 7.x
+dependencies[] = rdfx
+files[] = rdfui.test
+
+; Information added by drupal.org packaging script on 2011-10-01
+version = "7.x-2.0-alpha4"
+core = "7.x"
+project = "rdfx"
+datestamp = "1317447407"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfui/rdfui.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,24 @@
+(function ($) {
+
+Drupal.behaviors.rdfuiFieldsetSummaries = {
+  attach: function (context) {
+    function setSummary() {
+      $(this).drupalSetSummary(function (context) {
+        var formValues = $(':input', context).not('[type=hidden]').map(
+          function () {
+            return $(this).closest('.form-item').css('display') === 'none' ? null : $(this).val()
+          }
+        );
+        // Only show values in the vertical tab if the first
+        // form element (types, predicates) is not empty.
+        return !formValues[0] ? null : Drupal.checkPlain(formValues.toArray().join(' '))
+      })
+    }
+    $('fieldset.rdf-field', context).each(setSummary);
+    $(document).bind('state:visible', function () {
+      Drupal.behaviors.rdfuiFieldsetSummaries.attach($(this).closest('fieldset.rdf-field')[0])
+    })
+  }
+};
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfui/rdfui.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,638 @@
+<?php
+
+/**
+ * @file
+ * User interface for RDF.
+ */
+
+include_once(drupal_get_path('module', 'rdfx') . '/rdfx.inc');
+
+/**
+ * Implements hook_help().
+ */
+function rdfui_help($path, $arg) {
+  switch ($path) {
+    case 'admin/structure/types/manage/%/rdf':
+      return '<p>' . t('Manage the way this bundle and its fields are represented in RDF. The mappings defined here will be used to publish RDFa in the site\'s HTML pages.', array()) . '</p>';
+    case 'admin/help#rdf':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The RDF UI module provides a user interface for altering a bundle\'s RDF mapping.') . '</p>';
+    return $output;
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function rdfui_theme($path, $arg) {
+  return array(
+  'rdfui_term_autocomplete' => array(
+      'render element' => 'term',
+    ),
+  );
+}
+
+/**
+ * Implements hook_permission().
+ */
+function rdfui_permission() {
+  return array(
+    'administer RDF field mappings' => array(
+      'title' => t('Change the RDF mappings for types and fields'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function rdfui_menu() {
+  $items = array();
+
+  // Create tabs for all possible bundles.
+  foreach (entity_get_info() as $entity_type => $info) {
+    if ($info['fieldable']) {
+      foreach ($info['bundles'] as $bundle_name => $bundle_info) {
+        if (isset($bundle_info['admin'])) {
+          // Extract informations from the bundle description.
+          $path = $bundle_info['admin']['path'];
+          $bundle_arg = isset($bundle_info['admin']['bundle argument']) ? $bundle_info['admin']['bundle argument'] : $bundle_name;
+          $access = array_intersect_key($bundle_info['admin'], drupal_map_assoc(array('access callback', 'access arguments')));
+          $instance_position = count(explode('/', $path)) + 1;
+
+          if ($entity_type == 'node') {
+            $title = t('RDF Mappings');
+            $weight = 2;
+          }
+          elseif ($entity_type == 'comment') {
+            continue;
+            $title = t('Comment RDF Mappings');
+            $weight = 60;
+          }
+          else {
+            $title = t('RDF Mappings');
+            $weight = 50;
+          }
+
+          $items["$path/rdf"] = array(
+            'title' => $title,
+            // @todo Load arguments are not necessary / are cruft, right?
+            //'load arguments' => array($obj_type, $bundle_arg),
+            'page callback' => 'drupal_get_form',
+            'page arguments' => array('rdfui_admin_rdf_overview_form', $entity_type, $bundle_arg, $instance_position),
+            'type' => MENU_LOCAL_TASK,
+            'weight' => $weight,
+          ) + $access;
+        }
+      }
+    }
+  }
+
+  $items['rdfui/classes/autocomplete'] = array(
+    'title' => t('RDF classes autocomplete'),
+    'page callback' => 'rdfui_classes_autocomplete',
+    'access arguments' => array('administer RDF field mappings'),
+    'type' => MENU_CALLBACK,
+  );
+
+  $items['rdfui/datatype/autocomplete'] = array(
+    'title' => t('RDF datatype autocomplete'),
+    'page callback' => 'rdfui_datatype_autocomplete',
+    'access arguments' => array('administer RDF field mappings'),
+    'type' => MENU_CALLBACK,
+  );
+
+  $items['rdfui/predicates/autocomplete'] = array(
+    'title' => t('RDF predicates autocomplete'),
+    'page callback' => 'rdfui_predicates_autocomplete',
+    'access arguments' => array('administer RDF field mappings'),
+    'type' => MENU_CALLBACK,
+  );
+
+  return $items;
+}
+
+/**
+ * Menu callback; listing of field RDF mappings for a content type.
+ *
+ * Allows the content type to be mapped to a RDF class and
+ * fields to be mapped to RDF properties.
+ */
+function rdfui_admin_rdf_overview_form($form, &$form_state, $entity_type, $bundle, $instance) {
+  $bundle = field_extract_bundle($entity_type, $bundle);
+  $fields = field_info_instances($entity_type, $bundle);
+  $mapping = rdf_mapping_load($entity_type, $bundle);
+  // Don't make assumptions about entities and only get the type if dealing with a node entity
+  $type = ($entity_type == 'node') ? node_type_get_type($bundle) : '';
+  $form['rdf_mappings'] = array(
+    '#type' => 'vertical_tabs',
+    '#attached' => array(
+      'js' => array(drupal_get_path('module', 'rdfui') . '/rdfui.js'),
+    ),
+  );
+
+  // Declare the fieldset and field for RDF type.
+  $form['type'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Type'),
+    '#group' => 'rdf_mappings',
+    '#attributes' => array('class' => array('rdf-type')),
+  );
+  $form['type']['rdf_rdftype'] = array(
+    '#type' => 'textarea',
+    '#title' => t('RDF Type'),
+    '#attached' => array(
+      'js' => array(drupal_get_path('module', 'rdfui') . '/rdfui.js'),
+    ),
+  );
+
+  // Declare the fieldset and field for RDF type.
+  $form['type'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Type'),
+    '#group' => 'rdf_mappings',
+    '#attributes' => array('class' => array('rdf-field')),
+  );
+  $form['type']['rdf_rdftype'] = array(
+    '#type' => 'textarea',
+    '#title' => t('RDF Type'),
+    '#attributes' => array('class' => array('rdf-field')),
+  );
+
+  // If this entity is a node and has a title display a fieldset for mapping.
+  if (isset($type->has_title)) {
+    $form['rdf_title'] = array(
+      '#type' => 'fieldset',
+      '#group' => 'rdf_mappings',
+      '#title' => $type->title_label,
+      '#attributes' => array('class' => array('rdf-field')),
+    );
+    // Add the options for this entity's title.
+    rdfui_predicate_fieldset($form['rdf_title'], $mapping, 'title', 'title');
+  }
+
+  // Add the field for RDF type.
+  rdfui_rdftype_fieldset($form['type']['rdf_rdftype'], $mapping);
+  // Add the options for all other fields.
+  foreach ($fields as $field) {
+    $label = $field['label'];
+    $field_name = $field['field_name'];
+    $form[$field_name] = array(
+      '#type' => 'fieldset',
+      '#group' => 'rdf_mappings',
+      '#title' => t('@label', array('@label' => $label)),
+      '#attributes' => array('class' => array('rdf-field')),
+    );
+    rdfui_predicate_fieldset($form[$field_name], $mapping, $field_name, $label);
+  }
+
+  $form['field_names'] = array('#type' => 'value', '#value' => array_keys($fields));
+  $form['submit'] = array('#type' => 'submit', '#value' => t('Save mappings'));
+
+// @todo where is RDFUI_CURIE_REGEX declared?
+//  drupal_add_js(array('rdfui' => array('termRegex' => RDFUI_CURIE_REGEX)), 'setting');
+  return $form;
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function rdfui_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
+
+  $field_name = $form['#field']['field_name'];
+  $instance = $form['instance'];
+  $label = isset($instance['label']) ? $instance['label']['#default_value'] : $instance['field_name'];
+  $entity_type = $instance['entity_type']['#value'];
+  $mapping = rdf_mapping_load($entity_type, $instance['bundle']['#value']);
+
+  $form['rdf'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('@label RDF Mapping', array('@label' => $label)),
+  );
+
+  // add the predicate, datatype, etc fields
+  rdfui_predicate_fieldset($form['rdf'], $mapping, $field_name, $label);
+
+  $form['submit']['#weight'] = 1;
+
+  // add submit and validate handlers
+  $form['#validate'] = array_merge($form['#validate'], array('rdfui_form_field_ui_field_edit_form_validate'));
+  $form['#submit'] = array_merge($form['#submit'], array('rdfui_form_field_ui_field_edit_form_submit'));
+
+//  drupal_add_js(array('rdfui'=>array('termRegex'=>RDFUI_CURIE_REGEX)), 'setting');
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function rdfui_form_node_type_form_alter(&$form, &$form_state) {
+  $mapping = array();
+  // If we are editing an existing content type, the mapping will be available
+  // via the bundles in entity info.
+  if ($bundle = $form['type']['#default_value']) {
+    $entity = entity_get_info('node');
+    $mapping = $entity['bundles'][$bundle]['rdf_mapping'];
+  }
+
+  $form['rdf_settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => 'RDF Settings',
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#group' => 'additional_settings'
+  );
+  $form['rdf_settings']['rdf_rdftype'] = array(
+    '#type' => 'fieldset',
+    '#title' => 'RDF Type',
+  );
+  $form['rdf_settings']['rdf_title'] = array(
+    '#type' => 'fieldset',
+    '#title' => 'RDF Title Predicate',
+  );
+
+  // Add the RDF type field for the bundle.
+  rdfui_rdftype_fieldset($form['rdf_settings']['rdf_rdftype'], $mapping);
+  //Add the predicate, datatype, property fields for the bundle title.
+  rdfui_predicate_fieldset($form['rdf_settings']['rdf_title'], $mapping, 'title', 'title');
+
+  // add submit and validate handlers
+  $form['#validate'] = array_merge($form['#validate'], array('rdfui_form_node_type_form_validate'));
+  $form['#submit'] = array_merge($form['#submit'], array('rdfui_form_node_type_form_submit'));
+
+//  drupal_add_js(array('rdfui'=>array('termRegex'=>RDFUI_CURIE_REGEX)), 'setting');
+}
+
+
+function rdfui_form_field_ui_field_edit_form_validate($form, &$form_state) {
+  $field_name = $form['#field']['field_name'];
+
+  _rdfui_validate_terms($form_state, $field_name);
+  _rdfui_validate_datatype($form_state, $field_name);
+}
+
+function rdfui_admin_rdf_overview_form_validate($form, &$form_state) {
+  // Validate bundle's RDF type(s).
+  _rdfui_validate_terms($form_state);
+
+  // Validate title predicate(s).
+  if ((isset($form_state['input']['rdf_title_type']))) {
+    $field_name = 'title';
+    _rdfui_validate_terms($form_state, $field_name);
+    _rdfui_validate_datatype($form_state, $field_name);
+  }
+
+  // Validate predicates for all fields.
+  foreach ($form_state['values']['field_names'] as $field_name) {
+    _rdfui_validate_terms($form_state, $field_name);
+    _rdfui_validate_datatype($form_state, $field_name);
+  }
+}
+
+function rdfui_form_node_type_form_validate($form, &$form_state) {
+  // Validate bundle's RDF type(s).
+  _rdfui_validate_terms($form_state);
+
+  // Validate title predicate(s).
+  if ((isset($form_state['input']['rdf_title_type']))) {
+    $field_name = 'title';
+    _rdfui_validate_terms($form_state, $field_name);
+    _rdfui_validate_datatype($form_state, $field_name);
+  }
+}
+
+/**
+ * Saves RDF mapping for all fields and node type.
+ */
+function rdfui_admin_rdf_overview_form_submit($form, &$form_state) {
+  $entity_type = $form_state['build_info']['args'][0];
+  // @todo somehow $form_state['build_info']['args'][1] is an object for the
+  // node RDF mapping but a string 'user' for the user RDF mapping.
+  if (isset($form_state['build_info']['args'][1]->type)) {
+    $bundle = $form_state['build_info']['args'][1]->type;
+  }
+  elseif ($form_state['build_info']['args'][0] == 'taxonomy_term') {
+    $bundle = $form_state['build_info']['args'][1]->machine_name;
+  }
+  else {
+    $bundle = $form_state['build_info']['args'][1];
+  }
+  _rdfui_mapping_save($form_state, $entity_type, $bundle, 'title');
+
+  foreach ($form_state['values']['field_names'] as $field_name) {
+    _rdfui_mapping_save($form_state, $entity_type, $bundle, $field_name);
+  }
+  drupal_set_message(t('RDF mappings have been saved.'), 'status');
+}
+
+/**
+ * Saves RDF mapping for individual field.
+ */
+function rdfui_form_field_ui_field_edit_form_submit($form, &$form_state) {
+  $entity_type = $form['instance']['entity_type']['#value'];
+  $bundle = $form['instance']['bundle']['#value'];
+  $field_name = $form['#field']['field_name'];
+
+  _rdfui_mapping_save($form_state, $entity_type, $bundle, $field_name);
+}
+
+/**
+ * Saves RDF mapping for Title field.
+ */
+function rdfui_form_node_type_form_submit($form, &$form_state) {
+  $entity_type = 'node';
+  $bundle = $form_state['input']['type'];
+  // We only need to call _rdfui_mapping_save once because it checks whether
+  // rdf_type is set in the form before saving the field value.
+  _rdfui_mapping_save($form_state, $entity_type, $bundle, 'title');
+}
+
+/**
+ * Menu callback for classes autocomplete
+ */
+function rdfui_classes_autocomplete($string) {
+  // The user enters a comma-separated list of classes. We only autocomplete
+  // the last class.
+  $classes_typed = drupal_explode_tags($string);
+  $class_last = drupal_strtolower(array_pop($classes_typed));
+
+  $matches = array();
+  if ($class_last != '') {
+    $classes = array();
+    $classes_entered = count($classes_typed) ? implode(', ', $classes_typed) . ', ' : '';
+    $class_tids = rdfx_get_classes();
+    foreach ($class_tids as $class_tid) {
+      $class = rdfx_curie($class_tid) . ', ';
+      if (preg_match("/$class_last/", $class)) {
+        $details = _rdfx_get_term_details($class_tid);
+        $details->curie = $class;
+        $matches[$classes_entered . $class] = theme('rdfui_term_autocomplete', array('term' => $details,));
+      }
+    }
+  }
+  drupal_json_output($matches);
+}
+
+/**
+ * Menu callback for datatype autocomplete
+ */
+function rdfui_datatype_autocomplete($string) {
+
+  //@todo Make sure datatype is only active if property is the relationship.
+
+  $datatypes = 'xsd:string, xsd:boolean, xsd:decimal, xsd:float, xsd:double, xsd:dateTime, xsd:time, xsd:date, xsd:gYearMonth, xsd:gYear, xsd:gMonthDay, xsd:gDay, xsd:gMonth, xsd:hexBinary, xsd:base64Binary, xsd:anyURI, xsd:normalizedString, xsd:token, xsd:language, xsd:NMTOKEN, xsd:Name, xsd:NCName, xsd:integer, xsd:nonPositiveInteger, xsd:negativeInteger, xsd:long, xsd:int, xsd:short, xsd:byte, xsd:nonNegativeInteger, xsd:unsignedLong, xsd:unsignedInt, xsd:unsignedShort, xsd:unsignedByte, xsd:positiveInteger';
+
+  $datatypes = explode(', ', $datatypes);
+  $matches = array();
+
+  foreach($datatypes as $datatype) {
+    if (preg_match("/^$string/", $datatype))
+      $matches[$datatype] = $datatype;
+  }
+
+  drupal_json_output($matches);
+}
+
+/**
+ * Menu callback for predicates autocomplete
+ */
+function rdfui_predicates_autocomplete($string) {
+  // The user enters a comma-separated list of predicates. We only autocomplete
+  // the last predicate.
+  $predicates_typed = drupal_explode_tags($string);
+  $predicate_last = drupal_strtolower(array_pop($predicates_typed));
+
+  $matches = array();
+  if ($predicate_last != '') {
+    $predicates = array();
+    $predicates_entered = count($predicates_typed) ? implode(', ', $predicates_typed) . ', ' : '';
+    $predicate_tids = rdfx_get_properties();
+    foreach ($predicate_tids as $predicate_tid) {
+      $predicate = rdfx_curie($predicate_tid) . ', ';
+      if (preg_match("/$predicate_last/", $predicate)) {
+        $details = _rdfx_get_term_details($predicate_tid);
+        $details->curie = $predicate;
+        $matches[$predicates_entered . $predicate] = theme('rdfui_term_autocomplete', array('term' => $details,));
+      }
+    }
+  }
+  drupal_json_output($matches);
+}
+
+
+/**
+ * appends the rdf form fields to a fieldset dedicated to a fields.module field
+ */
+function rdfui_predicate_fieldset(&$fieldset, $mapping, $field_name, $label) {
+  $fieldset['rdf_'. $field_name .'_predicates'] = array(
+    '#type' => 'textfield',
+    '#autocomplete_path' => 'rdfui/predicates/autocomplete',
+    '#title' => t('RDF Predicates'),
+    '#default_value' => empty($mapping[$field_name]['predicates']) ? '' : implode(", ",$mapping[$field_name]['predicates']),
+    '#description' => t('Enter a comma-separated list of predicates for %label using CURIE syntax. For example: %predicates',
+      array(
+        '%label' => $label,
+        '%predicates' => 'foaf:familyName, foaf:lastName'
+      )
+    ),
+    '#resizable' => FALSE,
+  );
+
+  $fieldset['rdf_'. $field_name .'_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Attribute Type'),
+    '#default_value' => empty($mapping[$field_name]['type']) ? 'property' : $mapping[$field_name]['type'],
+    '#description' => t('For fields containing literals—things such as plain text, html, numbers—use the !property attribute. For fields containing references to other things—urls and node references, for example—use the !rel or !rev attribute.',
+      array(
+        '%label' => $label,
+        '!property' => l('property', 'http://www.w3.org/2006/07/SWD/RDFa/syntax/#id103203'),
+        '!rel' => l('rel','http://www.w3.org/2006/07/SWD/RDFa/syntax/#id103235'),
+        '!rev' => l('rev','http://www.w3.org/2006/07/SWD/RDFa/syntax/#id103282')
+      )
+    ),
+    '#options' => array('property'=>'property', 'rel'=>'rel', 'rev'=>'rev'),
+    '#attributes' => array('class' => array('rdf-attribute-type')),
+  );
+
+  // @todo Possibly autocomplete the builtin xsd datatypes, but do not restrict to xsd datatypes.
+  $fieldset['rdf_'. $field_name .'_datatype'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Datatype'),
+    '#autocomplete_path' => 'rdfui/datatype/autocomplete',
+    '#default_value' => empty($mapping[$field_name]['datatype']) ? '' : $mapping[$field_name]['datatype'],
+    '#description' => t('Enter the datatype for %label using CURIE syntax. For a list of common datatypes, see !link.',
+      array(
+        '%label' => $label,
+        '!link' => l('XML Schema datatypes', 'http://www.w3.org/TR/2004/REC-rdf-mt-20040210/#dtype_interp', array('attributes' => array('target' => '_blank'))),
+      )
+    ),
+    '#states' => array(
+      'visible' => array(
+        ':input[name="rdf_' . $field_name . '_type"]' => array('value' => 'property'),
+      ),
+    ),
+  );
+  drupal_add_css(drupal_get_path('module', 'rdfui') .'/css/rdfui.css', 'file');
+}
+
+/**
+ * Appends the RDF type fieldset. Because this fieldset is always on the same
+ * page as fields created by rdfui_predicate_fieldset(), which add the css and
+ * js files, we do not add the files again.
+ *
+ */
+function rdfui_rdftype_fieldset(&$fieldset, $mapping) {
+  $fieldset = array(
+    '#type' => 'textfield',
+    '#autocomplete_path' => 'rdfui/classes/autocomplete',
+    '#title' => t('RDF Type'),
+    '#default_value' => empty($mapping['rdftype']) ? '' : implode(", ",$mapping['rdftype']),
+    '#description' => t('Enter a comma-separated list of classes for this bundle using CURIE syntax. For example: %classes', array('%classes' => 'sioc:Item, foaf:Document')),
+  );
+}
+
+/**
+ * Sets a form error if predicates don't validate.
+ */
+function _rdfui_validate_terms($form_state, $field_name = '') {
+  // If the field_name is NOT NULL, then this is a predicate. If it is NULL,
+  // this is a type.
+  $field_id = $field_name != NULL ? 'rdf_'. $field_name .'_predicates' : 'rdf_rdftype';
+
+  // Validate terms.
+  if ($terms = trim($form_state['values'][$field_id])) {
+    $terms = rdfui_extract_curies($terms);
+    $rdf_namespaces = module_invoke_all('rdf_namespaces');
+    $errors = array();
+    $warnings = array();
+
+    foreach($terms as $term) {
+      // Ensure this is a CURIE.
+      if (!preg_match(QNAME, $term)){
+        // @todo Add a page to the drupal docs about CURIE format and adding
+        // namespaces. Then add a link to this error that says 'For more info'.
+        $errors[] = t('Term %term must be in CURIE format.', array('%term'=>$term));
+      }
+      else {
+        // Check the prefixes to ensure they are bound. If not, issue a warning.
+        $term_parts = explode(':', $term);
+        $prefix = $term_parts[0];
+        if (!isset($rdf_namespaces[$prefix])) {
+          $warnings[] = t('Term %term uses unmapped prefix %prefix. Please map the prefix in !rdf_publishing.',
+            array(
+              '%term' => $term,
+              '%prefix' => $prefix,
+              '!rdf_publishing' => l(t('RDF publishing settings'), 'admin/config/services/rdf/namespaces'),
+            )
+          );
+        }
+      }
+    }
+
+    if (!empty($errors)) {
+      foreach ($errors as $error) {
+        form_set_error($field_id, $error);
+      }
+    }
+    if (!empty($warnings)) {
+      foreach ($warnings as $warning) {
+        drupal_set_message($warning, $type='warning');
+      }
+    }
+  }
+}
+
+/**
+ * Sets a form error if datatype don't validate.
+ */
+function _rdfui_validate_datatype($form_state, $field_name) {
+
+  // validate datatype
+  if ($datatype = trim($form_state['values']['rdf_'. $field_name .'_datatype'])) {
+    if(!preg_match(QNAME, $datatype))
+      form_set_error('rdf_'. $field_name .'_datatype', t('Datatype %datatype is an invalid format.', array('%datatype'=>$datatype)));
+  }
+
+}
+
+/**
+ * Saves the mapping
+ */
+
+function _rdfui_mapping_save($form_state, $entity_type, $bundle, $field_name) {
+  $mapping = rdf_mapping_load($entity_type, $bundle);
+  // Set the RDF type if it is in this form.
+  if (!empty($form_state['values']['rdf_rdftype'])) {
+    $mapping['rdftype'] = rdfui_extract_curies($form_state['values']['rdf_rdftype']);
+  }
+  // Turn the predicates string into an array.
+  if (isset($form_state['input']['rdf_title_type']) || $field_name != 'title') {
+    $form_state['values']['rdf_'. $field_name .'_predicates'] = rdfui_extract_curies($form_state['values']['rdf_'. $field_name .'_predicates']);
+  }
+  
+  foreach (array('type', 'datatype', 'predicates') as $key) {
+    // If there is form input for this key, set it in the mapping.
+    if (!empty($form_state['values']['rdf_'. $field_name .'_' . $key])) {
+      $mapping[$field_name][$key] = $form_state['values']['rdf_'. $field_name .'_' . $key];
+    }
+    // If there is no form input for this key, we need to remove it from the
+    // mapping.
+    else {
+      // If there are no predicates, there should be no mapping at all for the
+      // field.
+      if ($key == 'predicates') {
+        unset($mapping[$field_name]);
+      }
+      else {
+        unset($mapping[$field_name][$key]);
+      }
+    }
+  }
+
+  $mapping_info = array(
+    'mapping' => $mapping,
+    'type' => $entity_type,
+    'bundle' => $bundle
+  );
+  rdf_mapping_save($mapping_info);
+}
+
+/**
+ * Returns HTML for a term.
+ *
+ * @param $term
+ *   An associative array containing:
+ *   - term: A render element representing the term.
+ *      - curie: The term's compact URI.
+ *      - label: The term's human readable label.
+ *      - comment: A description of the term.
+ *
+ * @ingroup themeable
+ */
+function theme_rdfui_term_autocomplete($variables) {
+  $term = $variables['term'];
+
+  $output = '<div class="form-item rdf-term-autocomplete">';
+  $output .= $term->curie . ' ';
+  $output .= '<p class="rdf-comment-autocomplete">' . $term->comment . '</p>';
+  $output .= '</div>';
+
+  return $output;
+}
+
+/**
+ * Generates an array of CURIE values from a string.
+ *
+ * Explodes a string with CURIES separated with ,  and with each a
+ * value on its own line.
+ */
+function rdfui_extract_curies($string_values) {
+  $list = explode(", ", $string_values);
+  $last = array_pop($list);
+  $last = str_replace(',', '', $last);
+  array_push($list, $last);
+  $list = array_map('trim', $list);
+  $list = array_filter($list, 'strlen');
+  $list = array_unique($list);
+  return $list;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfui/rdfui.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * Test RDF Mapping UI.
+ */
+class RdfUiTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'RDF UI',
+      'description' => 'Test the UI for mappings.',
+      'group' => 'RDFx',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rdfui');
+
+    $web_user = $this->drupalCreateUser(array('create article content', 'create page content', 'administer rdf', 'administer content types',));
+    $this->drupalLogin($web_user);
+  }
+
+  function testPrefixNotification() {
+    $edit = array();
+    $field_settings_form = 'admin/structure/types/manage/page/fields/body';
+
+    $edit['rdf_body_predicates'] = 'foo:bar';
+    $this->drupalPost($field_settings_form, $edit, t('Save settings'));
+    $this->assertText(t('Term foo:bar uses unmapped prefix foo.'), t('Warning displayed for unbound prefix.'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,248 @@
+<?php
+
+/**
+ * Callback function for viewing all bundles' RDF mappings.
+ */
+function rdfx_mapping_overview() {
+  $render = array();
+  $entities = entity_get_info();
+  $fields = field_info_instances();
+  $render['tabs'] = array(
+    '#type' => 'vertical_tabs',
+  );
+
+  // Create a tab for each entity.
+  foreach ($entities as $entity_type => $entity) {
+    $render['tabs'][$entity_type] = array(
+      '#type' => 'fieldset',
+      '#title' => $entity['label'],
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    // The bundle's RDF mapping array may contain mappings for entity attributes
+    // that are not fields. The bundle's field array may contain fields that are
+    // not in the RDF mapping array. In order to ensure we get all the available
+    // fields and all the mapped entity attributes, we compare the arrays.
+    foreach ($entity['bundles'] as $bundle_name => $bundle) {
+      $rows = array();
+      $real_fields = array();
+      $fake_fields = array();
+      $bundle_fields = $fields[$entity_type][$bundle_name];
+      $bundle['edit_path'] = NULL;
+      $rdf_mapping = $bundle['rdf_mapping'];
+      if (isset($bundle['admin']['real path'])) {
+        $bundle['edit_path'] = $bundle['admin']['real path'] . '/rdf';
+      }
+
+      // Set RDF type.
+      if (isset($rdf_mapping['rdftype'])) {
+        $rdftype = implode(', ', $rdf_mapping['rdftype']);
+        unset($rdf_mapping['rdftype']);
+      }
+      foreach ($rdf_mapping as $field_name => $mapping_info) {
+        // Gather Field API fields.
+        if (isset($bundle_fields[$field_name])) {
+          $real_fields[$field_name]['rdf_mapping'] = $mapping_info;
+          $real_fields[$field_name]['label'] = $fields[$entity_type][$bundle_name][$field_name]['label'];
+          $real_fields[$field_name]['edit_path'] = $bundle['edit_path'];
+          unset($bundle_fields[$field_name]);
+        }
+        // Gather non-field content variables.
+        else {
+          $fake_fields[$field_name]['rdf_mapping'] = $mapping_info;
+          $fake_fields[$field_name]['label'] = $field_name;
+          $fake_fields[$field_name]['edit_path'] = ($field_name == 'title') ? $bundle['edit_path'] : NULL;
+        }
+      }
+      // Theme this bundle's table and add it to it's parent entity's tab.
+      $variables = array(
+        'bundle' => $bundle,
+        'rdftype' => $rdftype,
+        'real_fields' => $real_fields,
+        'fake_fields' => $fake_fields,
+      );
+      $render['tabs'][$entity_type][$bundle_name] = theme('rdfx_mapping_admin_overview', $variables);
+    }
+  }
+  return $render;
+}
+
+/**
+ * Theme function to output the table for a bundle's mappings.
+ */
+function theme_rdfx_mapping_admin_overview($variables) {
+  $bundle_label = $variables['bundle']['label'];
+  $bundle = $variables['bundle'];
+  $real_fields = $variables['real_fields'];
+  $fake_fields = $variables['fake_fields'];
+  $rows = array();
+
+  // Add the table header for this bundle.
+  $header = array(t('Fields'), t('RDF predicates'), t('Mapping type'), t('Datatype'));
+  if (module_exists('rdfui')) {
+    $header[] = t('Operations');
+  }
+
+  // Display a title for each bundle above the mappings table. If RDF UI is
+  // enabled, also add an 'edit' link.
+  $title = "<h3>$bundle_label</h3>";
+  $edit_link = (module_exists('rdfui') && !empty($bundle['edit_path'])) ? ' (' . l(t('edit'), $bundle['edit_path']) . ')' : '';
+  $title .= "<p>" . t('RDF Types:') . ' ' . $variables['rdftype'] . $edit_link . '</p>';
+
+  // List all of the Field API fields and their mappings.
+  foreach ($real_fields as $name => $field) {
+    $rows[] = array(
+      'data' => theme('rdfx_mapping_admin_overview_row', array('field' => $field, 'field_name' => $name, 'edit_path' => $field['edit_path'])),
+    );
+  }
+
+  // Add any non-Field API entity attributes.
+  foreach ($fake_fields as $name => $field) {
+    $rows[] = array(
+      'data' => theme('rdfx_mapping_admin_overview_row', array('field' => $field, 'field_name' => $name, 'edit_path' => $field['edit_path'])),
+    );
+  }
+
+  // If there are no mappings, display a message inside the table.
+  if (!count($rows)) {
+    $rows[] = array(
+      'data' => array(array('data' => t('No mappings have been configured for this bundle.'), 'colspan' => 5))
+    );
+  }
+
+  // Return the table for this bundle.
+  return array(
+    '#prefix' => $title,
+    '#theme' => 'table',
+    '#rows' => $rows,
+    '#header' => $header,
+  );
+}
+
+/**
+ * Theme function to output a field's row in the bundle mapping table.
+ */
+function theme_rdfx_mapping_admin_overview_row($variables) {
+  $field = $variables['field'];
+
+  $field_label = '<strong>' . t($field['label']) . '</strong>';
+  $predicates = isset($field['rdf_mapping']['predicates']) ? t(implode(', ', $field['rdf_mapping']['predicates'])) : '';
+  $predicate_type = isset($field['rdf_mapping']['type']) ? check_plain($field['rdf_mapping']['type']) : 'property';
+  $datatype = isset($field['rdf_mapping']['datatype']) ? $field['rdf_mapping']['datatype'] : '';
+
+  $row = array($field_label, $predicates, $predicate_type, $datatype);
+
+  // Add operations links only if RDF UI is enabled.
+  if (module_exists('rdfui')) {
+    $operations = '';
+    if (isset($variables['edit_path'])) {
+      // By adding the appropriate url fragment, we can open the corresponding
+      // vertical tab on the RDF mapping UI page. The fragment should correspond
+      // to the html id for each fieldset, which means certain characters need
+      // to be replaced. These replacement patterns are from drupal_html_id().
+      $id = ($variables['field_name'] == 'title') ? 'rdf-title' : $variables['field_name'];
+      $id = strtr(drupal_strtolower($id), array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
+      $id = preg_replace('/[^A-Za-z0-9\-_]/', '', $id);
+      $id = preg_replace('/\-+/', '-', $id);
+      $operations = l(t('edit'), $variables['edit_path'], array('fragment' => "edit-$id"));
+    }
+    $row[] = $operations;
+  }
+
+  return $row;
+}
+
+/**
+ * Menu callback for viewing all declared namespaces (conflicting and non-conflicting)
+ * and their prefixes.
+ */
+function rdfx_admin_namespaces() {
+  $output = '';
+
+  // List conflicting namespaces.
+  $conflicting_namespaces = rdfx_get_conflicting_namespaces();
+  if ($conflicting_namespaces) {
+    $table_conflicting_namespaces = array();
+    $table_conflicting_namespaces['header'] = array('Prefix', 'Conflicting Namespaces');
+    foreach ($conflicting_namespaces as $prefix => $uris) {
+      $table_conflicting_namespaces['rows'][] = array($prefix, implode(", ", $uris));
+    }
+    $output .= '<div class="messages warning">' . t("Warning: The following namespaces have conflicts") . '</div>';
+    $output .= theme('table', $table_conflicting_namespaces);
+  }
+
+  // List non-conflicting namespaces.
+  $table_namespaces = array();
+  $table_namespaces['header'] = array('Prefix', 'Namespace');
+  foreach (rdf_get_namespaces() as $prefix => $namespace) {
+    $table_namespaces['rows'][] = array($prefix, $namespace);
+  }
+  // Only show label if there were conflicting namespaces.
+  if ($conflicting_namespaces) {
+    $output .= '<div class="messages status">' . t("The following namespaces do not have conflicts") . '</div>';
+  }
+  $output .= theme('table', $table_namespaces);
+
+  // Form to add namespaces.
+  $form = drupal_get_form('rdfx_admin_namespaces_form');
+  $output .= drupal_render($form);
+
+  return $output;
+}
+
+function rdfx_admin_namespaces_form($form, &$form_state) {
+  $form['prefix'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Prefix'),
+    '#required' => TRUE,
+    '#description' => t('Choose a prefix for this namespace, e.g. dc, foaf, sioc. This prefix will be used as an abbreviation for the namespace URI.'),
+  );
+  $form['ns_uri'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Namespace URI'),
+    '#required' => TRUE,
+    '#default_value' => isset($form_state['values']['ns_uri']) ? $form_state['values']['ns_uri'] : NULL,
+    '#description' => t("Enter the URI of the namespace. Make sure it ends with either / or #."),
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  return $form;
+}
+
+function rdfx_admin_namespaces_form_validate($form, &$form_state) {
+  // Loads the XML Namespace regular expression patterns.
+  module_load_include('inc', 'rdfx');
+
+  $prefix = $form_state['values']['prefix'];
+  $ns_uri = $form_state['values']['ns_uri'];
+
+  // Ensures that the namespace is a valid URI.
+  if (!valid_url($ns_uri, $absolute = TRUE)) {
+    form_set_error('ns_uri', t('The namespace URI must be a valid URI.'));
+  }
+  // Ensures the namespace URI ends in either / or #.
+  if (!preg_match('/(\/|\#)$/', $ns_uri)) {
+    form_set_error('ns_uri', t('The namespace URI must end in either a / or a #.'));
+  }
+  // Ensures the prefix is well formed according to the specification.
+  if (!preg_match('/^' . PREFIX .'$/', $prefix)) {
+    form_set_error('prefix', t('The prefix must follow the !link.', array('!link' => '<a href="http://www.w3.org/TR/xml-names11/#NT-NCName">XML Namespace Specification</a>')));
+  }
+}
+
+function rdfx_admin_namespaces_form_submit($form, &$form_state) {
+  $prefix = $form_state['values']['prefix'];
+  $ns_uri = $form_state['values']['ns_uri'];
+  // Prepares a fake empty vocabulary for _rdfx_save_vocabulary() to save the
+  // namespace and prefix.
+  // @todo use API when http://drupal.org/node/1117646 is fixed.
+  $vocabulary = array(
+    'title' => array(),
+    'description' => array(),
+    'namespaces' => array(),
+  );
+  _rdfx_save_vocabulary($ns_uri, $prefix, $vocabulary);
+  drupal_set_message(t('The namespace @namespace has been saved with the prefix @prefix.', array('@namespace' => $ns_uri, '@prefix' => $prefix)));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,9 @@
+<?php
+// $Id: votingapi.api.php,v 1.1.2.1.2.1 2009/07/01 07:26:12 eaton Exp $
+
+/**
+ * @file
+ * Provides hook documentation for the RDFx module.
+ */
+
+function hook_rdfx_term_types_alter()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Implementation of hook_features_export().
+ *
+ * Defines one or more component types that are available to Features for export
+ * and a variety of settings for each type.
+ */
+function rdf_mappings_features_export($data, &$export, $module_name = '') {
+  // Any feature exporting RDF mappings need the rdf and rdfx modules.
+  $export['dependencies']['rdf'] = 'rdf';
+  $export['dependencies']['rdfx'] = 'rdfx';
+
+  foreach ($data as $key => $value) {
+    $parts = explode('-', $key);
+    $entity_type = $parts[0];
+    $bundle_name = $parts[1];
+
+    if ($rdf_mapping = rdf_mapping_load($entity_type, $bundle_name)) {
+      $export['features']['rdf_mappings'][$entity_type . '-' . $bundle_name] = $rdf_mapping;
+    }
+  }
+
+  return array();
+}
+
+/**
+ * Implementation of hook_features_export_options().
+ *
+ * Provides an array of components that can be exported for a given type.
+ */
+function rdf_mappings_features_export_options() {
+  $bundles = array();
+
+  foreach (entity_get_info() as $entity_type => $entity) {
+    foreach ($entity['bundles'] as $bundle_name => $bundle) {
+      $bundles[$entity_type . '-' . $bundle_name] = $entity['label'] . ': ' . $bundle['label'];
+    }
+  }
+
+  return $bundles;
+}
+
+/**
+ * Implementation of hook_features_export_render().
+ *
+ * Renders a set of components to code as a defaults hook.
+ */
+function rdf_mappings_features_export_render($module, $data, $export = NULL) {
+  $code = array();
+  $code[] = '  $rdf_mappings = array();';
+  $code[] = '';
+
+  foreach ($data as $key => $entity_type_bundle) {
+    if (is_array($entity_type_bundle)) {
+      $entity_type_bundle = $key;
+    }
+    $parts = explode('-', $entity_type_bundle);
+    $entity_type = $parts[0];
+    $bundle_name = $parts[1];
+    if ($rdf_mapping = rdf_mapping_load($entity_type, $bundle_name)) {
+      $rdf_mapping_export = features_var_export($rdf_mapping, '  ');
+      $rdf_bundle = features_var_export($bundle_name);
+      $rdf_entity_type = features_var_export($entity_type);
+      $code[] = "  // Exported RDF mapping: {$bundle_name}";
+      $code[] = "  \$rdf_mappings[$rdf_entity_type][$rdf_bundle] = $rdf_mapping_export;";
+      $code[] = "";
+    }
+  }
+
+  $code[] = '  return $rdf_mappings;';
+  $code = implode("\n", $code);
+  return array('rdf_default_mappings' => $code);
+}
+
+/**
+ * Implementation of hook_features_revert().
+ *
+ * Reverts components of a feature back to their default state.
+ */
+function rdf_mappings_features_revert($module) {
+  return rdf_mappings_features_rebuild($module);
+}
+
+/**
+ * Implementation of hook_features_rebuild().
+ *
+ * Updates faux-exportable components back to their default state.
+ */
+function rdf_mappings_features_rebuild($module) {
+  if ($defaults = features_get_default('rdf_mappings', $module)) {
+    foreach ($defaults as $entity_type => $bundles) {
+      foreach ($bundles as $bundle => $mapping) {
+        rdf_mapping_save(array(
+          'type' => $entity_type,
+          'bundle' => $bundle,
+          'mapping' => $mapping,
+        ));
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.import.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * @file
+ * Functions for importing and parsing RDF data.
+ */
+
+/**
+ * Loads an RDF file from an HTTP URI or local file, parses it, and builds an
+ * RDF schema representation (associative array) from it.
+ *
+ * @param $uri
+ *    The namespace URI for this graph.
+ * @param $prefix
+ *    The prefix for this graph.
+ * @param $filename (optional)
+ *    A local RDF file to parse.
+ * @return array
+ * @throws Exception On network or parse error
+ */
+function rdfx_fetch_rdf($uri, $prefix, $filename = NULL) {
+  if ($filename != NULL) {
+    if (!is_file($filename)) {
+      throw new Exception("File not found: '$filename'");
+      return;
+    }
+    $content = file_get_contents($filename);
+    return _rdfx_parse_rdf($uri, $content);
+  }
+
+  $schema_url = $uri;
+  $i = strpos($schema_url, '#');
+  if ($i !== false) {
+    $schema_url = substr($schema_url, 0, $i);
+  }
+  return _rdfx_parse_rdf($uri);
+}
+
+function _rdfx_parse_rdf($base_uri) {
+  $namespaces = array();
+
+  $parser = ARC2::getRDFParser();
+  $parser->parse($base_uri);
+  // If this is an N3 file, the namespaces array isn't populated. Iterate
+  // through the attached parser object's prefixes and remove the colon from
+  // the end of the prefix.
+  // @todo File an issue with ARC2.
+
+  switch ($parser->format) {
+    case 'turtle':
+      foreach ($parser->parser->prefixes as $prefix => $uri) {
+        $formatted_prefix = str_replace(':', '', $prefix);
+        $namespaces[$formatted_prefix] = $uri;
+      }
+      break;
+    default:
+      foreach ($parser->parser->nsp as $uri => $prefix) {
+        $namespaces[$prefix] = $uri;
+      }
+      break;
+  }
+  return array($parser->getTriples(), $namespaces);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,46 @@
+<?php
+/*
+ * This file contains regular expressions for the following XML tokens:
+ * BaseChar, Ideographic, Letter, Digit, Extender, CombiningChar, NameChar,
+ * EntityRef, CharRef, Reference, Name, NmToken, and AttValue.
+ *
+ * The definitions of these tokens were taken from the XML spec
+ * (Extensible Markup Language 1.0) at L<http://www.w3.org/TR/REC-xml>.
+
+ * Also contains the regular expressions for the following tokens from the
+ * XML Namespaces spec at L<http://www.w3.org/TR/REC-xml-names>:
+ * NCNameChar, NCName, QName, Prefix and LocalPart.
+ *
+ * Modified from the XML:RegExp package, authored by Enno Derksen and
+ * maintained by T.J. Mather.
+ * http://search.cpan.org/~tjmather/XML-RegExp-0.03/lib/XML/RegExp.pm
+ */
+  define('BASE_CHAR', '(?:[a-zA-Z]|\xC3[\x80-\x96\x98-\xB6\xB8-\xBF]|\xC4[\x80-\xB1\xB4-\xBE]|\xC5[\x81-\x88\x8A-\xBE]|\xC6[\x80-\xBF]|\xC7[\x80-\x83\x8D-\xB0\xB4\xB5\xBA-\xBF]|\xC8[\x80-\x97]|\xC9[\x90-\xBF]|\xCA[\x80-\xA8\xBB-\xBF]|\xCB[\x80\x81]|\xCE[\x86\x88-\x8A\x8C\x8E-\xA1\xA3-\xBF]|\xCF[\x80-\x8E\x90-\x96\x9A\x9C\x9E\xA0\xA2-\xB3]|\xD0[\x81-\x8C\x8E-\xBF]|\xD1[\x80-\x8F\x91-\x9C\x9E-\xBF]|\xD2[\x80\x81\x90-\xBF]|\xD3[\x80-\x84\x87\x88\x8B\x8C\x90-\xAB\xAE-\xB5\xB8\xB9]|\xD4[\xB1-\xBF]|\xD5[\x80-\x96\x99\xA1-\xBF]|\xD6[\x80-\x86]|\xD7[\x90-\xAA\xB0-\xB2]|\xD8[\xA1-\xBA]|\xD9[\x81-\x8A\xB1-\xBF]|\xDA[\x80-\xB7\xBA-\xBE]|\xDB[\x80-\x8E\x90-\x93\x95\xA5\xA6]|\xE0(?:\xA4[\x85-\xB9\xBD]|\xA5[\x98-\xA1]|\xA6[\x85-\x8C\x8F\x90\x93-\xA8\xAA-\xB0\xB2\xB6-\xB9]|\xA7[\x9C\x9D\x9F-\xA1\xB0\xB1]|\xA8[\x85-\x8A\x8F\x90\x93-\xA8\xAA-\xB0\xB2\xB3\xB5\xB6\xB8\xB9]|\xA9[\x99-\x9C\x9E\xB2-\xB4]|\xAA[\x85-\x8B\x8D\x8F-\x91\x93-\xA8\xAA-\xB0\xB2\xB3\xB5-\xB9\xBD]|\xAB\xA0|\xAC[\x85-\x8C\x8F\x90\x93-\xA8\xAA-\xB0\xB2\xB3\xB6-\xB9\xBD]|\xAD[\x9C\x9D\x9F-\xA1]|\xAE[\x85-\x8A\x8E-\x90\x92-\x95\x99\x9A\x9C\x9E\x9F\xA3\xA4\xA8-\xAA\xAE-\xB5\xB7-\xB9]|\xB0[\x85-\x8C\x8E-\x90\x92-\xA8\xAA-\xB3\xB5-\xB9]|\xB1[\xA0\xA1]|\xB2[\x85-\x8C\x8E-\x90\x92-\xA8\xAA-\xB3\xB5-\xB9]|\xB3[\x9E\xA0\xA1]|\xB4[\x85-\x8C\x8E-\x90\x92-\xA8\xAA-\xB9]|\xB5[\xA0\xA1]|\xB8[\x81-\xAE\xB0\xB2\xB3]|\xB9[\x80-\x85]|\xBA[\x81\x82\x84\x87\x88\x8A\x8D\x94-\x97\x99-\x9F\xA1-\xA3\xA5\xA7\xAA\xAB\xAD\xAE\xB0\xB2\xB3\xBD]|\xBB[\x80-\x84]|\xBD[\x80-\x87\x89-\xA9])|\xE1(?:\x82[\xA0-\xBF]|\x83[\x80-\x85\x90-\xB6]|\x84[\x80\x82\x83\x85-\x87\x89\x8B\x8C\x8E-\x92\xBC\xBE]|\x85[\x80\x8C\x8E\x90\x94\x95\x99\x9F-\xA1\xA3\xA5\xA7\xA9\xAD\xAE\xB2\xB3\xB5]|\x86[\x9E\xA8\xAB\xAE\xAF\xB7\xB8\xBA\xBC-\xBF]|\x87[\x80-\x82\xAB\xB0\xB9]|[\xB8\xB9][\x80-\xBF]|\xBA[\x80-\x9B\xA0-\xBF]|\xBB[\x80-\xB9]|\xBC[\x80-\x95\x98-\x9D\xA0-\xBF]|\xBD[\x80-\x85\x88-\x8D\x90-\x97\x99\x9B\x9D\x9F-\xBD]|\xBE[\x80-\xB4\xB6-\xBC\xBE]|\xBF[\x82-\x84\x86-\x8C\x90-\x93\x96-\x9B\xA0-\xAC\xB2-\xB4\xB6-\xBC])|\xE2(?:\x84[\xA6\xAA\xAB\xAE]|\x86[\x80-\x82])|\xE3(?:\x81[\x81-\xBF]|\x82[\x80-\x94\xA1-\xBF]|\x83[\x80-\xBA]|\x84[\x85-\xAC])|\xEA(?:[\xB0-\xBF][\x80-\xBF])|\xEB(?:[\x80-\xBF][\x80-\xBF])|\xEC(?:[\x80-\xBF][\x80-\xBF])|\xED(?:[\x80-\x9D][\x80-\xBF]|\x9E[\x80-\xA3])))');
+  define('IDEOGRAPHIC', '(?:\xE3\x80[\x87\xA1-\xA9]|\xE4(?:[\xB8-\xBF][\x80-\xBF])|\xE5(?:[\x80-\xBF][\x80-\xBF])|\xE6(?:[\x80-\xBF][\x80-\xBF])|\xE7(?:[\x80-\xBF][\x80-\xBF])|\xE8(?:[\x80-\xBF][\x80-\xBF])|\xE9(?:[\x80-\xBD][\x80-\xBF]|\xBE[\x80-\xA5])');
+  define('DIGIT', '(?:[0-9]|\xD9[\xA0-\xA9]|\xDB[\xB0-\xB9]|\xE0(?:\xA5[\xA6-\xAF]|\xA7[\xA6-\xAF]|\xA9[\xA6-\xAF]|\xAB[\xA6-\xAF]|\xAD[\xA6-\xAF]|\xAF[\xA7-\xAF]|\xB1[\xA6-\xAF]|\xB3[\xA6-\xAF]|\xB5[\xA6-\xAF]|\xB9[\x90-\x99]|\xBB[\x90-\x99]|\xBC[\xA0-\xA9]))');
+  define('EXTENDER', '(?:\xC2\xB7|\xCB[\x90\x91]|\xCE\x87|\xD9\x80|\xE0(?:\xB9\x86|\xBB\x86)|\xE3(?:\x80[\x85\xB1-\xB5]|\x82[\x9D\x9E]|\x83[\xBC-\xBE]))');
+  define('COMBINING_CHAR', '(?:\xCC[\x80-\xBF]|\xCD[\x80-\x85\xA0\xA1]|\xD2[\x83-\x86]|\xD6[\x91-\xA1\xA3-\xB9\xBB-\xBD\xBF]|\xD7[\x81\x82\x84]|\xD9[\x8B-\x92\xB0]|\xDB[\x96-\xA4\xA7\xA8\xAA-\xAD]|\xE0(?:\xA4[\x81-\x83\xBC\xBE\xBF]|\xA5[\x80-\x8D\x91-\x94\xA2\xA3]|\xA6[\x81-\x83\xBC\xBE\xBF]|\xA7[\x80-\x84\x87\x88\x8B-\x8D\x97\xA2\xA3]|\xA8[\x82\xBC\xBE\xBF]|\xA9[\x80-\x82\x87\x88\x8B-\x8D\xB0\xB1]|\xAA[\x81-\x83\xBC\xBE\xBF]|\xAB[\x80-\x85\x87-\x89\x8B-\x8D]|\xAC[\x81-\x83\xBC\xBE\xBF]|\xAD[\x80-\x83\x87\x88\x8B-\x8D\x96\x97]|\xAE[\x82\x83\xBE\xBF]|\xAF[\x80-\x82\x86-\x88\x8A-\x8D\x97]|\xB0[\x81-\x83\xBE\xBF]|\xB1[\x80-\x84\x86-\x88\x8A-\x8D\x95\x96]|\xB2[\x82\x83\xBE\xBF]|\xB3[\x80-\x84\x86-\x88\x8A-\x8D\x95\x96]|\xB4[\x82\x83\xBE\xBF]|\xB5[\x80-\x83\x86-\x88\x8A-\x8D\x97]|\xB8[\xB1\xB4-\xBA]|\xB9[\x87-\x8E]|\xBA[\xB1\xB4-\xB9\xBB\xBC]|\xBB[\x88-\x8D]|\xBC[\x98\x99\xB5\xB7\xB9\xBE\xBF]|\xBD[\xB1-\xBF]|\xBE[\x80-\x84\x86-\x8B\x90-\x95\x97\x99-\xAD\xB1-\xB7\xB9])|\xE2\x83[\x90-\x9C\xA1]|\xE3(?:\x80[\xAA-\xAF]|\x82[\x99\x9A]))');
+
+  define('LETTER', '(?:' . BASE_CHAR . '|' . IDEOGRAPHIC . ')');
+  define('NAME_CHAR', '(?:[-._:]|' . LETTER . '|' . DIGIT . '|' . COMBINING_CHAR . '|' . EXTENDER . ')');
+
+  define('NAME', '(?:(?:[:_]|' . LETTER . ')' . NAME_CHAR . '*)');
+  define('NM_TOKEN', '(?:' . NAME_CHAR . '+)');
+  define('ENTITY_REF', '(?:\&' . NAME . ';)');
+  define('CHAR_REF', '(?:\&#(?:[0-9]+|x[0-9a-fA-F]+)');
+  define('REFERENCE', '(?:' . ENTITY_REF . '|' . CHAR_REF . ')');
+
+  // Comment from original code: What if it contains entity references?
+  define('ATT_VALUE', "(?:\"(?:[^\"&<]*|" . REFERENCE . ")\"|'(?:[^\'&<]|" . REFERENCE .")*')");
+
+  // Prefix definitions from the XML Namespace specification.
+  define('NC_NAME_CHAR', '(?:[-._]|' . LETTER . '|' . DIGIT . '|' . COMBINING_CHAR . '|' . EXTENDER . ')');
+  define('NC_NAME', '(?:(?:_|' . LETTER . ')' . NC_NAME_CHAR .'*)');
+
+  define('PREFIX', NC_NAME);
+  define('LOCAL_PART', NC_NAME);
+  define('QNAME', '/(?:(?:' . PREFIX .':)?' . LOCAL_PART . ')/');
+
+/*
+ * End XML:RegExp package.
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,22 @@
+name = RDFx
+description = Extends the RDF mapping API of Drupal core to provide more RDF seralization formats and other RDF capabilities.
+package = RDF
+version = VERSION
+core = 7.x
+dependencies[] = rdf
+dependencies[] = entity
+files[] = rdfx.install
+files[] = rdfx.module
+files[] = rdfx.inc
+files[] = rdfx.terms.inc
+files[] = rdfx.import.inc
+files[] = rdfx.query.inc
+files[] = rdfx.restws.formats.inc
+files[] = rdfx.test
+
+; Information added by drupal.org packaging script on 2011-10-01
+version = "7.x-2.0-alpha4"
+core = "7.x"
+project = "rdfx"
+datestamp = "1317447407"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,308 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the rdfx module.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function rdfx_schema() {
+  $schema['rdfx_vocabulary_graphs'] = array(
+    'description' => 'Vocabulary graph, including stubs for any external terms.',
+    'fields' => array(
+      'gid' => array(
+        'description' => 'Graph ID.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'main_ns' => array(
+        'description' => 'The {rdfx_namespaces}.nsid for this vocabulary.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'date_created' => array(
+        'description' => 'The Unix timestamp when the vocabulary was created or imported.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'date_updated' => array(
+        'description' => 'The Unix timestamp when the vocabulary was updated.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+    'primary key' => array('gid'),
+  );
+
+  $schema['rdfx_namespaces'] = array(
+    'description' => 'Namespace mappings defined in the vocabulary graph. Mappings are defined on a per graph basis (i.e. foaf will be defined multiple times, once for each vocabulary graph that uses foaf terms).',
+    'fields' => array(
+      'nsid' => array(
+        'description' => 'Namespace ID.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'gid' => array(
+        'description' => 'The {rdfx_vocabulary_graphs}.gid of the graph that defined this mapping.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'prefix' => array(
+        'description' => 'The prefix as defined by the user for the main namespace, and by the source file for the additional namespaces.',
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+      ),
+      'uri' => array(
+        'description' => 'The URI as defined by the user for the main namespace, and by the source file for the additional namespaces.',
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('nsid'),
+    'unique keys' => array(
+      'gid_uri' => array('gid', 'uri'),
+    ),
+  );
+
+  $schema['rdfx_terms'] = array(
+    'description' => 'Terms defined or used in the vocabulary graph. Terms are stored on a per graph basis (i.e. foaf:Person will be stored once for each vocabulary graph that asserts something about it).',
+    'fields' => array(
+      'tid' => array(
+        'description' => 'Term ID.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'nsid' => array(
+        'description' => 'The {rdfx_namespaces}.nsid for this term.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'local_name' => array(
+        'description' => 'The local name of this term.',
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+        'default' => '',
+      ),
+    ),
+    'primary key' => array('tid'),
+    'unique keys' => array(
+      'nsid_ln' => array('nsid', 'local_name'),
+    ),
+  );
+
+  $schema['rdfx_term_types'] = array(
+    'description' => 'The RDFS and OWL types that apply to the term. Only terms within the main_ns of a vocabulary graph should have term types.',
+    'fields' => array(
+      'tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the term.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'type' => array(
+        'description' => 'The term type. Types should use defined constants.',
+        'type' => 'varchar',
+        'length' => '32',
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('tid', 'type'),
+  );
+
+  $schema['rdfx_vocabulary_details'] = array(
+    'description' => 'Additional information about a vocabulary.',
+    'fields' => array(
+      'gid' => array(
+        'description' => 'The {rdfx_vocabulary_graphs}.gid of the vocabulary graph.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'language' => array(
+        'description' => 'The language code. Language codes should follow the format in _locale_get_predefined_list() in includes/iso.inc.',
+        'type' => 'varchar',
+        'length' => '12',
+        'not null' => TRUE,
+      ),
+      'label' => array(
+        'description' => 'The name of the vocabulary in language.',
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+      ),
+      'description' => array(
+        'description' => 'The description of the vocabulary in language',
+        'type' => 'varchar',
+        'length' => '4095',
+        'not null' => FALSE,
+      ),
+    ),
+    'primary key' => array('gid', 'language'),
+  );
+
+  $schema['rdfx_term_details'] = array(
+    'description' => 'Additional information about a term. Only terms within the main_ns of a vocabulary graph should have term details.',
+    'fields' => array(
+      'tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the term.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'language' => array(
+        'description' => 'The language code. Language codes should follow the format in _locale_get_predefined_list() in includes/iso.inc.',
+        'type' => 'varchar',
+        'length' => '12',
+        'not null' => TRUE,
+      ),
+      'label' => array(
+        'description' => 'The label for term tid in language.',
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => FALSE,
+      ),
+      'comment' => array(
+        'description' => 'The comment for term tid in language',
+        'type' => 'varchar',
+        'length' => '4095',
+        'not null' => FALSE,
+      ),
+    ),
+    'primary key' => array('tid', 'language'),
+  );
+
+  $schema['rdfx_term_domains'] = array(
+    'description' => 'Domains of properties. Properties within the main_ns can declare classes outside of the main_ns as domains, but not vice versa.',
+    'fields' => array(
+      'tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the property.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'domain_tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the domain class.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('tid', 'domain_tid'),
+  );
+
+  $schema['rdfx_term_inverses'] = array(
+    'description' => 'Inverse properties.',
+    'fields' => array(
+      'tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the property.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'inverse_tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the inverse property.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('tid', 'inverse_tid'),
+  );
+
+  $schema['rdfx_term_ranges'] = array(
+    'description' => 'Ranges of properties. Properties within the main_ns can declare classes outside of the main_ns as ranges, but not vice versa.',
+    'fields' => array(
+      'tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the property.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'range_tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the range class.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('tid', 'range_tid'),
+  );
+
+  $schema['rdfx_term_superclasses'] = array(
+    'description' => 'Superclasses of classes. Classes within the main_ns can declare classes outside of the main_ns as superclasses, but not as subclasses.',
+    'fields' => array(
+      'tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the subclass.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'superclass_tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the superclass.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('tid', 'superclass_tid'),
+  );
+
+  $schema['rdfx_term_superproperties'] = array(
+    'description' => 'Superproperties of properties. Properties within the main_ns can declare properties outside of the main_ns as superproperties, but not as subproperties.',
+    'fields' => array(
+      'tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the subproperty.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'superproperty_tid' => array(
+        'description' => 'The {rdfx_terms}.tid of the superproperty.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('tid', 'superproperty_tid'),
+  );
+
+  return $schema;
+}
+
+/**
+ * Enable entity module (new dependency).
+ */
+function rdfx_update_7001() {
+  module_enable(array(entity));
+  drupal_set_message('The Entity API module is now required by the RDFx module and has been enabled.');
+}
+
+/**
+ * Move the ARC2 library to the new location if the libraries module is used.
+ */
+function rdfx_update_7002() {
+  if (module_exists('libraries') && is_dir(libraries_get_path('arc'))) {
+    if (mkdir(libraries_get_path('ARC2')) && rename(libraries_get_path('arc'), libraries_get_path('ARC2') . '/arc')) {
+      drupal_set_message('The ARC2 library has been moved to its new location.');
+    }
+    else {
+      drupal_set_message('There was a problem while moving the ARC library to its new location.', 'error');
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,387 @@
+<?php
+
+/**
+ * @file
+ * Extends the RDF API of Drupal core to support more RDF seralizations formats
+ * other RDF capabilities.
+ */
+
+/**
+ * Path to the ARC2 PHP library.
+ */
+if (module_exists('libraries')) {
+  define('RDF_ARC2_PATH', libraries_get_path('ARC2') . '/arc');
+}
+else {
+  define('RDF_ARC2_PATH', drupal_get_path('module', 'rdfx') . '/vendor/arc');
+}
+
+/**
+ * Implements hook_init().
+ */
+function rdfx_init() {
+  // Attempts to load the ARC2 library, if available.
+  if (!class_exists('ARC2') && file_exists(RDF_ARC2_PATH . '/ARC2.php')) {
+    @include_once RDF_ARC2_PATH . '/ARC2.php';
+  }
+  module_load_include('inc', 'rdfx', 'rdfx.terms');
+  module_load_include('inc', 'rdfx', 'rdfx.import');
+  module_load_include('inc', 'rdfx', 'rdfx.query');
+}
+
+/*
+ * Implements hook_permission().
+ */
+function rdfx_permission() {
+  return array(
+    'administer rdf' => array(
+      'title' => t('Administer RDF'),
+      'description' => t('Configure and setup RDFx module.'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function rdfx_menu() {
+  // @todo use access RDF data permission instead of access content.
+//   $items['ns'] = array(
+//     'title' => 'Site vocabulary',
+//     'description' => 'RDF description of the site schema.',
+//     'page callback' => 'drupal_get_form',
+//     'access arguments' => array('access content'),
+//     'file' => 'rdfx.pages.inc',
+//   );
+  // Add config options to the Services block on the config page. RDF is not
+  // technically a service, but neither is RSS. RDF and RSS are very closely
+  // aligned.
+  $config_base = array(
+    'access arguments' => array('administer rdf'),
+    'file'             => 'rdfx.admin.inc',
+  );
+  $items['admin/config/services/rdf'] = array(
+    'title'            => 'RDF publishing settings',
+    'description'      => 'Configure how site content gets published in RDF.',
+    'page callback' => 'rdfx_mapping_overview',
+  ) + $config_base;
+  $items['admin/config/services/rdf/mappings'] = array(
+    'title' => 'RDF Mappings',
+    'description'      => 'Configure how site content gets published in RDF.',
+    'page callback'    => 'rdfx_mapping_overview',
+    'type'             => MENU_DEFAULT_LOCAL_TASK,
+  ) + $config_base;
+  $items['admin/config/services/rdf/namespaces'] = array(
+    'title' => 'RDF namespaces',
+    'description'      => 'See all namespaces and their prefixes.',
+    'page callback'    => 'rdfx_admin_namespaces',
+    'type'             => MENU_LOCAL_TASK,
+  ) + $config_base;
+  return $items;
+}
+
+/**
+ * Implements hook_help().
+ */
+function rdfx_help($path, $arg) {
+  switch($path) {
+    case 'admin/config/services/rdf/namespaces';
+      return '<p>' . t('Manage the namespaces and associated prefixes used by the site. Prefixes allow URIs to be shortened in the form of <a href="http://en.wikipedia.org/wiki/CURIE">CURIEs</a> (Compact URIs). For example, the CURIE %curie represents the URI %uri.', array('%curie' => 'dc:title', '%uri' => 'http://purl.org/dc/terms/title')) . '</p>';
+    case 'admin/config/services/rdf/mappings':
+      if (module_exists('rdfui')) {
+        $message = t('Manage RDF mappings for entity types and field bundles used throughout the site. Some mappings are not editable through the UI. See the core RDF mapping API !documentation to find out how to modify these mappings.', array('!documentation' => l('documentation', 'http://drupal.org/developing/api/rdf')));
+      }
+      else {
+        $message = t('View RDF mappings for entity types and field bundles used throughout the site. Enabling the RDF UI module (bundled with RDFx) will allow you to configure many of these mappings.');
+      }
+      return '<p>' . $message . '</p>';
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function rdfx_theme() {
+  return array(
+    'rdfx_mapping_admin_overview' => array(
+      'variables' => array('bundle' => array(), 'rdftype' => array(), 'real_fields' => array(), 'fake_fields' => array()),
+    ),
+    'rdfx_mapping_admin_overview_row' => array(
+      'variables' => array('field' => array()),
+    ),
+  );
+}
+
+function rdfx_get_rdf_model($type, $data) {
+  // Loads entity and its metadata.
+  $wrapper = entity_metadata_wrapper($type, $data);
+  $entity = $wrapper->value();
+
+  $entity_uri = rdfx_resource_uri($type, $wrapper->getIdentifier());
+  // Instantiates node resource as ARC2 class and set base and namespaces.
+  $res = ARC2::getResource();
+  $res->setUri($entity_uri);
+  $res->base = url('', array('absolute' => TRUE));
+  $res->ns = rdf_get_namespaces();
+
+  // Initializes ARC2 index.
+  $index = array();
+
+  // Adds the RDF types of the resource if a mapping exists.
+  if (!empty($entity->rdf_mapping['rdftype'])) {
+    $index[$entity_uri]['rdf:type'] = $entity->rdf_mapping['rdftype'];
+  }
+
+  foreach ($wrapper as $name => $property) {
+    if ($property->access('view')) {
+      try {
+        if ($property instanceof EntityDrupalWrapper || $property instanceof EntityValueWrapper) {
+          rdfx_add_statement($index, $entity_uri, $property, $wrapper, $name);
+        }
+        elseif ($property instanceof EntityListWrapper) {
+          // Iterates through the list and add each of them as statement.
+          $li_filtered = rdfx_property_access_filter($property);
+          foreach ($li_filtered as $li_name => $li_property) {
+            if ($li_property instanceof EntityDrupalWrapper || $li_property instanceof EntityValueWrapper) {
+              rdfx_add_statement($index, $entity_uri, $li_property, $wrapper, $name);
+            }
+          }
+        }
+        elseif ($property instanceof EntityStructureWrapper) {
+          // Entity Structure Wrapper exposes structural elements, such as
+          // text format for fields. We are not interested in this, and adding
+          // the additional information about values means you have to handle
+          // values as blank nodes.
+          $li_filtered = rdfx_property_access_filter($property);
+          foreach ($li_filtered as $li_name => $li_property) {
+            if ($li_property instanceof EntityDrupalWrapper || $li_property instanceof EntityValueWrapper) {
+              // This assumes that all literals have a 'value' array element
+              // and that all resources have a 'uri' array element.
+              if ($li_name == 'value' || $li_name == 'uri'){
+                rdfx_add_statement($index, $entity_uri, $li_property, $wrapper, $name);
+              }
+            }
+          }
+        }
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // Property not supported. Fail silently.
+      }
+    }
+  }
+
+  // Expand all CURIEs and attach the index to the ARC2 resource.
+  $res->index = $res->expandPNames($index);
+  return $res;
+}
+
+function rdfx_property_access_filter($wrapper) {
+  $filtered = array();
+  foreach ($wrapper as $name => $property) {
+    if ($property->access('view')) {
+      $filtered[$name] = $property;
+    }
+  }
+  return $filtered;
+}
+
+/**
+ * Gets the predicates relating the property to the entity.
+ */
+function rdfx_get_predicates(EntityMetadataWrapper $wrapper, $name) {
+  $element = array();
+  if ($wrapper instanceof EntityDrupalWrapper) {
+    $entity = $wrapper->value();
+    if (!empty($entity->rdf_mapping[$name])) {
+      // Just make use of the first predicate for now.
+      // @lin this support all predicates defined in the mapping.
+      $predicates = $entity->rdf_mapping[$name]['predicates'];
+      $element = $predicates;
+    }
+  }
+  // For elements which don't have a mapping, expose them using a local
+  // namespace. @todo site vocabulary.
+  // This functionality is disabled by default as a lot of this data is
+  // irrelevant for outsiders and might contains some data the site owner might
+  // not want to expose.
+  // @todo provide admin setting to enable this functionality.
+  if (!isset($element) && variable_get('rdfx_include_unset_mappings', FALSE)) {
+    $predicate = 'site:' . (is_numeric($name) ? 'item' : $name);
+    $element = array($predicate);
+  }
+  return $element;
+}
+
+/**
+ * Adds an RDF statement between the entity and the property. These statements
+ * can have either resource or literal objects.
+ */
+function rdfx_add_statement(&$index, $uri, $property, EntityMetadataWrapper $wrapper, $name) {
+  if ($property instanceof EntityDrupalWrapper) {
+    // For referenced entities only add the resource's URI
+    rdfx_add_resource($index, $uri, $property, $wrapper, $name);
+  }
+  elseif ($property instanceof EntityValueWrapper) {
+    rdfx_add_literal($index, $uri, $property, $wrapper, $name);
+  }
+}
+
+/**
+ * Adds a resource object.
+ */
+function rdfx_add_resource(&$index, $uri, $property, EntityMetadataWrapper $wrapper, $name) {
+  if ($id = $property->getIdentifier()) {
+    $predicates = rdfx_get_predicates($wrapper, $name);
+    $object_uri = rdfx_resource_uri($property->type(), $id);
+    foreach ($predicates as $predicate) {
+      $index[$uri][$predicate][] = $object_uri;
+    }
+  }
+}
+
+/**
+ * Adds a literal object.
+ */
+function rdfx_add_literal(&$index, $uri, $property, EntityMetadataWrapper $wrapper, $name) {
+  $predicates = rdfx_get_predicates($wrapper, $name);
+  $object_value = $property->value();
+
+  // Extracts datatype and callback from the RDF mapping.
+  $datatype = '';
+  if ($wrapper instanceof EntityDrupalWrapper) {
+    $entity = $wrapper->value();
+    if (!empty($entity->rdf_mapping[$name]['datatype'])) {
+      $datatype = $entity->rdf_mapping[$name]['datatype'];
+    }
+    if (!empty($entity->rdf_mapping[$name]['callback']) && function_exists($entity->rdf_mapping[$name]['callback'])) {
+      $object_value = $entity->rdf_mapping[$name]['callback']($object_value);
+    }
+  }
+
+  foreach ($predicates as $predicate) {
+    $index[$uri][$predicate][] = array(
+      'value' => $object_value,
+      'type' => 'literal',
+      'datatype' => $datatype,
+    );
+  }
+}
+
+/**
+ * Returns the URI used for the given resource.
+ */
+function rdfx_resource_uri($resource, $id) {
+  return url($resource . '/' . $id, array('absolute' => TRUE));
+}
+
+/**
+ * Lists the RDF serializations format which will be integrated with RestWS.
+ *
+ * Does not implement hook_restws_format_info() because we need to override the
+ * RDF serialization format to use our own ARC2 based serializer.
+ */
+function _rdfx_serialization_formats() {
+  $result['rdf'] = array(
+    'label' => t('RDF/XML'),
+    'class' => 'RDFxRestWSFormatRDFXML',
+    'mime type' => 'application/rdf+xml',
+  );
+  $result['ttl'] = array(
+    'label' => t('Turtle'),
+    'class' => 'RDFxRestWSFormatTurtle',
+    'mime type' => 'application/x-turtle',
+  );
+  $result['nt'] = array(
+    'label' => t('NTriples'),
+    'class' => 'RDFxRestWSFormatNTriples',
+    'mime type' => 'text/plain',
+  );
+  $result['rdfjson'] = array(
+    'label' => t('RDFJSON'),
+    'class' => 'RDFxRestWSFormatRDFJSON',
+    'mime type' => 'application/json',
+  );
+  return $result;
+}
+
+/**
+ * Implements hook_restws_format_info_alter().
+ */
+function rdfx_restws_format_info_alter(&$info) {
+  $info = _rdfx_serialization_formats() + $info;
+}
+
+/**
+ * Implements hook_requirements().
+ */
+function rdfx_requirements($phase) {
+  $requirements = array();
+
+  if ($phase == 'runtime') {
+    if (class_exists('ARC2')) {
+      $value = t('Installed (version @version)', array('@version' => ARC2::getVersion()));
+      $severity = REQUIREMENT_OK;
+      $description = '';
+    }
+    else {
+      $value = t('Not installed');;
+      $severity = REQUIREMENT_ERROR;
+      $path = module_exists('libraries') ? libraries_get_path('ARC2') . '/arc/ARC2.php' : drupal_get_path('module', 'rdfx') . '/vendor/arc/ARC2.php';
+      $description = t('The RDFx module requires the ARC2 library to function properly. The simplest way to install ARC2 is by using the Drush command "drush rdf-download". Alternatively, you can !download the latest package, unzip it, and move/rename the folder so that the path to ARC2.php is %path', array('!download' => l('download', 'http://github.com/semsol/arc2/tarball/master'), '%path' => $path));
+    }
+    $requirements['rdfx_arc'] = array(
+      'title' => t('RDFx ARC2 Library'),
+      'value' => $value,
+      'severity' => $severity,
+      'description' => $description,
+    );
+
+    // If there were any conflicting namespaces...
+    if (rdfx_get_conflicting_namespaces()) {
+      // Add a requirement warning and break.
+      $requirements['rdfx_ns_conflict'] = array(
+        'title' => t('RDFx Namespace Conflict'),
+        'severity' => REQUIREMENT_ERROR,
+        'value' => '',
+        'description' => t('One or more namespaces has conflicts.  See this page for more information:') . ' ' . l(t('RDF publishing settings'), 'admin/config/services/rdf/namespaces')
+      );
+    }
+  }
+  return $requirements;
+}
+
+
+/**
+ * Gets conflicting namespaces.
+ * Returns an array of (prefix => array(uri1, uri2, ...)) items.
+ */
+function rdfx_get_conflicting_namespaces() {
+  $conflicting_namespaces = array();
+
+  $rdf_namespaces = module_invoke_all('rdf_namespaces');
+
+  foreach ($rdf_namespaces as $prefix => $uris) {
+    if (is_array($uris)) {
+      $consolidated_uris = array_unique($uris);
+
+      // A prefix has conflicting namespaces if it has multiple associated URIs.
+      if (count($consolidated_uris) > 1) {
+        $conflicting_namespaces[$prefix] = $consolidated_uris;
+      }
+    }
+  }
+  return $conflicting_namespaces;
+}
+
+/**
+ * Implementation of hook_features_api().
+ */
+function rdfx_features_api() {
+  return array(
+    'rdf_mappings' => array(
+      'name' => t('RDF mappings'),
+      'default_hook' => 'rdf_default_mappings',
+      'file' => drupal_get_path('module', 'rdfx') .'/rdfx.features.inc',
+    ),
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.query.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * @file
+ * Functions for querying with SPARQL or extracting triples from an ARC2-style
+ * data structure.
+ */
+
+function _rdfx_query_ask(&$model, $queries) {
+  foreach ($queries as $query) {
+    list($s, $p, $o) = $query;
+    if (_rdfx_query_find_first($model, $s, $p, $o)) return true;
+  }
+  return false;
+}
+
+function _rdfx_query_find_literal(&$model, $queries) {
+  $literal = array();
+  foreach ($queries as $query) {
+    list($s, $p, $o) = $query;
+    $triples = _rdfx_query_find_all($model, $s, $p, $o);
+    // We create an associative array based on the language code of the
+    // literal. The language codes Drupal uses are specified in includes/iso.inc.
+    foreach ($triples as $triple) {
+      if ($triple['o_lang'] !== '') {
+        // Chinese and Portuguese are the only languages with a >2 letter
+        // langcode.
+        if (preg_match('/(zh-hans)|(zh-hant)|(pt-pt)|(pt-br)/', $triple['o_lang'])) {
+          $langcode = $triple['o_lang'];
+        }
+        // Remove the region code if it is used (i.e. en-US is changed to en).
+        else {
+          $lang_array = explode('-', $triple['o_lang']);
+          $langcode = !empty($lang_array[0]) ? $lang_array[0] : $triple['o_lang'];
+        }
+      }
+      else {
+        $langcode = 'und';
+      }
+      $literal[$langcode] = $triple['o'];
+    }
+  }
+  return $literal;
+}
+
+function _rdfx_query_find_uris(&$model, $queries) {
+  $uris = array();
+  foreach ($queries as $query) {
+    list($s, $p, $o) = $query;
+    $result = _rdfx_query_find_all($model, $s, $p, $o);
+    foreach ($result as $triple) {
+      if ($s == '?' && $triple['s_type'] == 'uri') {
+        $uris[] = $triple['s'];
+      }
+      if ($p == '?') {
+        $uris[] = $triple['p'];
+      }
+      if ($o == '?' && $triple['o_type'] == 'uri') {
+        $uris[] = $triple['o'];
+      }
+    }
+  }
+  return array_unique($uris);
+}
+
+function _rdfx_query_find_qnames(&$model, $queries) {
+  $uris = _rdfx_query_find_uris($model, $queries);
+  $qnames = array();
+  foreach ($uris as $uri) {
+    $qnames[] = $uri;
+  }
+  return $qnames;
+}
+
+function _rdfx_query_find_first(&$model, $s, $p, $o) {
+  foreach ($model as $triple) {
+    if (!is_null($s) && $s != '?' && ($triple['s'] != $s || $triple['s_type'] != 'uri')) continue;
+    if (!is_null($p) && $p != '?' && ($triple['p'] != $p)) continue;
+    if (!is_null($o) && $o != '?' && ($triple['o'] != $o || $triple['o_type'] != 'uri')) continue;
+    return $triple;
+  }
+  return null;
+}
+
+function _rdfx_query_find_all(&$model, $s, $p, $o) {
+  $result = array();
+  foreach ($model as $triple) {
+    if (!is_null($s) && $s != '?' && ($triple['s'] != $s)) continue;
+    if (!is_null($p) && $p != '?' && ($triple['p'] != $p)) continue;
+    if (!is_null($o) && $o != '?' && ($triple['o'] != $o)) continue;
+    $result[] = $triple;
+  }
+  return $result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.restws.formats.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * A base formatter for all RDF serialization formats.
+ */
+class RDFxRestWSBaseFormat extends RestWSBaseFormat {
+  /**
+   * Read only support.
+   */
+  public function createResource($resourceController, $data) {
+    throw new RestWSException('Not implemented', 501);
+  }
+
+  public function updateResource($resourceController, $id, $data) {
+    throw new RestWSException('Not implemented', 501);
+  }
+
+  public function deleteResource($resourceController, $id) {
+    throw new RestWSException('Not implemented', 501);
+  }
+}
+
+/**
+ * Formatters for all RDF serialization formats.
+ */
+class RDFxRestWSFormatRDFXML extends RDFxRestWSBaseFormat {
+  public function viewResource($resourceController, $id) {
+    $resource = rdfx_get_rdf_model($resourceController->resource(), $id);
+    $serializer = ARC2::getSer('RDFXML', array('ns' => $resource->ns));
+    return $serializer->getSerializedIndex($resource->index);
+  }
+}
+
+class RDFxRestWSFormatTurtle extends RDFxRestWSBaseFormat {
+  public function viewResource($resourceController, $id) {
+    $resource = rdfx_get_rdf_model($resourceController->resource(), $id);
+    $serializer = ARC2::getSer('Turtle', array('ns' => $resource->ns));
+    return $serializer->getSerializedIndex($resource->index);
+  }
+}
+
+class RDFxRestWSFormatNTriples extends RDFxRestWSBaseFormat {
+  public function viewResource($resourceController, $id) {
+    $resource = rdfx_get_rdf_model($resourceController->resource(), $id);
+    $serializer = ARC2::getSer('NTriples', array('ns' => $resource->ns));
+    return $serializer->getSerializedIndex($resource->index);
+  }
+}
+
+class RDFxRestWSFormatRDFJSON extends RDFxRestWSBaseFormat {
+  public function viewResource($resourceController, $id) {
+    $resource = rdfx_get_rdf_model($resourceController->resource(), $id);
+    $serializer = ARC2::getSer('RDFJSON', array('ns' => $resource->ns));
+    return $serializer->getSerializedIndex($resource->index);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.terms.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,622 @@
+<?php
+
+/**
+ * @file
+ * Functions for managing RDF Terms.
+ */
+
+function rdfx_get_properties() {
+  $property_tids = _rdfx_get_terms('property');
+  return $property_tids;
+}
+
+function rdfx_get_classes() {
+  $class_tids = _rdfx_get_terms('class');
+  return $class_tids;
+}
+
+function _rdfx_get_terms($term_type) {
+  $term_types = rdfx_term_types();
+  switch ($term_type) {
+    case 'property':
+      $types = array_keys($term_types['properties']['term_types']);
+      break;
+    case 'class':
+      $types = array_keys($term_types['classes']['term_types']);
+      break;
+    default:
+      $types = array_merge(array_keys($term_types['properties']['term_types']), array_keys($term_types['classes']['term_types']));
+  }
+  $query = db_select('rdfx_term_types', 'rdftt')
+    ->fields('rdft', array('tid'))
+    ->condition('rdftt.type', $types, 'IN');
+  $query->join('rdfx_terms', 'rdft', 'rdftt.tid = rdft.tid');
+  $query->join('rdfx_namespaces', 'rdfns', 'rdfns.nsid = rdft.nsid');
+  $query->join('rdfx_vocabulary_graphs', 'rdfvg', 'rdfvg.main_ns = rdfns.nsid');
+  $terms = $query->execute()->fetchCol();
+  return $terms;
+}
+
+/**
+ * Gets a list of all defined namespaces.
+ */
+function rdfx_get_namespaces() {
+  $rdf_namespaces = &drupal_static(__FUNCTION__);
+  if (empty($rdf_namespaces)) {
+    $rdf_namespaces = rdf_get_namespaces();
+  }
+  return $rdf_namespaces;
+}
+
+/**
+ * Implements hook_rdf_namespaces.
+ */
+function rdfx_rdf_namespaces() {
+  // Starts with some additionnal common namespaces which core does not include.
+  $ns_mappings = array(
+    'owl'      => 'http://www.w3.org/2002/07/owl#',
+    'rdf'      => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+    'rss'      => 'http://purl.org/rss/1.0/',
+    // url() does not support empty fragment.
+    'site'     => url('ns', array('absolute' => TRUE)) . '#',
+  );
+
+  // Gets the custom namespaces stored in the database.
+  $query = db_select('rdfx_vocabulary_graphs', 'g');
+  $query->fields('n', array('prefix', 'uri'));
+  $query->join('rdfx_namespaces', 'n', 'g.main_ns = n.nsid');
+  $query->orderBy('n.prefix');
+  $namespaces = $query->execute()->fetchAllKeyed();
+  foreach ($namespaces as $prefix => $uri) {
+    $ns_mappings[$prefix] = $uri;
+  }
+
+  return $ns_mappings;
+}
+
+/**
+ * Saves the main namespace mapping for a vocabulary graph and the additional
+ * namespace mappings as defined in the document.
+ */
+function _rdfx_save_vocabulary($main_ns, $main_ns_prefix, $vocabulary) {
+  $current_time = REQUEST_TIME;
+  // If the vocabulary URI matches the main_ns of a vocabulary source, then
+  // this is an update to that record. Otherwise, this is a newly imported
+  // source.
+  $gid = rdfx_get_gid($main_ns);
+
+  // If there is an existing vocabulary, make sure that the main_ns is in the
+  // namespaces array and that the user defined mapping is the last in the
+  // array so the prefix reflects the user definition. Also change the
+  // vocabulary graph updated date.
+  if ($gid) {
+    $vocabulary['namespaces'][$main_ns_prefix] = $main_ns;
+    db_update('rdfx_vocabulary_graphs')
+      ->fields(array('date_updated' => $current_time,))
+      ->execute();
+  }
+
+  // If this is a new vocabulary, create a graph with a main namespace and
+  // add the additional namespaces.
+  else {
+    // @todo If the vocab URI isn't used in any terms, don't add it to ns table.
+    // This may happen where multiple files are defining a vocabulary.
+
+    // @todo This should be handled as a transaction in case there is an error
+    // in the middle. If there is an error, then there will be an SQL error
+    // when the user retries the import.
+
+    // Insert this namespace to get the nsid. The vocabulary_source entry will
+    // point to this nsid for the main_ns. We temporarily insert 0 for the gid,
+    // then update when we have the real gid.
+    $nsid = db_insert('rdfx_namespaces')
+      ->fields(array('uri' => $main_ns, 'prefix' => $main_ns_prefix, 'gid' => '0'))
+      ->execute();
+    $gid = db_insert('rdfx_vocabulary_graphs')
+      ->fields(array(
+          'main_ns' => $nsid,
+          'date_created' => $current_time,
+          'date_updated' => $current_time,))
+      ->execute();
+    db_update('rdfx_namespaces')
+      ->condition('nsid', $nsid)
+      ->fields(array('gid' => $gid))
+      ->execute();
+  }
+  // Insert/update the vocabulary title.
+  if (count($vocabulary['title']) > 0) {
+    foreach ($vocabulary['title'] as $langcode => $title) {
+      $query = db_merge('rdfx_vocabulary_details')
+        ->key(array('gid' => $gid, 'language' => $langcode))
+        ->fields(array('language' => $langcode, 'label' => $title));
+      $status = $query->execute();
+    }
+  }
+
+  // Insert/update the vocabulary description.
+  if (count($vocabulary['description']) > 0) {
+    foreach ($vocabulary['description'] as $langcode => $description) {
+      $query = db_merge('rdfx_vocabulary_details')
+        ->key(array('gid' => $gid, 'language' => $langcode))
+        ->fields(array('language' => $langcode, 'description' => $description));
+      $status = $query->execute();
+    }
+  }
+
+  // Insert/update the other namespace mappings used in this vocabulary graph.
+  if (count($vocabulary['namespaces']) > 0) {
+    foreach ($vocabulary['namespaces'] as $prefix => $namespace) {
+      if ($namespace != $main_ns) {
+        $query = db_merge('rdfx_namespaces')
+          ->key(array('gid' => $gid, 'uri' => $namespace))
+          ->fields(array('uri' => $namespace, 'prefix' => $prefix, 'gid' => $gid))
+          ->updateFields(array('prefix' => $prefix));
+        $status = $query->execute();
+      }
+    }
+  }
+
+  $nsids = rdfx_get_nsids($main_ns);
+  return $nsids;
+}
+
+/**
+ * Saves vocabulary terms.
+ */
+function rdfx_save_terms($vocabulary_uri, $prefix, $vocabulary) {
+  $nsids = _rdfx_save_vocabulary($vocabulary_uri, $prefix, $vocabulary);
+  foreach ($vocabulary['terms'] as $term_type => $terms) {
+    foreach ($terms as $term_uri => $term_description) {
+      list($term_ns, $term_local_name) = rdfx_split_uri($term_uri);
+      if (isset($nsids[$term_ns])) {
+        $nsid = $nsids[$term_ns];
+      }
+      else {
+        // If the namespace wasn't mapped to a prefix in the source graph, we
+        // didn't save it to the namespaces table, so we need to add an entry.
+
+        // @todo For the prefix value, we save the URI... should this be changed?
+        $gid = rdfx_get_gid($vocabulary_uri);
+        $nsid = db_insert('rdfx_namespaces')
+          ->fields(array('uri' => $term_ns, 'prefix' => $term_ns, 'gid' => $gid))
+          ->execute();
+        $nsids[$term_ns] = $nsid;
+      }
+
+      // Get the tid of this term, saving to {rdfx_terms} if not already there.
+      $tid = db_query("SELECT tid FROM {rdfx_terms} WHERE nsid = :nsid AND local_name = :localname", array(':nsid' => $nsid, ':localname' => $term_local_name))->fetchField();
+      if ($tid == NULL) {
+        $tid = db_insert('rdfx_terms')
+          ->fields(array('nsid', 'local_name'))
+          ->values(array(
+            'nsid' => $nsid,
+            'local_name' => $term_local_name,
+          ))
+          ->execute();
+      }
+
+      // Add the current type to this term in {rdfx_term_types}.
+      db_merge('rdfx_term_types')
+        ->key(array('tid' => $tid, 'type' => $term_type))
+        ->fields(array(
+            'tid' => $tid,
+            'type' => $term_type,
+        ))
+        ->execute();
+
+      // Add label and comment to {rdfx_term_details}.
+      $term_details = array();
+      if (isset($term_description['label'])) {
+        foreach ($term_description['label'] as $lang => $text) {
+          $term_details[$lang]['label'] = $text;
+        }
+      }
+      if (isset($term_description['comment'])) {
+        foreach ($term_description['comment'] as $lang => $text) {
+          $term_details[$lang]['comment'] = $text;
+        }
+      }
+      if (!empty($term_details)) {
+        foreach ($term_details as $lang => $details) {
+          db_merge('rdfx_term_details')
+            ->key(array('tid' => $tid, 'language' => $lang))
+            ->fields(array(
+                'tid' => $tid,
+                'language' => $lang,
+                'label' => isset($details['label']) ? $details['label'] : NULL,
+                'comment' => isset($details['comment']) ? $details['comment'] :  NULL,
+            ))
+            ->execute();
+        }
+      }
+
+      // Add relationships to their respective tables. This is handled as a
+      // complicated set of loops to reduce code duplication. To add a new
+      // relationship, just add the array key that is used in
+      // $types['properties']['description'] to define the relationship, and
+      // then add the name of the table that stores the relationship.
+      $relationships = array(
+        'domain' => 'rdfx_term_domains',
+        'range' => 'rdfx_term_ranges',
+      );
+      foreach ($relationships as $relationship => $table_name) {
+        if (isset($term_description[$relationship])) {
+          foreach ($term_description[$relationship] as $related_term) {
+            $related_term_tid = rdfx_get_tid($related_term, $vocabulary_uri);
+            if ($related_term_tid) {
+              db_merge($table_name)
+                ->key(array('tid' => $tid, $relationship . '_tid' => $related_term_tid))
+                ->fields(array(
+                    'tid' => $tid,
+                    $relationship . '_tid' => $related_term_tid,
+                ))
+                ->execute();
+            }
+          }
+        }
+      }
+    }
+  }
+  // @todo Add a hook that passes the $vocabulary and the $model.
+}
+
+/**
+ * Returns metadata about term types defined by rdf modules.
+ *
+ * If your module needs to determine what term types are being supplied by
+ * other modules, call this function. Querying rdfx database tables directly
+ * for this information is discouraged. Any additional term types should be
+ * added through the corresponding alter hook.
+ *
+ * Three major bins of data are stored: tags, value_types, and functions. Each
+ * entry in these bins is keyed by the value stored in the actual VotingAPI
+ * tables, and contains an array with (minimally) 'name' and 'description' keys.
+ * Modules can add extra keys to their entries if desired.
+ *
+ * This metadata can be modified or expanded using hook_rdfx_term_types_alter().
+ *
+ * @return
+ *   An array of metadata defined by RDFx Terms and altered by rdf modules.
+ *
+ * @see hook_rdfx_term_types_alter()
+ *
+ * Modeled on VotingAPI votingapi_metadata.
+ */
+function rdfx_term_types($reset = FALSE) {
+  static $types;
+  if ($reset || !isset($types)) {
+    $types['classes']['term_types'] = array();
+    $types['properties']['term_types'] = array();
+
+    $term_details = '';
+
+    // @todo Should the inference consider subProp and subClass relationships
+    // as well. ie. should all OWL classes also have the type RDFS Class
+
+    // @todo Switch to drupal cache
+    $types['classes']['term_types'] = array(
+      'rdfs_class' => array(
+        'uri' => 'http://www.w3.org/2000/01/rdf-schema#Class',
+        'inference' => array(
+          'http://www.w3.org/2000/01/rdf-schema#subClassOf' => array(
+            'subject',
+            'object',
+          ),
+          'http://www.w3.org/2000/01/rdf-schema#domain' => array(
+            'object',
+          ),
+          'http://www.w3.org/2000/01/rdf-schema#range' => array(
+            'object',
+          ),
+        ),
+      ),
+      'owl_class' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#Class',
+        'inference' => array(
+          'http://www.w3.org/2002/07/owl#equivalentClass' => array(
+            'subject',
+            'object',
+          ),
+          'http://www.w3.org/2002/07/owl#disjointWith' => array(
+            'subject',
+            'object',
+          ),
+        ),
+      ),
+    );
+
+    $types['properties']['term_types'] = array (
+      'rdf_property' => array(
+        'uri' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Property',
+        'inference' => array(
+          'http://www.w3.org/2000/01/rdf-schema#domain' => array(
+            'subject',
+          ),
+          'http://www.w3.org/2000/01/rdf-schema#range' => array(
+            'subject',
+          ),
+          'http://www.w3.org/2000/01/rdf-schema#subPropertyOf' => array(
+            'subject',
+            'object',
+          ),
+          'http://www.w3.org/2002/07/owl#equivalentProperty' => array(
+            'subject',
+            'object',
+          ),
+          'http://www.w3.org/2002/07/owl#inverseOf' => array(
+            'subject',
+            'object',
+          ),
+        ),
+      ),
+      'owl_property_datatype' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#DatatypeProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_object' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#ObjectProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_functional' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#FunctionalProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_inverse_functional' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#InverseFunctionalProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_symmetric' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#SymmetricProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_asymmetric' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#AsymmetricProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_annotation' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#AnnotationProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_reflexive' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#ReflexiveProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_irreflexive' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#IrreflexiveProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_transitive' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#TransitiveProperty',
+        'inference' => array(
+        ),
+      ),
+    );
+
+    $types['classes']['description'] = array(
+      'superclass' => array(
+        'http://www.w3.org/2000/01/rdf-schema#subClassOf' => array(
+          'object',
+        ),
+      ),
+      'disjoint' => array(
+        'http://www.w3.org/2002/07/owl#disjointWith' => array(
+          'object',
+        ),
+      ),
+    );
+
+    $types['properties']['description'] = array(
+      'domain' => array(
+        'http://www.w3.org/2000/01/rdf-schema#domain' => array(
+          'object',
+        ),
+      ),
+      'range' => array(
+        'http://www.w3.org/2000/01/rdf-schema#range' => array(
+          'object',
+        ),
+      ),
+      'superproperty' => array(
+        'http://www.w3.org/2000/01/rdf-schema#subPropertyOf' => array(
+          'object',
+        ),
+      ),
+      'inverse' => array(
+        'http://www.w3.org/2002/07/owl#inverseOf' => array(
+          'object',
+        ),
+      ),
+    );
+    drupal_alter('rdfx_term_types', $types);
+  }
+
+  return $types;
+}
+
+/**
+ * Splits a URI into namespace and localpart.
+ */
+function rdfx_split_uri ($uri) {
+  $parts = ARC2::splitURI($uri);
+  return $parts;
+}
+
+function rdfx_get_tid($term_uri, $graph_main_ns) {
+  $nsids = rdfx_get_nsids($graph_main_ns);
+  list($term_ns, $term_local_name) = rdfx_split_uri($term_uri);
+  if (isset($nsids[$term_ns])) {
+    $tid = db_query("SELECT tid FROM {rdfx_terms} WHERE nsid = :nsid AND local_name = :localname", array(':nsid' => $nsids[$term_ns], ':localname' => $term_local_name))->fetchField();
+    return $tid;
+  }
+  else {
+    return NULL;
+  }
+}
+
+function rdfx_get_gid($main_ns) {
+  $gids = db_select('rdfx_namespaces', 'rdfns', array());
+  $gids->join('rdfx_vocabulary_graphs', 'rdfvg', 'rdfvg.main_ns = rdfns.nsid');
+  $gids
+    ->fields('rdfns', array('gid'))
+    ->condition('rdfns.uri', $main_ns);
+  // @todo There should only be one result if there is a matching vocab source.
+  // However, perhaps we should test to make sure and throw an error?
+  $gid = $gids->execute()->fetchField();
+  return $gid;
+}
+
+function rdfx_get_nsids($main_ns) {
+  $gid = rdfx_get_gid($main_ns);
+  $nsids = db_query("SELECT uri, nsid FROM {rdfx_namespaces} WHERE gid = :gid", array(':gid' => $gid))->fetchAllKeyed();
+  return $nsids;
+}
+
+function rdfx_curie($tid) {
+  $query = db_select('rdfx_terms', 'rdft')
+    ->fields('rdft', array('local_name'))
+    ->fields('rdfns', array('prefix'))
+    ->condition('rdft.tid', $tid, '=');
+  $query->join('rdfx_namespaces', 'rdfns', 'rdfns.nsid = rdft.nsid');
+  $result = $query->execute()->fetch();
+  $curie = $result->prefix . ':' . $result->local_name;
+  return $curie;
+}
+
+function _rdfx_get_term_details($tid, $langcode = 'und') {
+  $query_language = db_query("SELECT language FROM {rdfx_term_details} WHERE tid = :tid", array(':tid' => $tid));
+  $languages = $query_language->fetchCol();
+  if (!in_array($langcode, $languages)) {
+    if (in_array('und', $languages)) {
+      $langcode = 'und';
+    }
+    elseif (in_array('en', $languages)) {
+      $langcode = 'en';
+    }
+    else {
+      return;
+    }
+  }
+  $query = db_select('rdfx_term_details', 'rdfd')
+    ->fields('rdfd', array('label', 'comment'))
+    ->condition('rdfd.tid', $tid, '=')
+    ->condition('language', $langcode, '=');
+  $details = $query->execute()->fetch();
+  return $details;
+}
+
+/**
+ * Queries a set of triples for classes and properties, and builds
+ * an associative array describing the vocabulary and any
+ * classes and properties found.
+ *
+ * @param array $model An ARC2-style array of triples an RDFS vocabulary or OWL ontology
+ * @param array $namespaces Associative array of namespaces parsed from the RDF file
+ * @param string $ns_prefix Namespace prefix for the vocabulary
+ * @param string $ns_uri Only terms in this namespace will be considered
+ * @return array Array describing the vocabulary, its classes and properties.
+ */
+function _rdfx_extract_schema(&$model, $namespaces, $ns_prefix, $ns_uri) {
+  $vocabulary_details = _rdfx_get_vocabulary_details($model, $ns_uri);
+  $terms = _rdfx_fetch_terms($model);
+  $vocabulary = array(
+      'uri' => $ns_uri,
+      'title' => $vocabulary_details['title'],
+      'description' => $vocabulary_details['description'],
+      'terms' => $terms,
+      'namespaces' => $namespaces,
+  );
+  return $vocabulary;
+}
+
+function _rdfx_fetch_terms(&$model) {
+  $terms = array();
+  $term_uris = array();
+
+  // Retrieve the queries for term retrieval. This may have been modified by
+  // other modules.
+  $term_type_groups = rdfx_term_types();
+
+  foreach($term_type_groups as $term_type_group => $group) {
+    foreach ($group['term_types'] as $term_type => $term) {
+      $query = array(
+        array('?', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', $term['uri']),
+      );
+      foreach ($term['inference'] as $inference_uri => $query_types) {
+        foreach ($query_types as $query_type) {
+          switch ($query_type) {
+            case 'subject':
+              $query[] = array('?', $inference_uri, null);
+              break;
+            case 'object':
+              $query[] = array(null, $inference_uri, '?');
+              break;
+          }
+        }
+      }
+      $term_uris[$term_type] = _rdfx_query_find_uris($model, $query);
+
+      // Add term details and various relationships for each term, as defined
+      // in rdfx_term_types() and altered by hook_rdfx_term_types_alter().
+      $query_x = array();
+      foreach ($term_uris[$term_type] as $term_uri) {
+
+        $terms[$term_type][$term_uri] = _evoc_query_for_term_description($model, $term_uri);
+        foreach ($group['description'] as $property => $queries) {
+          foreach ($queries as $predicate_uri => $query_types) {
+            foreach ($query_types as $query_type) {
+              switch ($query_type) {
+                case 'subject':
+                  $query_x[$term_uri][$property][] = array('?', $predicate_uri, $term_uri);
+                  break;
+                case 'object':
+                  $query_x[$term_uri][$property][] = array($term_uri, $predicate_uri, '?');
+                  break;
+              }
+            }
+          }
+          $terms[$term_type][$term_uri][$property] = _rdfx_query_find_uris($model, $query_x[$term_uri][$property]);
+        }
+      }
+    }
+  }
+  return $terms;
+}
+
+function _rdfx_get_vocabulary_details(&$model, $ns_uri) {
+  $query_predicates = array(
+    'title' => array(
+      'http://www.w3.org/2000/01/rdf-schema#label',
+      'http://purl.org/dc/elements/1.1/title',
+      'http://purl.org/dc/terms/title',
+    ),
+    'description' => array(
+      'http://www.w3.org/2000/01/rdf-schema#comment',
+      'http://purl.org/dc/elements/1.1/description',
+      'http://purl.org/dc/terms/description',
+    ),
+  );
+
+  if (substr($ns_uri, -1) == '#') {
+    $uri = substr($ns_uri, 0, -1);
+  }
+
+  foreach ($query_predicates as $query_element => $predicates) {
+    foreach ($predicates as $predicate) {
+      $queries[$query_element][] = array($ns_uri, $predicate, '?');
+//       if ($uri !== NULL) {
+//         $queries[$query_element][] = array($uri, $predicate, '?');
+//       }
+    }
+    $details[$query_element] = _rdfx_query_find_literal($model, $queries[$query_element]);
+  }
+  return $details;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * Test the RDF serialization functionality for nodes.
+ */
+class RdfxNodeSerializationTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'RDF serialization for Nodes',
+      'description' => 'Create a node and test its RDF serialization.',
+      'group' => 'RDFx',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('rdfx');
+
+    // Set default storage backend.
+    variable_set('field_storage_default', 'field_sql_storage');
+
+//     $field_name = drupal_strtolower('rdfx_text_test_field');
+//     $field = array('field_name' => $field_name, 'type' => 'test_field', 'cardinality' => 4);
+//     $field = field_create_field($field);
+//     $field_id = $field['id'];
+//     $instance = array(
+//       'field_name' => $field_name,
+//       'entity_type' => 'test_entity',
+//       'bundle' => 'article',
+//       'label' => $this->randomName() . '_label',
+//       'description' => $this->randomName() . '_description',
+//       'weight' => mt_rand(0, 127),
+//       'settings' => array(
+//         'test_instance_setting' => $this->randomName(),
+//       ),
+//       'widget' => array(
+//         'type' => 'test_field_widget',
+//         'label' => 'Test Field',
+//         'settings' => array(
+//           'test_widget_setting' => $this->randomName(),
+//         )
+//       )
+//     );
+//     field_create_instance($this->instance);
+
+    $web_user = $this->drupalCreateUser(array('create article content', 'create page content'));
+    $this->drupalLogin($web_user);
+  }
+
+  /**
+   * Create a "Article" node and ensure it serialized properly.
+   */
+  function testRdfxNodeCreation() {
+    // Create a node.
+    $edit = array();
+    $langcode = LANGUAGE_NONE;
+    $edit["title"] = $this->randomName(8);
+    $edit["body[$langcode][0][value]"] = $this->randomName(16);
+    $this->drupalPost('node/add/article', $edit, t('Save'));
+
+    // Check that the Article has been created.
+    $this->assertRaw(t('!post %title has been created.', array('!post' => 'Article', '%title' => $edit["title"])), t('Article created.'));
+
+    // Check that the node exists in the database.
+    $node = $this->drupalGetNodeByTitle($edit["title"]);
+    $this->assertTrue($node, t('Node found in database.'));
+
+    // Expected base URI and graph URI.
+    $base_uri = url('', array('absolute' => TRUE));
+    $uri = url('node/' . $node->nid, array('absolute' => TRUE));
+
+    // Get the node as RDF.
+    $g = rdfx_get_rdf_model('node', $node);
+
+    // Inspect the PHP object returned by ARC2.
+    // Test object class.
+    $this->assertTrue(get_class($g) == 'ARC2_Resource', t('Object is of type ARC2_Resource.'));
+    // Test base uri.
+    $this->assertTrue($g->base == $base_uri, t('Base uri set properly by ARC2.'));
+    // Test graph uri.
+    $this->assertTrue($g->uri == $uri, t('Graph uri set properly by ARC2.'));
+
+    // Test if core rdf namespaces are present.
+    // @todo move this into a dedicate test for namespaces.
+    $erroneous_core_ns = FALSE;
+    foreach(rdf_rdf_namespaces() as $prefix => $ns) {
+      if (!isset($g->ns[$prefix]) || $g->ns[$prefix] != $ns) {
+        $erroneous_core_ns = TRUE;
+      }
+    }
+    $this->assertFalse($erroneous_core_ns, t('Core RDF namespaces set properly by ARC2.'));
+
+    // Test RDF types in ARC2 RDF index.
+    $o = array (
+      'value'=> 'http://rdfs.org/sioc/ns#Item',
+      'type'=> 'uri',
+    );
+    $this->assertTrue(in_array($o, $g->index[$uri]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type']), t('sioc:Item type found in ARC2 index.'));
+    $o = array (
+      'value'=> 'http://xmlns.com/foaf/0.1/Document',
+      'type'=> 'uri',
+    );
+    $this->assertTrue(in_array($o, $g->index[$uri]['http://www.w3.org/1999/02/22-rdf-syntax-ns#type']), t('foaf:Document type found in ARC2 index.'));
+
+    // Test title in ARC2 RDF index.
+    $o = array (
+      'value'=> $node->title,
+      'type'=> 'literal',
+      'datatype'=> '',
+    );
+    $this->assertTrue(in_array($o, $g->index[$uri]['http://purl.org/dc/terms/title']), t('dc:title value found in ARC2 index.'));
+
+    // Test date in ARC2 RDF index.
+    $o = array (
+      'value'=> date_iso8601($node->created),
+      'type'=> 'literal',
+      'datatype' => 'xsd:dateTime',
+    );
+    $this->assertTrue(in_array($o, $g->index[$uri]['http://purl.org/dc/terms/date']), t('dc:date value found in ARC2 index.'));
+    $o = array (
+      'value'=> date_iso8601($node->created),
+      'type'=> 'literal',
+      'datatype' => 'xsd:dateTime',
+    );
+    $this->assertTrue(in_array($o, $g->index[$uri]['http://purl.org/dc/terms/created']), t('dc:created value found in ARC2 index.'));
+
+    // Test comment_count in ARC2 RDF index.
+    $o = array (
+      'value'=> $node->comment_count,
+      'type'=> 'literal',
+      'datatype'=> 'xsd:integer',
+    );
+    $this->assertTrue(in_array($o, $g->index[$uri]['http://rdfs.org/sioc/ns#num_replies']), t('sioc:num_replies value found in ARC2 index.'));
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/CHANGELOG.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,104 @@
+References 7.x-2.x
+==================
+
+#1391814 by yched: Fixed encoded HTML entities in select widget (regression
+  introduced in 2.0)
+#1354580 by bforchhammer, yched: Fixed unpublished referenced nodes not
+  displayed to users that are allowed to see them (regression introduced in 2.0)
+#1345816 by bforchhammer: Added support for the 'view_unpublished' module.
+#1256280 by girishmuraly: Added query alterability in hook_field_prepare_view().
+#1183300 by scor: Fixed extraneaous #maxlength in node_reference_autocomplete
+  widget.
+#1410300 by yched: Fixed hook_field_install() should live in .install files.
+#1409022 by yched: Fixed missing view name notification message in D6 migration.
+#1391814 followup by yched: Fixed raw HTML in Views exposed filters.
+#998848 followup by larowlan, stevector, yched: template suggestions for
+  referenced node in a specific view mode are wrong.
+
+References 7.x-2.0
+==================
+
+Note for users upgrading from References 7.x-2.0-beta3:
+There were a couple changes in the way 'References' views are handled
+("referenceable nodes/users defined by a view"), which might require
+double-checking those existing on your site:
+- The 'label' (node title or user name) is no longer automatically added if not
+included in the view. If some of your 'References' views currently do not
+include it, you might want to add it explicitly, else it will no longer appear
+in the widgets.
+- The HTML generated by the view is no longer stripped out before being handed
+to "checkboxes / radios" widgets, thus allowing advanced formatting. You might
+want to check for Reference views having fields configured to display "as
+links", since the (probably unwanted) <a> tags generated by Views are not
+removed anymore.
+
+Note for users upgrading from CCK D6:
+- The Refernces project integrates with the content_migrate module present in
+CCK 7.x-2.x-dev to allow the migration of field definitions and field values
+from D6 nodereference and userreference fields. Field values are safely
+migrated, and a best effort is made for the field definitions, but the settings
+for widgets and formatters might need to be manually checked and adjusted after
+the migration.
+- The "referenceable nodes/users defined by a view" feature is now supported
+through the dedicated 'References' views Display type, as opposed to using the
+'default' display in D6. A temporary backward-compatibility layer is included
+and the existing views should keep working as expected (if they have been
+properly adapted/migrated from D6 themselves), but it is highly recommended to
+edit them and add an explicit 'References' display - submitting the "field
+settings" will lose the currently selected view if it doesn't have a
+'References' display.
+- The remarks in "Note for users upgrading from beta3" above also apply.
+
+#1157530 by yched: Fixed node-specific code in references.module code.
+#1157746 by yched: Fixed 'match' option not working in views.
+#1149600 by dafeder, yched: fix 'Undefined index error' in
+  _[user|node]_reference_view_settings_validate().
+#1045019 by Les Lim, Steven Jones, rickvug, and KarenS: Added devel_generate
+  integration.
+#1230550 by yched: Dispaly a warning about manual Views edits during D6 field
+  migration.
+#1083902 by dereine, derhasi: Added backreference views relationships.
+#1157538 by yched: Enhance previews for 'References' views displays.
+#1094406 by h0tw1r3: Added Account for the 'view own unpublished content' perm
+  when displaying referenced nodes.
+#1183300 by Pasqualle: Remove maxlength from noderef autocomplete widget.
+#1236096 by Dave Reid: fix fatal error on prepare_view (followup to #1094406)
+#1275096 by Scyther, dereine, and jenlampton: Fix column not found error for nid.
+#1275096 by jboese, dereine: Fix column not found error for nid (take 2).
+#1341148 by plach: Fix Check views_access() when using Views to get the potential
+  references.
+#1085576 by henrrrik, stamina, yched: Added "raw ID" and "raw path" formatters.
+#1051624 by Stalski: Added "rendered user in a given view mode" formatter for
+  user_reference fields.
+#988856 by Nephele, johnv, rickmanelius, BlakeLucchesi ... : Added Feeds mapper
+  for node_reference and user_reference fields.
+#1219224 by kunago, michaelfavia, yched: Added support for optgroups in select
+  widget (for referenceable nodes/users provided by a view).
+#1194086 by Dave Reid, mariagwyn, yched: Display entity labels through entity_label()
+  (formatters only for now)
+#1288852 by yched: Fixed "Trying to get property of non-object" with fatal error
+  on user_reference fields using a view (when the view does not include the
+  user name as a field).
+#1378086 by yched: Stop implicitly adding the 'node title / user name' field in
+  Reference views if it is not present in the view definition.
+#1155946 by yched: allow HTML in "checkboxes / radios" widgets (for lists of
+  referenceable targets generated by views).
+#1139238 by wondex, s_leu: Add relevant meta data in the 'potential_references'
+  db query to allow smart alteration.
+
+References 7.x-2.0-beta3
+========================
+
+This release primarily aims at facilitating synchronized releases of 3rd party
+modules making use of the node_reference_potential_references() function.
+
+#1154998 by yched: Rename _node_reference_potential_references() to
+  node_reference_potential_references().
+
+References 7.x-2.0-beta2
+========================
+
+Initial beta release (starting directly at beta2, the beta1 git tag got borched)
+
+Note : If you installed a previous 7.x-2.x dev version, it is recommended to
+clear your sites caches after deploying this release.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+
+-- SUMMARY --
+
+The References project contains straight ports of the node_reference and 
+user_reference modules to the Drupal 7 API.
+
+For a full description of the module, visit the project page:
+  http://drupal.org/project/references
+  
+-- REQUIREMENTS --
+
+None. 
+
+CCK for Drupal 7 is /not/ a requirement for these modules.
+
+-- GOALS AND LIMITATIONS -- 
+  
+It is not envisioned as a final solution, but as a way to actually deploy 
+Drupal 7 from release day on sites using node and user references much as on 
+Drupal 6, until a native entity relationships Drupal 7 module becomes a usable 
+alternative.
+
+As of 2010-11-30, is looks like a candidate for that usable alternative might
+someday be project Relation: 
+  http://drupal.org/project/relation
+
+In short: use these modules now, but be ready to migrate to a different entity
+referencing solution during the D7 life cycle.
+
+-- CONTACT --
+
+Current maintainers:
+
+* References: Frederic G. MARAND (fgm) - http://drupal.org/user/27985
+* CCK D7: Yves CHEDEMOIS (yched) - http://drupal.org/user/39567
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/node_reference/node_reference.devel_generate.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,22 @@
+<?php
+// $Id: nodereference.devel_generate.inc,v 1.1 2010/01/28 21:06:42 weitzman Exp $
+
+function node_reference_devel_generate($object, $field, $instance, $bundle) {
+  if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
+    return devel_generate_multiple('_node_reference_devel_generate', $object, $field, $instance, $bundle);
+  }
+  else {
+    return _node_reference_devel_generate($object, $field, $instance, $bundle);
+  }
+}
+
+function _node_reference_devel_generate($object, $field, $instance, $bundle) {
+  $object_field = array();
+  $allowed_values = node_reference_potential_references($field);
+  // unset($allowed_values[0]);
+  if (!empty($allowed_values)) {
+    // Just pick one of the specified allowed values.
+    $object_field['nid'] = array_rand($allowed_values);
+  }
+  return $object_field;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/node_reference/node_reference.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+name = Node Reference
+description = Defines a field type for referencing one node from another.
+package = Fields
+core = 7.x
+dependencies[] = field
+dependencies[] = references
+dependencies[] = options
+files[] = node_reference.test
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-2.1"
+core = "7.x"
+project = "references"
+datestamp = "1360265821"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/node_reference/node_reference.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the node_reference module.
+ */
+
+/**
+ * Implements hook_field_schema().
+ */
+function node_reference_field_schema($field) {
+  $columns = array(
+    'nid' => array(
+      'type'     => 'int',
+      'unsigned' => TRUE,
+      'not null' => FALSE,
+    ),
+  );
+  return array(
+    'columns' => $columns,
+    'indexes' => array('nid' => array('nid')),
+    'foreign keys' => array(
+      'nid' => array(
+        'table' => 'node',
+        'columns' => array('nid' => 'nid'),
+      ),
+    ),
+  );
+}
+
+/**
+ * Rebuild views data cache (a callabck was renamed).
+ */
+function node_reference_update_7000() {
+  if (function_exists('views_invalidate_cache')) {
+    views_invalidate_cache();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/node_reference/node_reference.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1200 @@
+<?php
+
+/**
+ * @file
+ * Defines a field type for referencing one node from another.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function node_reference_menu() {
+  $items['node_reference/autocomplete/%/%/%'] = array(
+    'page callback' => 'node_reference_autocomplete',
+    'page arguments' => array(2, 3, 4),
+    'access callback' => 'reference_autocomplete_access',
+    'access arguments' => array(2, 3, 4),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_field_info().
+ */
+function node_reference_field_info() {
+  return array(
+    'node_reference' => array(
+      'label'             => t('Node reference'),
+      'description'       => t('This field stores the ID of a related node as an integer value.'),
+      'settings'          => array(
+        'referenceable_types' => array(),
+        'view' => array(
+          'view_name' => '',
+          'display_name' => '',
+          'args' => array(),
+        ),
+      ),
+      // It probably make more sense to have the referenceable types be per-field than per-instance
+      // 'instance settings' => array('referenceable_types' => array()),
+      'default_widget'    => 'options_select', //  node_reference_autocomplete',
+      'default_formatter' => 'node_reference_default',
+      // Support hook_entity_property_info() from contrib "Entity API".
+      'property_type' => 'node',
+      // Support default token formatter for field tokens.
+      'default_token_formatter' => 'node_reference_plain',
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function node_reference_field_settings_form($field, $instance, $has_data) {
+  $settings = $field['settings'];
+
+  $form = array();
+  $form['referenceable_types'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Content types that can be referenced'),
+    '#multiple' => TRUE,
+    '#default_value' => $settings['referenceable_types'],
+    '#options' => array_map('check_plain', node_type_get_names()),
+  );
+
+  if (module_exists('views')) {
+    $view_settings = $settings['view'];
+
+    $description = '<p>' . t('The list of nodes that can be referenced can provided by a view (Views module) using the "References" display type.') . '</p>';
+
+    // Special note for legacy fields migrated from D6.
+    if (!empty($view_settings['view_name']) && $view_settings['display_name'] == 'default') {
+      $description .= '<p><strong><span class="admin-missing">'. t("Important D6 migration note:") . '</span></strong>';
+      $description .= '<br/>' . t("The field is currently configured to use the 'Master' display of the view %view_name.", array('%view_name' => $view_settings['view_name']));
+      $description .= '<br/>' . t("It is highly recommended that you: <br/>- edit this view and create a new display using the 'References' display type, <br/>- update the field settings to explicitly select the correct view and display.");
+      $description .= '<br/>' . t("The field will work correctly until then, but submitting this form might inadvertently change the field settings.") . '</p>';
+    }
+
+    $form['view'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Views - Nodes that can be referenced'),
+      '#collapsible' => TRUE,
+      '#collapsed' => empty($view_settings['view_name']),
+      '#description' => $description,
+    );
+
+    $views_options = references_get_views_options('node');
+    if ($views_options) {
+      // The value of the 'view_and_display' select below will need to be split
+      // into 'view_name' and 'view_display' in the final submitted values, so
+      // we massage the data at validate time on the wrapping element (not
+      // ideal).
+      $form['view']['#element_validate'] = array('_node_reference_view_settings_validate');
+
+      $views_options = array('' => '<' . t('none') . '>') + $views_options;
+      $default = empty($view_settings['view_name']) ? '' : $view_settings['view_name'] . ':' .$view_settings['display_name'];
+      $form['view']['view_and_display'] = array(
+        '#type' => 'select',
+        '#title' => t('View used to select the nodes'),
+        '#options' => $views_options,
+        '#default_value' => $default,
+        '#description' => '<p>' . t('Choose the view and display that select the nodes that can be referenced.<br />Only views with a display of type "References" are eligible.') . '</p>' .
+          t('Note:<ul><li>This will discard the "Content types" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate nodes on node creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate nodes will be displayed.</li></ul>'),
+      );
+
+      $default = implode(', ', $view_settings['args']);
+      $form['view']['args'] = array(
+        '#type' => 'textfield',
+        '#title' => t('View arguments'),
+        '#default_value' => $default,
+        '#required' => FALSE,
+        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+      );
+    }
+    else {
+      $form['view']['no_view_help'] = array(
+        '#markup' => '<p>' . t('No eligible view was found.') .'</p>',
+      );
+    }
+  }
+
+  return $form;
+}
+
+/**
+ * Validate callback for the 'view settings' fieldset.
+ *
+ * Puts back the various form values in the expected shape.
+ */
+function _node_reference_view_settings_validate($element, &$form_state, $form) {
+  // Split view name and display name from the 'view_and_display' value.
+  if (!empty($element['view_and_display']['#value'])) {
+    list($view, $display) = explode(':', $element['view_and_display']['#value']);
+  }
+  else {
+    $view = '';
+    $display = '';
+  }
+
+  // Explode the 'args' string into an actual array. Beware, explode() turns an
+  // empty string into an array with one empty string. We'll need an empty array
+  // instead.
+  $args_string = trim($element['args']['#value']);
+  $args = ($args_string === '') ? array() : array_map('trim', explode(',', $args_string));
+
+  $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Implements hook_field_validate().
+ *
+ * Possible error codes:
+ * - 'invalid_nid': nid is not valid for the field (not a valid node id, or the node is not referenceable).
+ */
+function node_reference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  // Extract nids to check.
+  $ids = array();
+
+  // First check non-numeric "nid's to avoid losing time with them.
+  foreach ($items as $delta => $item) {
+    if (is_array($item) && !empty($item['nid'])) {
+      if (is_numeric($item['nid'])) {
+        $ids[] = $item['nid'];
+      }
+      else {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'invalid_nid',
+          'message' => t("%name: invalid input.",
+            array('%name' => $instance['label'])),
+        );
+      }
+    }
+  }
+  // Prevent performance hog if there are no ids to check.
+  if ($ids) {
+    $options = array(
+      'ids' => $ids,
+    );
+    $refs = node_reference_potential_references($field, $options);
+    foreach ($items as $delta => $item) {
+      if (is_array($item)) {
+        if (!empty($item['nid']) && !isset($refs[$item['nid']])) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'invalid_nid',
+            'message' => t("%name: this post can't be referenced.",
+              array('%name' => $instance['label'])),
+          );
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_prepare_view().
+ */
+function node_reference_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  $checked_ids = &drupal_static(__FUNCTION__, array());
+
+  // Set an 'access' property on each item (TRUE if the node exists and is
+  // accessible by the current user).
+
+  // Extract ids to check.
+  $ids = array();
+  foreach ($items as $id => $entity_items) {
+    foreach ($entity_items as $delta => $item) {
+      if (is_array($item)) {
+        // Default to 'not accessible'.
+        $items[$id][$delta]['access'] = FALSE;
+        if (!empty($item['nid']) && is_numeric($item['nid'])) {
+          $ids[$item['nid']] = $item['nid'];
+        }
+      }
+    }
+  }
+
+  if ($ids) {
+    // Load information about ids that we haven't already loaded during this
+    // page request.
+    $ids_to_check = array_diff($ids, array_keys($checked_ids));
+    if (!empty($ids_to_check)) {
+      $query = db_select('node', 'n')
+        ->addTag('node_access')
+        ->addMetaData('id', 'node_reference_field_prepare_view')
+        ->addMetaData('field', $field)
+        ->fields('n', array('nid'))
+        // WHERE n.nid IN (nids to check) AND ...
+        ->condition('n.nid', $ids_to_check, 'IN');
+
+      // Unless the user has the right permissions, restrict on the node status.
+      // (note: the 'view any unpublished content' permission is provided by the
+      // 'view_unpublished' contrib module.)
+      if (!user_access('bypass node access') && !user_access('view any unpublished content')) {
+        // ... AND n.status = 1
+        $status_condition = db_or()
+          ->condition('n.status', NODE_PUBLISHED);
+
+        // Take the 'view own unpublished content' permission into account to
+        // decide whether some unpublished nodes should still be visible.
+        if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT nid FROM {node} WHERE uid = :uid AND status = :status', array(':uid' => $GLOBALS['user']->uid, ':status' => NODE_NOT_PUBLISHED))->fetchCol()) {
+          // ... AND (n.status = 1 OR n.nid IN (own unpublished))
+          $status_condition
+            ->condition('n.nid', $own_unpublished, 'IN');
+        }
+
+        $query->condition($status_condition);
+      }
+
+      $accessible_ids = $query->execute()->fetchAllAssoc('nid');
+
+      // Populate our static list so that we do not query on those ids again.
+      foreach ($ids_to_check as $id) {
+        $checked_ids[$id] = isset($accessible_ids[$id]);
+      }
+    }
+
+    foreach ($items as $id => $entity_items) {
+      foreach ($entity_items as $delta => $item) {
+        if (is_array($item) && !empty($item['nid']) && !empty($checked_ids[$item['nid']])) {
+          $items[$id][$delta]['access'] = TRUE;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function node_reference_field_is_empty($item, $field) {
+  // nid = 0 is empty too, which is exactly what we want.
+  return empty($item['nid']);
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function node_reference_field_formatter_info() {
+  $ret = array(
+    'node_reference_default' => array(
+      'label' => t('Title (link)'),
+      'description' => t('Display the title of the referenced node as a link to the node page.'),
+      'field types' => array('node_reference'),
+    ),
+    'node_reference_plain' => array(
+      'label' => t('Title (no link)'),
+      'description' => t('Display the title of the referenced node as plain text.'),
+      'field types' => array('node_reference'),
+    ),
+    'node_reference_node' => array(
+      'label' => t('Rendered node'),
+      'description' => t('Display the referenced node in a specific view mode'),
+      'field types' => array('node_reference'),
+      'settings' => array('node_reference_view_mode' => 'full'),
+    ),
+    'node_reference_nid' => array(
+      'label' => t('Node ID'),
+      'description' => t('Display the referenced node ID'),
+      'field types' => array('node_reference'),
+    ),
+    'node_reference_path' => array(
+      'label' => t('URL as plain text'),
+      'description' => t('Display the URL of the referenced node'),
+      'field types' => array('node_reference'),
+      'settings' => array(
+        'alias' => TRUE,
+        'absolute' => FALSE
+      ),
+    ),
+  );
+  return $ret;
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function node_reference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $element = array();
+
+  switch ($display['type']) {
+    case 'node_reference_node':
+      $entity_info = entity_get_info('node');
+      $modes = $entity_info['view modes'];
+      $options = array();
+      foreach ($modes as $name => $mode) {
+        $options[$name] = $mode['label'];
+      }
+      $element['node_reference_view_mode'] = array(
+        '#title' => t('View mode'),
+        '#type' => 'select',
+        '#options' => $options,
+        '#default_value' => $settings['node_reference_view_mode'],
+        // Never empty, so no #empty_option
+      );
+      break;
+
+    case 'node_reference_path':
+      $element['alias'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Display the aliased path (if exists) instead of the system path'),
+        '#default_value' => $settings['alias'],
+      );
+      $element['absolute'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Display an absolute URL'),
+        '#default_value' => $settings['absolute'],
+      );
+      break;
+  }
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function node_reference_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $summary = array();
+
+  switch ($display['type']) {
+    case 'node_reference_node':
+      $entity_info = entity_get_info('node');
+      $modes = $entity_info['view modes'];
+      $mode = $modes[$settings['node_reference_view_mode']]['label'];
+      $summary[] = t('View mode: %mode', array('%mode' => $mode));
+      break;
+
+    case 'node_reference_path':
+      $summary[] = t('Aliased path: %yes_no', array('%yes_no' => $settings['alias'] ? t('Yes') : t('No')));
+      $summary[] = t('Absolute URL: %yes_no', array('%yes_no' => $settings['absolute'] ? t('Yes') : t('No')));
+      break;
+  }
+
+  return implode('<br />', $summary);
+}
+
+/**
+ * Implements hook_field_formatter_prepare_view().
+ *
+ * Preload all nodes referenced by items using 'full entity' formatters.
+ */
+function node_reference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
+  // Load the referenced nodes, except for the 'node_reference_nid' which does
+  // not need full objects.
+
+  // Collect ids to load.
+  $ids = array();
+  foreach ($displays as $id => $display) {
+    if ($display['type'] != 'node_reference_nid') {
+      foreach ($items[$id] as $delta => $item) {
+        if ($item['access']) {
+          $ids[$item['nid']] = $item['nid'];
+        }
+      }
+    }
+  }
+  $entities = node_load_multiple($ids);
+
+  // Add the loaded nodes to the items.
+  foreach ($displays as $id => $display) {
+    if ($display['type'] != 'node_reference_nid') {
+      foreach ($items[$id] as $delta => $item) {
+        if ($item['access']) {
+          $items[$id][$delta]['node'] = $entities[$item['nid']];
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function node_reference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $settings = $display['settings'];
+  $result = array();
+
+  switch ($display['type']) {
+    case 'node_reference_default':
+    case 'node_reference_plain':
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          $node = $item['node'];
+          $label = entity_label('node', $node);
+          if ($display['type'] == 'node_reference_default') {
+            $uri = entity_uri('node', $node);
+            $result[$delta] = array(
+              '#type' => 'link',
+              '#title' => $label,
+              '#href' => $uri['path'],
+              '#options' => $uri['options'],
+            );
+          }
+          else {
+            $result[$delta] = array(
+              '#markup' => check_plain($label),
+            );
+          }
+          if (!$node->status) {
+            $result[$delta]['#prefix'] = '<span class="node-unpublished">';
+            $result[$delta]['#suffix'] = '</span>';
+          }
+        }
+      }
+      break;
+
+    case 'node_reference_node':
+      // To prevent infinite recursion caused by reference cycles, we store
+      // diplayed nodes in a recursion queue.
+      $recursion_queue = &drupal_static(__FUNCTION__, array());
+
+      // If no 'referencing entity' is set, we are starting a new 'reference
+      // thread' and need to reset the queue.
+      // @todo Bug: $entity->referencing_entity on nodes referenced in a different
+      // thread on the page. E.g: 1 references 1+2 / 2 references 1+2 / visit homepage.
+      // We'd need a more accurate way...
+      if (!isset($entity->referencing_entity)) {
+        $recursion_queue = array();
+      }
+
+      // The recursion queue only needs to track nodes.
+      if ($entity_type == 'node') {
+        list($id) = entity_extract_ids($entity_type, $entity);
+        $recursion_queue[$id] = $id;
+      }
+
+      // Check the recursion queue to determine which nodes should be fully
+      // displayed, and which nodes will only be displayed as a title.
+      $nodes_display = array();
+      foreach ($items as $delta => $item) {
+        if ($item['access'] && !isset($recursion_queue[$item['nid']])) {
+          $nodes_display[$item['nid']] = $item['node'];
+        }
+      }
+
+      // Load and build the fully displayed nodes.
+      if ($nodes_display) {
+        foreach ($nodes_display as $nid => $node) {
+          $nodes_display[$nid]->referencing_entity = $entity;
+          $nodes_display[$nid]->referencing_field = $field['field_name'];
+        }
+        $nodes_built = node_view_multiple($nodes_display, $settings['node_reference_view_mode']);
+      }
+
+      // Assemble the render array.
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          if (isset($nodes_display[$item['nid']])) {
+            $result[$delta] = $nodes_built['nodes'][$item['nid']];
+          }
+          else {
+            $node = $item['node'];
+            $label = entity_label('node', $node);
+            $uri = entity_uri('node', $node);
+            $result[$delta] = array(
+              '#type' => 'link',
+              '#title' => $label,
+              '#href' => $uri['path'],
+              '#options' => $uri['options'],
+            );
+            if (!$node->status) {
+              $result[$delta]['#prefix'] = '<span class="node-unpublished">';
+              $result[$delta]['#suffix'] = '</span>';
+            }
+          }
+        }
+      }
+      break;
+
+    case 'node_reference_nid':
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          $result[$delta] = array(
+            '#markup' => $item['nid'],
+          );
+        }
+      }
+      break;
+
+    case 'node_reference_path':
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          $uri = entity_uri('node', $item['node']);
+          $options = array(
+            'absolute' => $settings['absolute'],
+            'alias' => !$settings['alias'],
+          );
+
+          $options += $uri['options'];
+          $result[$delta] = array(
+            '#markup' => url($uri['path'], $options),
+          );
+        }
+      }
+      break;
+  }
+
+  return $result;
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function node_reference_field_widget_info() {
+  return array(
+    'node_reference_autocomplete' => array(
+      'label'       => t('Autocomplete text field'),
+      'description' => t('Display the list of referenceable nodes as a textfield with autocomplete behaviour.'),
+      'field types' => array('node_reference'),
+      'settings'    => array(
+        'autocomplete_match' => 'contains',
+        'size' => 60,
+        'autocomplete_path' => 'node_reference/autocomplete',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_widget_info_alter().
+ */
+function node_reference_field_widget_info_alter(&$info) {
+  $info['options_select']['field types'][] = 'node_reference';
+  $info['options_buttons']['field types'][] = 'node_reference';
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function node_reference_field_widget_settings_form($field, $instance) {
+  $widget   = $instance['widget'];
+  $defaults = field_info_widget_settings($widget['type']);
+  $settings = array_merge($defaults, $widget['settings']);
+
+  $form = array();
+  if ($widget['type'] == 'node_reference_autocomplete') {
+    $form['autocomplete_match'] = array(
+      '#type'             => 'select',
+      '#title'            => t('Autocomplete matching'),
+      '#default_value'    => $settings['autocomplete_match'],
+      '#options'          => array(
+        'starts_with'     => t('Starts with'),
+        'contains'        => t('Contains'),
+      ),
+      '#description'      => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
+    );
+    $form['size'] = array(
+      '#type'             => 'textfield',
+      '#title'            => t('Size of textfield'),
+      '#default_value'    => $settings['size'],
+      '#element_validate' => array('_element_validate_integer_positive'),
+      '#required'         => TRUE,
+    );
+  }
+  return $form;
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function node_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  switch ($instance['widget']['type']) {
+    case 'node_reference_autocomplete':
+      $element += array(
+        '#type' => 'textfield',
+        '#default_value' => isset($items[$delta]['nid']) ? $items[$delta]['nid'] : NULL,
+        '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
+        '#size' => $instance['widget']['settings']['size'],
+        '#maxlength' => NULL,
+        '#element_validate' => array('node_reference_autocomplete_validate'),
+        '#value_callback' => 'node_reference_autocomplete_value',
+      );
+      break;
+  }
+
+  return array('nid' => $element);
+}
+
+/**
+ * Value callback for a node_reference autocomplete element.
+ *
+ * Replace the node nid with a node title.
+ */
+function node_reference_autocomplete_value($element, $input = FALSE, $form_state) {
+  if ($input === FALSE) {
+    // We're building the displayed 'default value': expand the raw nid into
+    // "node title [nid:n]".
+    $nid = $element['#default_value'];
+    if (!empty($nid)) {
+      $q = db_select('node', 'n');
+      $node_title_alias = $q->addField('n', 'title');
+      $q->addTag('node_access')
+        ->condition('n.nid', $nid)
+        ->range(0, 1);
+      $result = $q->execute();
+      // @todo If no result (node doesn't exist or no access).
+      $value = $result->fetchField();
+      $value .= ' [nid:' . $nid . ']';
+      return $value;
+    }
+  }
+}
+
+/**
+ * Validation callback for a node_reference autocomplete element.
+ */
+function node_reference_autocomplete_validate($element, &$form_state, $form) {
+  $field = field_widget_field($element, $form_state);
+  $instance = field_widget_instance($element, $form_state);
+
+  $value = $element['#value'];
+  $nid = NULL;
+
+  if (!empty($value)) {
+    // Check whether we have an explicit "[nid:n]" input.
+    preg_match('/^(?:\s*|(.*) )?\[\s*nid\s*:\s*(\d+)\s*\]$/', $value, $matches);
+    if (!empty($matches)) {
+      // Explicit nid. Check that the 'title' part matches the actual title for
+      // the nid.
+      list(, $title, $nid) = $matches;
+      if (!empty($title)) {
+        $real_title = db_select('node', 'n')
+          ->fields('n', array('title'))
+          ->condition('n.nid', $nid)
+          ->execute()
+          ->fetchField();
+        if (trim($title) != trim($real_title)) {
+          form_error($element, t('%name: title mismatch. Please check your selection.', array('%name' => $instance['label'])));
+        }
+      }
+    }
+    else {
+      // No explicit nid (the submitted value was not populated by autocomplete
+      // selection). Get the nid of a referencable node from the entered title.
+      $options = array(
+        'string' => $value,
+        'match' => 'equals',
+        'limit' => 1,
+      );
+      $references = node_reference_potential_references($field, $options);
+      if ($references) {
+        // @todo The best thing would be to present the user with an
+        // additional form, allowing the user to choose between valid
+        // candidates with the same title. ATM, we pick the first
+        // matching candidate...
+        $nid = key($references);
+      }
+      else {
+        form_error($element, t('%name: found no valid post with that title.', array('%name' => $instance['label'])));
+      }
+    }
+  }
+
+  // Set the element's value as the node id that was extracted from the entered
+  // input.
+  form_set_value($element, $nid, $form_state);
+}
+
+/**
+ * Implements hook_field_widget_error().
+ */
+function node_reference_field_widget_error($element, $error, $form, &$form_state) {
+  form_error($element['nid'], $error['message']);
+}
+
+/**
+ * Builds a list of referenceable nodes suitable for the '#option' FAPI property.
+ *
+ * Warning: the function does NOT take care of encoding or escaping the node
+ * titles. Proper massaging needs to be performed by the caller, according to
+ * the destination FAPI '#type' (radios / checkboxes / select).
+ *
+ * @param $field
+ *   The field definition.
+ * @param $flat
+ *   Whether optgroups are allowed.
+ *
+ * @return
+ *   An array of referenceable node titles, keyed by node id. If the $flat
+ *   parameter is TRUE, the list might be nested by optgroup first.
+ */
+function _node_reference_options($field, $flat = TRUE) {
+  $references = node_reference_potential_references($field);
+
+  $options = array();
+  foreach ($references as $key => $value) {
+    // The label, displayed in selects and checkboxes/radios, should have HTML
+    // entities unencoded. The widgets (core's options.module) take care of
+    // applying the relevant filters (strip_tags() or filter_xss()).
+    $label = html_entity_decode($value['rendered'], ENT_QUOTES);
+    if (empty($value['group']) || $flat) {
+      $options[$key] = $label;
+    }
+    else {
+      // The group name, displayed in selects, cannot contain tags, and should
+      // have HTML entities unencoded.
+      $group = html_entity_decode(strip_tags($value['group']), ENT_QUOTES);
+      $options[$group][$key] = $label;
+    }
+  }
+
+  return $options;
+}
+
+/**
+ * Retrieves an array of candidate referenceable nodes.
+ *
+ * This info is used in various places (allowed values, autocomplete
+ * results, input validation...). Some of them only need the nids,
+ * others nid + titles, others yet nid + titles + rendered row (for
+ * display in widgets).
+ *
+ * The array we return contains all the potentially needed information,
+ * and lets consumers use the parts they actually need.
+ *
+ * @param $field
+ *   The field definition.
+ * @param $options
+ *   An array of options to limit the scope of the returned list. The following
+ *   key/value pairs are accepted:
+ *   - string: string to filter titles on (used by autocomplete).
+ *   - match: operator to match the above string against, can be any of:
+ *     'contains', 'equals', 'starts_with'. Defaults to 'contains'.
+ *   - ids: array of specific node ids to lookup.
+ *   - limit: maximum size of the the result set. Defaults to 0 (no limit).
+ *
+ * @return
+ *   An array of valid nodes in the form:
+ *   array(
+ *     nid => array(
+ *       'title' => The node title,
+ *       'rendered' => The text to display in widgets (can be HTML)
+ *     ),
+ *     ...
+ *   )
+ */
+function node_reference_potential_references($field, $options = array()) {
+  // Fill in default options.
+  $options += array(
+    'string' => '',
+    'match' => 'contains',
+    'ids' => array(),
+    'limit' => 0,
+  );
+
+  $results = &drupal_static(__FUNCTION__, array());
+
+  // Create unique id for static cache.
+  $cid = $field['field_name'] . ':' . $options['match'] . ':'
+    . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids']))
+    . ':' . $options['limit'];
+  if (!isset($results[$cid])) {
+    $references = FALSE;
+    if (module_exists('views') && !empty($field['settings']['view']['view_name'])) {
+      $references = _node_reference_potential_references_views($field, $options);
+    }
+
+    if ($references === FALSE) {
+      $references = _node_reference_potential_references_standard($field, $options);
+    }
+
+    // Store the results.
+    $results[$cid] = !empty($references) ? $references : array();
+  }
+
+  return $results[$cid];
+}
+
+/**
+ * Helper function for node_reference_potential_references().
+ *
+ * Case of Views-defined referenceable nodes.
+ */
+function _node_reference_potential_references_views($field, $options) {
+  $settings = $field['settings']['view'];
+  $options['title_field'] = 'title';
+  return references_potential_references_view('node', $settings['view_name'], $settings['display_name'], $settings['args'], $options);
+}
+
+/**
+ * Helper function for node_reference_potential_references().
+ *
+ * List of referenceable nodes defined by content types.
+ */
+function _node_reference_potential_references_standard($field, $options) {
+  // Avoid useless work
+  if (!count($field['settings']['referenceable_types'])) {
+    return array();
+  }
+
+  $query = db_select('node', 'n');
+  $node_nid_alias   = $query->addField('n', 'nid');
+  $node_title_alias = $query->addField('n', 'title', 'node_title');
+  $node_type_alias  = $query->addField('n', 'type',  'node_type');
+  $query->addTag('node_access')
+    ->addMetaData('id', ' _node_reference_potential_references_standard')
+    ->addMetaData('field', $field)
+    ->addMetaData('options', $options);
+
+  if (is_array($field['settings']['referenceable_types'])) {
+    $query->condition('n.type', $field['settings']['referenceable_types'], 'IN');
+  }
+
+  if ($options['string'] !== '') {
+    switch ($options['match']) {
+      case 'contains':
+        $query->condition('n.title', '%' . $options['string'] . '%', 'LIKE');
+        break;
+
+      case 'starts_with':
+        $query->condition('n.title', $options['string'] . '%', 'LIKE');
+        break;
+
+      case 'equals':
+      default: // no match type or incorrect match type: use "="
+        $query->condition('n.title', $options['string']);
+        break;
+    }
+  }
+
+  if ($options['ids']) {
+    $query->condition('n.nid', $options['ids'], 'IN');
+  }
+
+  if ($options['limit']) {
+    $query->range(0, $options['limit']);
+  }
+
+  $query
+    ->orderBy($node_title_alias)
+    ->orderBy($node_type_alias);
+
+  $result = $query->execute()->fetchAll();
+  $references = array();
+  foreach ($result as $node) {
+    $references[$node->nid] = array(
+      'title'    => $node->node_title,
+      'rendered' => check_plain($node->node_title),
+    );
+  }
+  return $references;
+}
+
+/**
+ * Menu callback for the autocomplete results.
+ */
+function node_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
+  $field = field_info_field($field_name);
+  $instance = field_info_instance($entity_type, $field_name, $bundle);
+
+  $options = array(
+    'string' => $string,
+    'match' => $instance['widget']['settings']['autocomplete_match'],
+    'limit' => 10,
+  );
+  $references = node_reference_potential_references($field, $options);
+
+  $matches = array();
+  foreach ($references as $id => $row) {
+    // Markup is fine in autocompletion results (might happen when rendered
+    // through Views) but we want to remove hyperlinks.
+    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
+    // Add a class wrapper for a few required CSS overrides.
+    $matches[$row['title'] . " [nid:$id]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
+  }
+
+  drupal_json_output($matches);
+}
+
+/**
+ * Implements hook_node_type_update().
+ *
+ * Reflect type name changes to the 'referenceable types' settings: when
+ * the name of a type changes, the change needs to be reflected in the
+ * "referenceable types" setting for any node_reference field
+ * referencing it.
+ */
+function node_reference_node_type_update($info) {
+  if (!empty($info->old_type) && $info->old_type != $info->type) {
+    $fields = field_info_fields();
+    foreach ($fields as $field_name => $field) {
+      if ($field['type'] == 'node_reference' && isset($field['settings']['referenceable_types'][$info->old_type])) {
+        $field['settings']['referenceable_types'][$info->type] = empty($field['settings']['referenceable_types'][$info->old_type]) ? 0 : $info->type;
+        unset($field['settings']['referenceable_types'][$info->old_type]);
+        field_update_field($field);
+      }
+    }
+  }
+}
+
+/**
+ * Theme preprocess function.
+ *
+ * Allows specific node templates for nodes displayed as values of a
+ * node_reference field with a specific view mode.
+ */
+function node_reference_preprocess_node(&$vars) {
+  // The 'referencing_field' attribute of the node is added by the
+  // node_reference_node mode formatter (display referenced node
+  // in a specific view mode).
+  if (!empty($vars['node']->referencing_field)) {
+    $node = $vars['node'];
+    $field_name = $node->referencing_field;
+    $vars['theme_hook_suggestions'][] = 'node__node_reference';
+    $vars['theme_hook_suggestions'][] = 'node__node_reference__' . $field_name;
+    $vars['theme_hook_suggestions'][] = 'node__node_reference__' . $node->type;
+    $vars['theme_hook_suggestions'][] = 'node__node_reference__' . $field_name . '__' . $node->type;
+  }
+}
+
+/**
+ * Implements hook_field_prepare_translation().
+ *
+ * When preparing a translation, load any translations of existing
+ * references.
+ */
+function node_reference_field_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
+  if (isset($items) && is_array($items)) {
+    // Match each reference with its matching translation, if it exists.
+    foreach ($items as $key => $item) {
+      $reference_node = node_load($item['nid']);
+      $items[$key]['nid'] = node_reference_find_translation($reference_node, $entity->language);
+    }
+  }
+}
+
+/**
+ * Find a translation for a specific node reference, if it exists.
+ *
+ * @param $reference_node
+ *   The untranslated node reference.
+ * @param $langcode
+ *
+ * @return
+ *   A nid for the translation of the node reference,
+ *   otherwise the original untranslated nid if no translation exists.
+ */
+function node_reference_find_translation($reference_node, $langcode) {
+  // Check if the source node translation is set and if translations are supported.
+  if (isset($reference_node->tnid) && translation_supported_type($reference_node->type)) {
+    // Determine whether an alternative language is being used.
+    if (!empty($reference_node->language) && $reference_node->language != $langcode) {
+      // Return a corresponding translation nid for the reference (if it exists).
+      $translations = translation_node_get_translations($reference_node->tnid);
+      if (isset($translations[$langcode])) {
+        return $translations[$langcode]->nid;
+      }
+    }
+  }
+  // Return the untranslated reference nid, no matching translations found.
+  return $reference_node->nid;
+}
+
+/**
+ * Implements hook_options_list().
+ */
+function node_reference_options_list($field) {
+  return _node_reference_options($field, FALSE);
+}
+
+/**
+ * Implements hook_content_migrate_field_alter().
+ *
+ * Use this to tweak the conversion of field settings from the D6 style to the
+ * D7 style for specific situations not handled by basic conversion, as when
+ * field types or settings are changed.
+ *
+ * $field_value['widget_type'] is available to
+ * see what widget type was originally used.
+ */
+function node_reference_content_migrate_field_alter(&$field_value, $instance_value) {
+  switch ($field_value['module']) {
+    case 'nodereference':
+      $field_value['module'] = 'node_reference';
+      $field_value['type'] = 'node_reference';
+
+      // Translate 'view' settings.
+      $view_name = isset($field_value['settings']['advanced_view']) ? $field_value['settings']['advanced_view'] : '';
+      $view_args = isset($field_value['settings']['advanced_view_args']) ? $field_value['settings']['advanced_view_args'] : '';
+      $view_args = array_map('trim', explode(',', $view_args));
+      $field_value['settings']['view'] = array(
+        'view_name' => $view_name,
+        'display_name' => 'default',
+        'args' => $view_args,
+      );
+      if ($view_name) {
+        $field_value['messages'][] = t("The field uses the view @view_name to determine referenceable nodes. You will need to manually edit the view and add a display of type 'References'.", array('@view_name' => $view_name));
+      }
+      unset($field_value['settings']['advanced_view']);
+      unset($field_value['settings']['advanced_view_args']);
+
+      break;
+  }
+}
+
+/**
+ * Implements hook_content_migrate_instance_alter().
+ *
+ * Use this to tweak the conversion of instance or widget settings from the D6
+ * style to the D7 style for specific situations not handled by basic
+ * conversion, as when formatter or widget names or settings are changed.
+ */
+function node_reference_content_migrate_instance_alter(&$instance_value, $field_value) {
+  switch ($field_value['type']) {
+    case 'nodereference':
+      // Massage formatters.
+      foreach ($instance_value['display'] as $context => &$display) {
+        switch ($display['type']) {
+          case 'full':
+          case 'teaser':
+            // Those two formatters have been merged into
+            // 'node_reference_view_mode', with a formatter setting.
+            $display['type'] = 'node_reference_node';
+            $display['settings']['node_reference_view_mode'] = $display['type'];
+            break;
+
+          default:
+            // The formatter names changed, all are prefixed with
+            // 'node_reference_'.
+            $display['type'] = 'node_reference_' . $display['type'];
+            break;
+        }
+      }
+      // Massage the widget.
+      switch ($instance_value['widget']['type']) {
+        case 'nodereference_autocomplete':
+          $instance_value['widget']['type'] = 'node_reference_autocomplete';
+          $instance_value['widget']['module'] = 'node_reference';
+          break;
+        case 'nodereference_select':
+          $instance_value['widget']['type'] = 'options_select';
+          $instance_value['widget']['module'] = 'options';
+          break;
+        case 'nodereference_buttons':
+          $instance_value['widget']['type'] = 'options_buttons';
+          $instance_value['widget']['module'] = 'options';
+      }
+      break;
+  }
+}
+
+/**
+ * Implements hook_field_views_data().
+ *
+ * In addition to the default field information we add the relationship for
+ * views to connect back to the node table.
+ */
+function node_reference_field_views_data($field) {
+  // No module_load_include(): this hook is invoked from
+  // views/modules/field.views.inc, which is where that function is defined.
+  $data = field_views_field_default_views_data($field);
+
+  $storage = $field['storage']['details']['sql'];
+
+  foreach ($storage as $age => $table_data) {
+    $table = key($table_data);
+    $columns = current($table_data);
+    $id_column = $columns['nid'];
+    if (isset($data[$table])) {
+      // Filter: swap the handler to the 'in' operator. The callback receives
+      // the field name instead of the whole $field structure to keep views
+      // data to a reasonable size.
+      $data[$table][$id_column]['filter']['handler'] = 'views_handler_filter_in_operator';
+      $data[$table][$id_column]['filter']['options callback'] = 'node_reference_views_filter_options';
+      $data[$table][$id_column]['filter']['options arguments'] = array($field['field_name']);
+
+      // Argument: display node.title in argument titles (handled in our custom
+      // handler) and summary lists (handled by the base views_handler_argument
+      // handler).
+      // Both mechanisms rely on the 'name table' and 'name field' information
+      // below, by joining to a separate copy of the base table from the field
+      // data table.
+      $data[$table][$id_column]['argument']['handler'] = 'references_handler_argument';
+      $data[$table][$id_column]['argument']['name table'] = $table . '_reference';
+      $data[$table][$id_column]['argument']['name field'] = 'title';
+      $data[$table . '_reference']['table']['join'][$table] = array(
+        'left_field' => $id_column,
+        'table' => 'node',
+        'field' => 'nid',
+      );
+
+      // Relationship.
+      $data[$table][$id_column]['relationship'] = array(
+        'handler' => 'references_handler_relationship',
+        'base' => 'node',
+        'base field' => 'nid',
+        'field' => $id_column,
+        'label' => $field['field_name'],
+        'field_name' => $field['field_name'],
+      );
+    }
+  }
+
+  return $data;
+}
+
+/**
+ * Implements hook_field_views_data_views_data_alter().
+ */
+function node_reference_field_views_data_views_data_alter(&$data, $field) {
+  foreach ($field['bundles'] as $entity_type => $bundles) {
+    $entity_info = entity_get_info($entity_type);
+    $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
+
+    list($label, $all_labels) = field_views_field_label($field['field_name']);
+    $entity = $entity_info['label'];
+    if ($entity == t('Node')) {
+      $entity = t('Content');
+    }
+
+    // Only specify target entity type if the field is used in more than one.
+    if (count($field['bundles']) > 1) {
+      $title = t('@field (@field_name) - reverse (to @entity)', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name']));
+    }
+    else {
+      $title = t('@field (@field_name) - reverse', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name']));
+    }
+    $data['node'][$pseudo_field_name]['relationship'] = array(
+      'title' => $title,
+      'help' => t('Relate each @entity referencing the node through @field.', array('@entity' => $entity, '@field' => $label)),
+      'handler' => 'views_handler_relationship_entity_reverse',
+      'field_name' => $field['field_name'],
+      'field table' => _field_sql_storage_tablename($field),
+      'field field' => $field['field_name'] . '_nid',
+      'base' => $entity_info['base table'],
+      'base field' => $entity_info['entity keys']['id'],
+      'label' => t('!field_name', array('!field_name' => $field['field_name'])),
+    );
+  }
+}
+
+/**
+ * 'options callback' for the views_handler_filter_in_operator filter.
+ *
+ * @param $field_name
+ *   The field name.
+ */
+function node_reference_views_filter_options($field_name) {
+  $options = array();
+
+  if ($field = field_info_field($field_name)) {
+    $options = _node_reference_options($field, TRUE);
+
+    // The options are displayed in checkboxes within the filter admin form, and
+    // in a select within an exposed filter. Checkboxes accept HTML, other
+    // entities should be encoded; selects require the exact opposite: no HTML,
+    // no encoding. We go for a middle ground: strip tags, leave entities
+    // unencoded.
+    foreach ($options as $key => $value) {
+      $options[$key] = strip_tags($value);
+    }
+  }
+
+  return $options;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/node_reference/node_reference.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,155 @@
+<?php
+
+/**
+ * @file
+ * Initial node_reference tests
+ */
+
+/**
+ * Unit tests for referenceability of node types in entity forms.
+ */
+class NodeReferenceFormTest extends FieldTestCase {
+  public static function getInfo() {
+    return array(
+      'name'        => 'Node reference',
+      'description' => 'Make sure nodes are referenceable in entity forms.',
+      'group'       => 'References',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('node_reference', 'field_test'));
+
+    $this->langcode = LANGUAGE_NONE;
+    $this->field_name = 'test_node_reference';
+    $this->field = array(
+      'field_name'  => $this->field_name,
+      'type'        => 'node_reference',
+      'cardinality' => 1,
+      'settings'    => array(
+        'referenceable_types' => array_keys(node_type_get_names()),
+      ),
+    );
+    $this->field = field_create_field($this->field);
+    $this->instance = array(
+      'field_name'  => $this->field_name,
+      'entity_type' => 'test_entity',
+      'bundle'      => 'test_bundle',
+      'widget'      => array(
+        'type'        => 'options_buttons',
+      ),
+    );
+
+    $this->instance = field_create_instance($this->instance);
+
+    $this->nodes = array();
+    foreach (node_type_get_names() as $type_name => $type_title) {
+      $this->nodes[$type_name] = $this->drupalCreateNode(array(
+        'type'  => $type_name,
+        'title' => $this->randomName(8),
+      ));
+      $this->pass(t('Created %type node %nid: %title', array(
+        '%type'  => $type_name,
+        '%nid'   => $this->nodes[$type_name]->nid,
+        '%title' => $this->nodes[$type_name]->title,
+      )), 'destination creation');
+    }
+  }
+
+  function runReferenceableNodeTest($allowed, $group) {
+    field_update_field(array(
+      'field_name' => $this->field_name,
+      'settings'   => array('referenceable_types' => array_keys($allowed)),
+    ));
+    $entity = field_test_create_stub_entity();
+    $form = drupal_get_form('field_test_entity_form', $entity);
+    $options = $form[$this->field_name][$this->langcode]['#options'];
+    $this->assertTrue(isset($options['_none']), t('Empty choice offered for reference'), $group);
+    unset($options['_none']);
+    foreach ($this->nodes as $node) {
+      if (isset($allowed[$node->type])) {
+        $this->assertTrue(isset($options[$node->nid]),
+          t('Node of type @type is referenceable', array('@type' => $node->type)),
+          $group);
+      }
+      else {
+        $this->assertFalse(isset($options[$node->nid]),
+          t('Node of type @type is not referenceable', array('@type' => $node->type)),
+          $group);
+      }
+      unset($options[$node->nid]);
+    }
+    $this->assertTrue(empty($options), t('No extra choice is referenceable'), $group);
+  }
+
+  /**
+   * Test unlimited referencing
+   */
+  function testReferenceableNodeTypesAll() {
+    $allowed = node_type_get_names();
+    $this->runReferenceableNodeTest($allowed, t('Unimited referencing'));
+  }
+
+  /**
+   * Test referencing a limited list of node types
+   */
+  function testReferenceableNodeTypesOne() {
+    $allowed = array_slice(node_type_get_names(), 0, 1, TRUE);
+    $this->runReferenceableNodeTest($allowed, t('Limited referencing'));
+  }
+
+
+  /**
+   * Test autocomplete widget.
+   */
+  function testLongNodeReferenceWidget() {
+    // Create regular test user.
+    $web_user = $this->drupalCreateUser(array('create article content', 'access content'));
+    $this->drupalLogin($web_user);
+
+    // Create test field instance on article node type.
+    $instance = array(
+      'field_name'  => $this->field_name,
+      'entity_type' => 'node',
+      'bundle'      => 'article',
+      'widget'      => array(
+        'type'        => 'node_reference_autocomplete',
+      ),
+    );
+    $instance = field_create_instance($instance);
+
+    // Create a node with a short title and a node with a title longer than
+    // 128 characters.
+    $node_short_title = $this->drupalCreateNode(array(
+      'type'  => 'page',
+      'title' => $this->randomName(8),
+    ));
+    $node_long_title = $this->drupalCreateNode(array(
+      'type'  => 'page',
+      'title' => $this->randomName(200),
+    ));
+
+    // Display node creation form.
+    $langcode = LANGUAGE_NONE;
+    $this->drupalGet('node/add/article');
+    $this->assertFieldByName("{$this->field_name}[$langcode][0][nid]", '', t('Widget is displayed'));
+
+    // Submit node form with autocomplete value for short title.
+    $edit = array(
+      'title' => $this->randomName(8),
+      "{$this->field_name}[$langcode][0][nid]" => $node_short_title->title . ' [nid:' . $node_short_title->nid . ']',
+    );
+    $this->drupalPost('node/add/article', $edit, t('Save'));
+    $this->assertRaw(t('!post %title has been created.', array('!post' => 'Article', '%title' => $edit["title"])), t('Article created.'));
+    $this->assertText($node_short_title->title, t('Referenced node title is displayed.'));
+
+    // Submit node form with autocomplete value for long title.
+    $edit = array(
+      'title' => $this->randomName(8),
+      "{$this->field_name}[$langcode][0][nid]" => $node_long_title->title . ' [nid:' . $node_long_title->nid . ']',
+    );
+    $this->drupalPost('node/add/article', $edit, t('Save'));
+    $this->assertRaw(t('!post %title has been created.', array('!post' => 'Article', '%title' => $edit["title"])), t('Article created.'));
+    $this->assertText($node_long_title->title, t('Referenced node title is displayed.'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/references.feeds.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,305 @@
+<?php
+/**
+ * @file
+ * Mapper that handles any fields added by the References module (node_reference, user_reference)
+ *
+ * Code is effectively a port of the mapper_for_nodereference_field patch to drupal 7, and borrows
+ * heavily from the nodereference patch
+ *
+ */
+
+/**
+ * Implements hook_feeds_parser_sources_alter().
+ */
+function node_reference_feeds_parser_sources_alter(&$sources, $content_type) {
+  if (!empty($content_type)) {
+    $fields = field_info_fields();
+    foreach ($fields as $field) {
+      if ($field['type'] == 'node_reference' && isset($field['bundles']['node']) && in_array($content_type, $field['bundles']['node'])) {
+        $sources['parent:node_reference:'. $field['field_name']] = array(
+          'name' => t('Feed node: Node Reference (nid): @field_name', array('@field_name' => $field['field_name'])),
+          'description' => t('Node References from the parent feed node.'),
+          'callback' => 'node_reference_feeds_get_source',
+        );
+      }
+    }
+  }
+  return $sources;
+}
+
+/**
+ * Callback for mapping parent node references to child node reference values.
+ *
+ * @param $source
+ *   A FeedsSource object.
+ * @param $result
+ *   FeedsParserResult object.
+ * @param $key
+ *   The key as defined in the _feeds_parser_sources_alter() hook defined above.
+ * @return array
+ *   The node ids that the parent node references.
+ */
+function node_reference_feeds_get_source(FeedsSource $source, FeedsParserResult $result, $key) {
+  if ($node = node_load($source->feed_nid)) {
+    $results = array();
+    $field = substr($key, 22);
+    if (!empty($node->{$field}['und'])) {
+      foreach ($node->{$field}['und'] as $delta => $value) {
+        $results[] = $value['nid'];
+      }
+    }
+    return $results;
+  }
+}
+
+/**
+ * Implements hook_feeds_processor_targets_alter() for node_reference fields
+ *
+ * @see FeedsNodeProcessor::getMappingTargets().
+ */
+function node_reference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+  foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
+    $info = field_info_field($name);
+    if ($info['type'] == 'node_reference') {
+
+      $targets[$name . ':title'] = array(
+        'name' => $instance['label'] . t(' (Node reference by node title)'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by node title.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':nid'] = array(
+        'name' => $instance['label'] . t(' (Node reference by node ID)'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by node ID.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':url'] = array(
+        'name' => $instance['label'] . t(' (Node reference by Feeds URL)'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by Feeds URL.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':guid'] = array(
+        'name' => $instance['label'] . t(' (Node reference by Feeds GUID)'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by Feeds GUID.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':title:duplicates'] = array(
+        'name' => $instance['label'] . t(' (Node reference by node title) -- allow duplicate nodes'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by node title. This target allows duplicate nodes (nodes can appear more than once in a field).', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':nid:duplicates'] = array(
+        'name' => $instance['label'] . t(' (Node reference by node ID) -- allow duplicate nodes'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by node ID. This target allows duplicate nodes (nodes can appear more than once in a field).', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':url:duplicates'] = array(
+        'name' => $instance['label'] . t(' (Node reference by Feeds URL) -- allow duplicate nodes'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by Feeds URL.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':guid:duplicates'] = array(
+        'name' => $instance['label'] . t(' (Node reference by Feeds GUID) -- allow duplicate nodes'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by Feeds GUID.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+    }
+  }
+}
+/**
+ * Implements hook_feeds_processor_targets_alter() for user_reference fields
+ *
+ * @see FeedsNodeProcessor::getMappingTargets().
+ *
+ */
+function user_reference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
+  foreach (field_info_instances($entity_type, $bundle_name) as $name => $instance) {
+    $info = field_info_field($name);
+    if ($info['type'] == 'user_reference') {
+
+      $targets[$name . ':name'] = array(
+        'name' => $instance['label'] . t(' (User reference by user name)'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the user matched by user name. ', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':uid'] = array(
+        'name' => $instance['label'] . t(' (User reference by user ID)'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the user matched by user ID.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':url'] = array(
+        'name' => $instance['label'] . t(' (User reference by Feeds URL)'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by Feeds URL.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':guid'] = array(
+        'name' => $instance['label'] . t(' (User reference by Feeds GUID)'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by Feeds GUID.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':name:duplicates'] = array(
+        'name' => $instance['label'] . t(' (User reference by user name) -- allow duplicate users'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the user matched by user name. This target allows duplicate users (users can appear more than once in a field).', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':uid:duplicates'] = array(
+        'name' => $instance['label'] . t(' (User reference by user ID) -- allow duplicate users'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the user matched by user ID. This target allows duplicate users (users can appear more than once in a field).', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':url:duplicates'] = array(
+        'name' => $instance['label'] . t(' (User reference by Feeds URL) -- allow duplicate users'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by Feeds URL.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+
+      $targets[$name . ':guid:duplicates'] = array(
+        'name' => $instance['label'] . t(' (User reference by Feeds GUID) -- allow duplicate users'),
+        'callback' => 'references_feeds_set_target',
+        'description' => t('The @label field of the node matched by Feeds GUID.', array('@label' => $instance['label'])),
+        'real_target' => $name);
+    }
+  }
+}
+
+/**
+ * Callback for mapping both node reference and user_reference fields
+ *
+ * Implementation of hook_feeds_set_target().
+ *
+ * @param $source
+ *   A FeedsSource object.
+ * @param $entity
+ *   The entity to map to.
+ * @param $target
+ *   The target key on $entity to map to.
+ * @param $value
+ *   The value to map. Can be an array or a string.
+ */
+function references_feeds_set_target($source, $entity, $target, $value) {
+  if (empty($value)) {
+    return;
+  }
+
+  // Handle comma delimited or non-multiple values.
+  if (!is_array($value)) {
+    $value = array($value);
+  }
+
+  // Determine the field we are matching against, and whether duplicates are allowed.
+  $target_info = explode(':', $target, 3);
+  if (sizeof($target_info) == 3) {
+    list($target, $match_key, $duplicates) = $target_info;
+  }
+  else {
+    list($target, $match_key) = $target_info;
+  }
+
+  // Load field definition.
+  $info = field_info_field($target);
+  // Parameters to handle differences between node references and user references
+  if ($info['type'] == 'user_reference') {
+    $idname = 'uid';
+    $typename = 'user';
+    $validate_function = 'user_reference_potential_references';
+  }
+  else {
+    $idname = 'nid';
+    $typename = 'node';
+    $validate_function = 'node_reference_potential_references';
+  }
+
+  $field = isset($entity->$target) ? $entity->$target : array();
+  if (!isset($field['und'])) {
+    $field['und'] = array();
+  }
+
+  // Match values against nodes and add to field.
+  foreach ($value as $v) {
+    // Create options.
+    $options = array(
+      'string' => $v,
+      'match' => 'equals',
+      'ids' => array(),
+      'limit' => 1,
+    );
+
+    switch ($match_key) {
+      case 'title':
+      case 'name':
+        // Validate node title or user name.
+        if ((is_string($options['string']) && $options['string'] != '') || is_numeric($options['string'])) {
+          // Lookup potential exact matches for the value (limit to one result).
+          $matches = $validate_function($info,$options);
+          // Use the first element of the potential matches.
+          $options['ids']= key($matches);
+        }
+
+        // Alert if no match is found.
+        if (empty($options['ids'])) {
+          drupal_set_message(t('%title does not match an existing '.$typename, array('%title' => $options['string'])));
+        }
+        break;
+
+      case 'nid':
+      case 'uid':
+        // Make sure it is a positive integer.
+        if ((is_int($options['string']) || ctype_digit($options['string'])) && $options['string'] > 0 && $options['string'] !== '') {
+          // Make sure it is a valid node id or user id for this field.
+          $matches = $validate_function($info, array($options['string']));
+          foreach ($matches as $k => $v) {
+            if ($options['string'] == $k) {
+              $options['ids'] = $k;
+            }
+          }
+        }
+
+        // Alert if no match is found.
+        if (empty($options['ids'])) {
+          drupal_set_message(t('%id is not a valid '.$typename.' id for this field.', array('%id' => $options['string'])));
+        }
+        break;
+
+      case 'guid':
+      case 'url':
+        // get the value from table feeds-item.
+        $result = db_query('SELECT f.entity_id FROM {feeds_item} f WHERE f.'.$match_key.' = :v', array( ':v' => $v) );
+        $options['ids'] = $result->fetchField();
+
+        // Alert if no match is found.
+        if (empty($options['ids'])) {
+          drupal_set_message(t('%id is not a valid '.$typename.' id for this field.', array('%id' => $v)));
+        }
+        break;
+    }
+
+    if (!empty($options['ids'])) {
+      $reference = array($idname => $options['ids']);
+      if (!empty($duplicates)) {
+        // Add the reference, ignoring duplicates.
+        $field['und'][] = $reference;
+      }
+      else if (!in_array($reference, $field['und'])) {
+        // Add the reference only if it doesn't already exist.
+        $field['und'][] = $reference;
+      }
+
+      if ($info['cardinality'] == 1) {
+        break;
+      }
+    }
+  }
+  $entity->{$target} = $field;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/references.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+name = References
+description = Defines common base features for the various reference field types.
+package = Fields
+core = 7.x
+dependencies[] = field
+dependencies[] = options
+files[] = views/references_handler_relationship.inc
+files[] = views/references_handler_argument.inc
+files[] = views/references_plugin_display.inc
+files[] = views/references_plugin_style.inc
+files[] = views/references_plugin_row_fields.inc
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-2.1"
+core = "7.x"
+project = "references"
+datestamp = "1360265821"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/references.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,208 @@
+<?php
+
+/**
+ * @file
+ * Defines common base features for the various reference field types.
+ */
+
+/**
+ * Menu access callback for reference autocomplete paths.
+ *
+ * Check for both 'edit' and 'view' access in the unlikely event
+ * a user has edit but not view access.
+ */
+function reference_autocomplete_access($entity_type, $bundle, $field_name, $entity = NULL, $account = NULL) {
+  return user_access('access content', $account)
+      && ($field = field_info_field($field_name))
+      && field_info_instance($entity_type, $field_name, $bundle)
+      && field_access('view', $field, $entity_type, $entity, $account)
+      && field_access('edit', $field, $entity_type, $entity, $account);
+}
+
+/**
+ * Implements hook_init().
+ */
+function references_init() {
+  // Include feeds.module integration.
+  if (module_exists('feeds')) {
+    module_load_include('inc','references','references.feeds');
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function references_views_api() {
+  return array(
+    'api' => 3,
+    'path' => drupal_get_path('module', 'references') . '/views',
+  );
+}
+
+/**
+ * Implements hook_views_plugins().
+ *
+ * Defines some plugins used by the Views modes for
+ * user_reference.
+ */
+function references_views_plugins() {
+  $plugins = array(
+    'display' => array(
+      'references' => array(
+        'title' => t('References'),
+        'admin' => t('References'),
+        'help' => 'Selects referenceable entities for a reference field (node_reference, user_reference...)',
+        'handler' => 'references_plugin_display',
+        'uses hook menu' => FALSE,
+        'use ajax' => FALSE,
+        'use pager' => FALSE,
+        'accept attachments' => FALSE,
+        // Custom property, used with views_get_applicable_views() to retrieve
+        // all views with a 'References' display.
+        'references display' => TRUE,
+      ),
+    ),
+    'style' => array(
+      'references_style' => array(
+        'title' => t('References list'),
+        'help' => 'Returns results as a PHP array of names + rendered rows.',
+        'handler' => 'references_plugin_style',
+        'theme' => 'views_view_unformatted',
+        'uses row plugin' => TRUE,
+        'uses fields' => TRUE,
+        'uses options' => TRUE,
+        'uses grouping' => TRUE,
+        'type' => 'references',
+        'even empty' => TRUE,
+      ),
+    ),
+    'row' => array(
+      'references_fields' => array(
+        'title' => t('Inline fields'),
+        'help' => t('Displays the fields with an optional template.'),
+        'handler' => 'references_plugin_row_fields',
+        'theme' => 'views_view_fields',
+        'theme path' => drupal_get_path('module', 'views') . '/theme',
+        'theme file' => 'theme.inc',
+        'uses fields' => TRUE,
+        'uses options' => TRUE,
+        'type' => 'references',
+      ),
+    ),
+  );
+  return $plugins;
+}
+
+/**
+ * Retrieves the list of views with a 'references' display, in a format suitable for a 'select' form element..
+ *
+ * @param $entity_type
+ *   The entity type.
+ *
+ * @return
+ *   An array of eligible views displays.
+ */
+function references_get_views_options($entity_type) {
+  // Filter views that contain a 'references' display. This actually returns a
+  // list of displays (the same view appears several times).
+  $displays = views_get_applicable_views('references display');
+
+  // Filter views that list the entity type we want, and group the separate
+  // displays by view.
+  $entity_info = entity_get_info($entity_type);
+  $options = array();
+  foreach ($displays as $data) {
+    list($view, $display_id) = $data;
+    if ($view->base_table == $entity_info['base table']) {
+      $options[$view->name . ':' . $display_id] = $view->name .' - ' . $view->display[$display_id]->display_title;
+    }
+  }
+
+  return $options;
+}
+
+/**
+ * Retrieves an array of candidate referenceable entities, defined by a view.
+ *
+ * @param $entity_type
+ *   The entity type.
+ * @param $view_name
+ *   The name of the view.
+ * @param $display_name
+ *   The name of the view's display. This has to be a 'References' display.
+ * @param $args
+ *   The array of arguments ("contextual filters") for the view.
+ * @param $options
+ *   Array of options to limit the scope of the returned list. This parameter
+ *   is similar to the $options parameter for
+ *   node_reference_potential_references(). An additional key is required:
+ *   - title_field: the name of the column holding entities 'titles' within the
+ *     entity base table.
+ *
+ * @return
+ *   An array of entities, in the format expected by
+ *   node_reference_potential_references().
+ *
+ * @see node_reference_potential_references()
+ * @see _node_reference_potential_references_views()
+ */
+function references_potential_references_view($entity_type, $view_name, $display_name, $args, $options) {
+  $entity_info = entity_get_info($entity_type);
+
+  // Check that the view is valid and the display still exists.
+  $view = views_get_view($view_name);
+  if (!$view || $view->base_table != $entity_info['base table'] || !isset($view->display[$display_name])) {
+    return FALSE;
+  }
+
+  // If we have no access to the View an empty result should be returned to
+  // avoid triggering the fallback results.
+  if  (!$view->access(array($display_name))) {
+    return array();
+  }
+
+  // Temporary backwards compatibility for fields migrated from CCK D6: accept
+  // 'default' display, but dynamically add a 'references' display out of it.
+  if ($display_name == 'default') {
+    $display_name = $view->add_display('references');
+  }
+
+  $view->set_display($display_name);
+
+  // @todo From merlinofchaos on IRC : arguments using summary view can defeat
+  // the style setting.
+  // We might also need to check if there's an argument, and set its
+  // style_plugin as well.
+
+  // Set additional options to let references_plugin_display::query() narrow
+  // the results.
+  $references_options = array(
+    'ids' => $options['ids'],
+    'title_field' => $options['title_field'],
+    'string' => $options['string'],
+    'match' => $options['match'],
+  );
+  $view->display_handler->set_option('references_options', $references_options);
+
+  // We need the title field for autocomplete widgets, so add it (hidden) if not
+  // present.
+  $fields = $view->get_items('field', $display_name);
+  if (!isset($fields[$options['title_field']])) {
+    $label_options = array(
+      'exclude' => 1,
+    );
+    $view->add_item($display_name, 'field', $entity_info['base table'], $options['title_field'], $label_options);
+  }
+
+  // Limit result set size.
+  $limit = !empty($options['limit']) ? $options['limit'] : 0;
+  $view->display_handler->set_option('pager', array('type' => 'some', 'options' => array('items_per_page' => $limit)));
+
+  // Make sure the query is not cached
+  $view->is_cacheable = FALSE;
+
+  // Get the results.
+  $results = $view->execute_display($display_name, $args);
+
+  return $results;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/user_reference/user_reference.devel_generate.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+<?php
+
+function user_reference_devel_generate($object, $field, $instance, $bundle) {
+  if (field_behaviors_widget('multiple values', $instance) == FIELD_BEHAVIOR_CUSTOM) {
+    return devel_generate_multiple('_user_reference_devel_generate', $object, $field);
+  }
+  else {
+    return _user_reference_devel_generate($object, $field);
+  }
+}
+
+function _user_reference_devel_generate($object, $field) {
+  $object_field = array();
+  $allowed_values = user_reference_potential_references($field);
+  if (isset($allowed_values[0])) {
+    unset($allowed_values[0]);
+  }
+  if (!empty($allowed_values)) {
+    // Just pick one of the specified allowed values.
+    $object_field['uid'] = array_rand($allowed_values);
+  }
+  return $object_field;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/user_reference/user_reference.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = User Reference
+description = Defines a field type for referencing a user from a node.
+package = Fields
+core = 7.x
+dependencies[] = field
+dependencies[] = references
+dependencies[] = options
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-2.1"
+core = "7.x"
+project = "references"
+datestamp = "1360265821"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/user_reference/user_reference.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the user_reference module.
+ */
+
+/**
+ * Implements hook_field_schema();
+ */
+function user_reference_field_schema($field) {
+  $columns = array(
+    'uid' => array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => FALSE,
+    ),
+  );
+  return array(
+    'columns' => $columns,
+    'indexes' => array('uid' => array('uid')),
+    'foreign keys' => array(
+      'uid' => array(
+        'table' => 'users',
+        'columns' => array('uid' => 'uid'),
+      ),
+    ),
+  );
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/user_reference/user_reference.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1208 @@
+<?php
+
+/**
+ * @file
+ * Defines a field type for referencing a user from a node.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function user_reference_menu() {
+  $items['user_reference/autocomplete/%/%/%'] = array(
+    'page callback' => 'user_reference_autocomplete',
+    'page arguments' => array(2, 3, 4),
+    'access callback' => 'reference_autocomplete_access',
+    'access arguments' => array(2, 3, 4),
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_field_info().
+ */
+function user_reference_field_info() {
+  return array(
+    'user_reference' => array(
+      'label' => t('User reference'),
+      'description' => t('This field stores the ID of a related user as an integer value.'),
+      'settings' => array(
+        'referenceable_roles' => array(),
+        'referenceable_status' => array(),
+        'view' => array(
+          'view_name' => '',
+          'display_name' => '',
+          'args' => array(),
+        ),
+      ),
+      'default_widget' => 'user_reference_autocomplete',
+      'default_formatter' => 'user_reference_default',
+      // Support hook_entity_property_info() from contrib "Entity API".
+      'property_type' => 'user',
+      // Support default token formatter for field tokens.
+      'default_token_formatter' => 'user_reference_plain',
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_settings_form().
+ */
+function user_reference_field_settings_form($field, $instance, $has_data) {
+  $settings = $field['settings'];
+
+  $form = array();
+  $form['referenceable_roles'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('User roles that can be referenced'),
+    '#default_value' => is_array($settings['referenceable_roles'])
+       ? array_filter($settings['referenceable_roles'])
+       : array(),
+    '#options' => user_roles(TRUE),
+  );
+  $form['referenceable_status'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('User status that can be referenced'),
+    '#default_value' => is_array($settings['referenceable_status'])
+      ? array_filter($settings['referenceable_status'])
+      : array(1),
+    '#options' => array(1 => t('Active'), 0 => t('Blocked')),
+  );
+
+  if (module_exists('views')) {
+    $view_settings = $settings['view'];
+
+    $description = '<p>' . t('The list of users that can be referenced can provided by a view (Views module) using the "References" display type.') . '</p>';
+
+    // Special note for legacy fields migrated from D6.
+    if (!empty($view_settings['view_name']) && $view_settings['display_name'] == 'default') {
+      $description .= '<p><strong><span class="admin-missing">'. t("Important D6 migration note:") . '</span></strong>';
+      $description .= '<br/>' . t("The field is currently configured to use the 'Master' display of the view %view_name.", array('%view_name' => $view_settings['view_name']));
+      $description .= '<br/>' . t("It is highly recommended that you: <br/>- edit this view and create a new display using the 'References' display type, <br/>- update the field settings to explicitly select the correct view and display.");
+      $description .= '<br/>' . t("The field will work correctly until then, but submitting this form might inadvertently change the field settings.") . '</p>';
+    }
+
+    $form['view'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Views - Users that can be referenced'),
+      '#collapsible' => TRUE,
+      '#collapsed' => empty($view_settings['view_name']),
+      '#description' => $description,
+    );
+
+    $views_options = references_get_views_options('user');
+    if ($views_options) {
+      // The value of the 'view_and_display' select below will need to be split
+      // into 'view_name' and 'view_display' in the final submitted values, so
+      // we massage the data at validate time on the wrapping element (not
+      // ideal).
+      $form['view']['#element_validate'] = array('_user_reference_view_settings_validate');
+
+      $views_options = array('' => '<' . t('none') . '>') + $views_options;
+      $default = empty($view_settings['view_name']) ? '' : $view_settings['view_name'] . ':' .$view_settings['display_name'];
+      $form['view']['view_and_display'] = array(
+        '#type' => 'select',
+        '#title' => t('View used to select the users'),
+        '#options' => $views_options,
+        '#default_value' => $default,
+        '#description' => '<p>' . t('Choose the view and display that select the nodes that can be referenced.<br />Only views with a display of type "References" are eligible.') . '</p>' .
+          t('Note:<ul><li>This will discard the "Referenceable Roles" and "Referenceable Status" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate users on user creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate users will be displayed.</li></ul>'),
+      );
+
+      $default = implode(', ', $view_settings['args']);
+      $form['view']['args'] = array(
+        '#type' => 'textfield',
+        '#title' => t('View arguments'),
+        '#default_value' => $default,
+        '#required' => FALSE,
+        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+      );
+    }
+    else {
+      $form['view']['no_view_help'] = array(
+        '#markup' => '<p>' . t('No eligible view was found.') .'</p>',
+      );
+    }
+  }
+
+  return $form;
+}
+
+/**
+ * Validate callback for the 'view settings' fieldset.
+ *
+ * Puts back the various form values in the expected shape.
+ */
+function _user_reference_view_settings_validate($element, &$form_state, $form) {
+  // Split view name and display name from the 'view_and_display' value.
+  if (!empty($element['view_and_display']['#value'])) {
+    list($view, $display) = explode(':', $element['view_and_display']['#value']);
+  }
+  else {
+    $view = '';
+    $display = '';
+  }
+
+  // Explode the 'args' string into an actual array. Beware, explode() turns an
+  // empty string into an array with one empty string. We'll need an empty array
+  // instead.
+  $args_string = trim($element['args']['#value']);
+  $args = ($args_string === '') ? array() : array_map('trim', explode(',', $args_string));
+
+  $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
+  form_set_value($element, $value, $form_state);
+}
+
+/**
+ * Implements hook_field_validate().
+ *
+ * Possible error codes:
+ * - 'invalid_uid': uid is not valid for the field (not a valid user id, or the user is not referenceable).
+ */
+function user_reference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  // Extract uids to check.
+  $ids = array();
+
+  // First check non-numeric uid's to avoid losing time with them.
+  foreach ($items as $delta => $item) {
+    if (is_array($item) && !empty($item['uid'])) {
+      if (is_numeric($item['uid'])) {
+        $ids[] = $item['uid'];
+      }
+      else {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'invalid_uid',
+          'message' => t('%name: invalid input.',
+            array('%name' => $instance['label'])),
+        );
+      }
+    }
+  }
+  // Prevent performance hog if there are no ids to check.
+  if ($ids) {
+    $options = array(
+      'ids' => $ids,
+    );
+    $refs = user_reference_potential_references($field, $options);
+    foreach ($items as $delta => $item) {
+      if (is_array($item)) {
+        if (!empty($item['uid']) && !isset($refs[$item['uid']])) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'invalid_uid',
+            'message' => t("%name: this user can't be referenced.",
+              array('%name' => $instance['label'])),
+          );
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_prepare_view().
+ */
+function user_reference_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  $checked_ids = &drupal_static(__FUNCTION__, array());
+
+  // Set an 'access' property on each item (TRUE if the user exists).
+
+  // Extract ids to check.
+  $ids = array();
+  foreach ($items as $id => $entity_items) {
+    foreach ($entity_items as $delta => $item) {
+      if (is_array($item)) {
+        // Default to 'not accessible'.
+        $items[$id][$delta]['access'] = FALSE;
+        if (!empty($item['uid']) && is_numeric($item['uid'])) {
+          $ids[$item['uid']] = $item['uid'];
+        }
+      }
+    }
+  }
+
+  if ($ids) {
+    // Load information about ids that we haven't already loaded during this
+    // page request.
+    $ids_to_check = array_diff($ids, array_keys($checked_ids));
+    if (!empty($ids_to_check)) {
+      $query = db_select('users', 'u')
+        ->addMetaData('id', 'user_reference_field_prepare_view')
+        ->addMetaData('field', $field)
+        ->fields('u', array('uid'))
+        ->condition('u.uid', $ids_to_check, 'IN');
+      $accessible_ids = $query->execute()->fetchAllAssoc('uid');
+
+      // Populate our static list so that we do not query on those ids again.
+      foreach ($ids_to_check as $id) {
+        $checked_ids[$id] = isset($accessible_ids[$id]);
+      }
+    }
+
+    foreach ($items as $id => $entity_items) {
+      foreach ($entity_items as $delta => $item) {
+        if (is_array($item) && !empty($item['uid']) && !empty($checked_ids[$item['uid']])) {
+          $items[$id][$delta]['access'] = TRUE;
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function user_reference_field_is_empty($item, $field) {
+  return empty($item['uid']);
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function user_reference_field_formatter_info() {
+  return array(
+    'user_reference_default' => array(
+      'label' => t('Default'),
+      'description' => t("Display the name of the referenced user as a link to the user's profile page."),
+      'field types' => array('user_reference'),
+    ),
+    'user_reference_plain' => array(
+      'label' => t('Plain text'),
+      'description' => t('Display the name of the referenced user as plain text.'),
+      'field types' => array('user_reference'),
+    ),
+    'user_reference_user' => array(
+      'label'       => t('Rendered user'),
+      'description' => t('Display the referenced user in a specific view mode'),
+      'field types' => array('user_reference'),
+      'settings'    => array('user_reference_view_mode' => 'full'),
+    ),
+    'user_reference_uid' => array(
+      'label' => t('User ID'),
+      'description' => t('Display the referenced user ID'),
+      'field types' => array('user_reference'),
+    ),
+    'user_reference_path' => array(
+      'label' => t('URL as plain text'),
+      'description' => t('Display the URL of the referenced user'),
+      'field types' => array('user_reference'),
+      'settings' => array(
+        'alias' => TRUE,
+        'absolute' => FALSE
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function user_reference_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $element = array();
+
+  switch ($display['type']) {
+    case 'user_reference_user':
+      $entity_info = entity_get_info('user');
+      $modes = $entity_info['view modes'];
+      $options = array();
+      foreach ($modes as $name => $mode) {
+        $options[$name] = $mode['label'];
+      }
+      $element['user_reference_view_mode'] = array(
+        '#title'   => t('View mode'),
+        '#type'    => 'select',
+        '#options' => $options,
+        '#default_value' => $settings['user_reference_view_mode'],
+        // Never empty, so no #empty_option
+      );
+      break;
+
+    case 'user_reference_path':
+      $element['alias'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Display the aliased path (if exists) instead of the system path'),
+        '#default_value' => $settings['alias'],
+      );
+      $element['absolute'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Display an absolute URL'),
+        '#default_value' => $settings['absolute'],
+      );
+      break;
+  }
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function user_reference_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $summary = array();
+
+  switch ($display['type']) {
+    case 'user_reference_user':
+      $entity_info = entity_get_info('user');
+      $modes = $entity_info['view modes'];
+      $mode = $modes[$settings['user_reference_view_mode']]['label'];
+      $summary[] = t('View mode: %mode', array('%mode' => $mode));
+      break;
+
+    case 'user_reference_path':
+      $summary[] = t('Aliased path: %yes_no', array('%yes_no' => $settings['alias'] ? t('Yes') : t('No')));
+      $summary[] = t('Absolute URL: %yes_no', array('%yes_no' => $settings['absolute'] ? t('Yes') : t('No')));
+      break;
+  }
+
+  return implode('<br />', $summary);
+}
+
+
+/**
+ * Implements hook_field_formatter_prepare_view().
+ *
+ * Preload all user referenced by items using 'full entity' formatters.
+ */
+function user_reference_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
+  // Load the referenced users, except for the 'user_reference_uid' which does
+  // not need full objects.
+
+  // Collect ids to load.
+  $ids = array();
+  foreach ($displays as $id => $display) {
+    if ($display['type'] != 'user_reference_uid') {
+      foreach ($items[$id] as $delta => $item) {
+        if ($item['access']) {
+          $ids[$item['uid']] = $item['uid'];
+        }
+      }
+    }
+  }
+  $entities = user_load_multiple($ids);
+
+  // Add the loaded user objects to the items.
+  foreach ($displays as $id => $display) {
+    if ($display['type'] != 'user_reference_uid') {
+      foreach ($items[$id] as $delta => $item) {
+        if ($item['access']) {
+          $items[$id][$delta]['user'] = $entities[$item['uid']];
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function user_reference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $settings = $display['settings'];
+  $result = array();
+
+  // @todo Optimisation: use hook_field_formatter_prepare_view() to load
+  // user names or full user entities in 'multiple' mode.
+
+  // Collect the list of user ids.
+  $uids = array();
+  foreach ($items as $delta => $item) {
+    $uids[$item['uid']] = $item['uid'];
+  }
+
+  switch ($display['type']) {
+    case 'user_reference_default':
+    case 'user_reference_plain':
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          $user = $item['user'];
+          $label = entity_label('user', $user);
+          if ($display['type'] == 'user_reference_default') {
+            $uri = entity_uri('user', $user);
+            $result[$delta] = array(
+              '#type' => 'link',
+              '#title' => $label,
+              '#href' => $uri['path'],
+              '#options' => $uri['options'],
+            );
+          }
+          else {
+            $result[$delta] = array(
+              '#markup' => check_plain($label),
+            );
+          }
+        }
+      }
+      break;
+
+    case 'user_reference_user':
+      $view_mode = $display['settings']['user_reference_view_mode'];
+      // To prevent infinite recursion caused by reference cycles, we store
+      // diplayed accounts in a recursion queue.
+      $recursion_queue = &drupal_static(__FUNCTION__, array());
+
+      // If no 'referencing entity' is set, we are starting a new 'reference
+      // thread' and need to reset the queue.
+      // @todo Bug: $entity->referencing_entity on accounts referenced in a different
+      // thread on the page. E.g: 1 references 1+2 / 2 references 1+2 / visit homepage.
+      // We'd need a more accurate way...
+      if (!isset($entity->referencing_entity)) {
+        $recursion_queue = array();
+      }
+
+      // The recursion queue only needs to track nodes.
+      if ($entity_type == 'user') {
+        list($id) = entity_extract_ids($entity_type, $entity);
+        $recursion_queue[$id] = $id;
+      }
+
+      // Check the recursion queue to determine which accounts should be fully
+      // displayed, and which accounts will only be displayed as a username.
+      $users_display = array();
+      foreach ($items as $delta => $item) {
+        if ($item['access'] && !isset($recursion_queue[$item['uid']])) {
+          $users_display[$item['uid']] = $item['user'];
+        }
+      }
+
+      // Load and build the fully displayed nodes.
+      if ($users_display) {
+        $users_built = array('users' => array('#sorted' => TRUE));
+        foreach ($users_display as $uid => $account) {
+          $users_display[$uid]->referencing_entity = $entity;
+          $users_display[$uid]->referencing_field = $field['field_name'];
+          $users_built['users'][$account->uid] = user_view($account, $settings['user_reference_view_mode']);
+        }
+      }
+
+      // Assemble the render array.
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          if (isset($users_display[$item['uid']])) {
+            $result[$delta] = $users_built['users'][$item['uid']];
+          }
+          else {
+            $account = $item['user'];
+            $label = entity_label('user', $user);
+            $uri = entity_uri('user', $account);
+            $result[$delta] = array(
+              '#type' => 'link',
+              '#title' => $label,
+              '#href' => $uri['path'],
+              '#options' => $uri['options'],
+            );
+            if (!$account->status) {
+              $result[$delta]['#prefix'] = '<span class="user-unpublished">';
+              $result[$delta]['#suffix'] = '</span>';
+            }
+          }
+        }
+      }
+      break;
+
+    case 'user_reference_uid':
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          $result[$delta] = array(
+            '#markup' => $item['uid'],
+          );
+        }
+      }
+      break;
+
+    case 'user_reference_path':
+      foreach ($items as $delta => $item) {
+        if ($item['access']) {
+          $uri = entity_uri('user', $item['user']);
+          $options = array(
+            'absolute' => $settings['absolute'],
+            'alias' => !$settings['alias'],
+          );
+
+          $options += $uri['options'];
+          $result[$delta] = array(
+            '#markup' => url($uri['path'], $options),
+          );
+        }
+      }
+      break;
+  }
+
+  return $result;
+}
+
+/**
+ * Helper function for widgets and formatters.
+ *
+ * Store user names collected in the curent request.
+ */
+function _user_reference_get_user_names($uids, $known_titles = array()) {
+  $titles = &drupal_static(__FUNCTION__, array());
+
+  // Save titles we receive.
+  $titles += $known_titles;
+
+  // Collect nids to retrieve from database.
+  $uids_query = array();
+  foreach ($uids as $uid) {
+    if (!isset($titles[$uid])) {
+      $uids_query[] = $uid;
+    }
+  }
+  if ($uids_query) {
+    $query = db_select('users', 'u')
+      ->fields('u', array('uid', 'name'))
+      ->condition('u.uid', $uids);
+    $titles += $query->execute()->fetchAllKeyed();
+  }
+
+  // Build the results array.
+  $return = array();
+  foreach ($uids as $uid) {
+    $return[$uid] = isset($titles[$uid]) ? $titles[$uid] : '';
+  }
+
+  return $return;
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function user_reference_field_widget_info() {
+  return array(
+    'user_reference_autocomplete' => array(
+      'label' => t('Autocomplete text field'),
+      'description' => t('Display the list of referenceable users as a textfield with autocomplete behaviour.'),
+      'field types' => array('user_reference'),
+      'settings' => array(
+        'autocomplete_match' => 'contains',
+        'size' => 60,
+        'autocomplete_path' => 'user_reference/autocomplete',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_widget_info_alter().
+ */
+function user_reference_field_widget_info_alter(&$info) {
+  $info['options_select']['field types'][] = 'user_reference';
+  $info['options_buttons']['field types'][] = 'user_reference';
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function user_reference_field_widget_settings_form($field, $instance) {
+  $widget   = $instance['widget'];
+  $defaults = field_info_widget_settings($widget['type']);
+  $settings = array_merge($defaults, $widget['settings']);
+
+  $form = array();
+  if ($widget['type'] == 'user_reference_autocomplete') {
+    $form['autocomplete_match'] = array(
+      '#type'             => 'select',
+      '#title'            => t('Autocomplete matching'),
+      '#default_value'    => $settings['autocomplete_match'],
+      '#options'          => array(
+        'starts_with'     => t('Starts with'),
+        'contains'        => t('Contains'),
+      ),
+      '#description'      => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of users.'),
+    );
+    $form['size'] = array(
+      '#type'             => 'textfield',
+      '#title'            => t('Size of textfield'),
+      '#default_value'    => $settings['size'],
+      '#element_validate' => array('_element_validate_integer_positive'),
+      '#required'         => TRUE,
+    );
+  }
+ return $form;
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function user_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  switch ($instance['widget']['type']) {
+    case 'user_reference_autocomplete':
+      $element += array(
+        '#type' => 'textfield',
+        '#default_value' => isset($items[$delta]['uid']) ? $items[$delta]['uid'] : NULL,
+        '#autocomplete_path' => $instance['widget']['settings']['autocomplete_path'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
+        '#size' => $instance['widget']['settings']['size'],
+        '#element_validate' => array('user_reference_autocomplete_validate'),
+        '#value_callback' => 'user_reference_autocomplete_value',
+      );
+      break;
+  }
+  return array('uid' => $element);
+}
+
+/**
+ * Value callback for a user_reference autocomplete element.
+ *
+ * Substitute in the user name for the uid.
+ */
+function user_reference_autocomplete_value($element, $input = FALSE, $form_state) {
+  if ($input === FALSE) {
+    // We're building the displayed 'default value': expand the raw uid into
+    // "user name [uid:n]".
+    $uid = $element['#default_value'];
+    if (!empty($uid)) {
+      $q = db_select('users', 'u');
+      $q->addField('u', 'name');
+
+      $q->condition('u.uid', $uid)
+        ->range(0, 1);
+      $result = $q->execute();
+      // @todo If no result (user doesn't exist).
+      $value = $result->fetchField();
+      $value .= ' [uid:' . $uid . ']';
+      return $value;
+    }
+  }
+}
+
+/**
+ * Validation callback for a user_reference autocomplete element.
+ */
+function user_reference_autocomplete_validate($element, &$form_state, $form) {
+  $field = field_widget_field($element, $form_state);
+  $instance = field_widget_instance($element, $form_state);
+
+  $value = $element['#value'];
+  $uid = NULL;
+
+  if (!empty($value)) {
+    // Check whether we have an explicit "[uid:n]" input.
+    preg_match('/^(?:\s*|(.*) )?\[\s*uid\s*:\s*(\d+)\s*\]$/', $value, $matches);
+    if (!empty($matches)) {
+      // Explicit uid. Check that the 'name' part matches the actual name for
+      // the uid.
+      list(, $name, $uid) = $matches;
+      if (!empty($name)) {
+        $names = _user_reference_get_user_names(array($uid));
+        if ($name != $names[$uid]) {
+          form_error($element, t('%name: name mismatch. Please check your selection.', array('%name' => $instance['label'])));
+        }
+      }
+    }
+    else {
+      // No explicit uid (the submitted value was not populated by autocomplete
+      // selection). Get the uid of a referencable user from the entered name.
+      $options = array(
+        'string' => $value,
+        'match' => 'equals',
+        'limit' => 1,
+      );
+      $references = user_reference_potential_references($field, $options);
+      if ($references) {
+        // @todo The best thing would be to present the user with an
+        // additional form, allowing the user to choose between valid
+        // candidates with the same name. ATM, we pick the first
+        // matching candidate...
+        $uid = key($references);
+      }
+      else {
+        form_error($element, t('%name: found no valid user with that name.', array('%name' => $instance['label'])));
+      }
+    }
+  }
+
+  // Set the element's value as the user id that was extracted from the entered
+  // input.
+  form_set_value($element, $uid, $form_state);
+}
+
+/**
+ * Implements hook_field_widget_error().
+ */
+function user_reference_field_widget_error($element, $error, $form, &$form_state) {
+  form_error($element['uid'], $error['message']);
+}
+
+/**
+ * Builds a list of referenceable users suitable for the '#option' FAPI property.
+ *
+ * Warning: the function does NOT take care of encoding or escaping the user
+ * names. Proper massaging needs to be performed by the caller, according to
+ * the destination FAPI '#type' (radios / checkboxes / select).
+ *
+ * @param $field
+ *   The field definition.
+ *
+ * @return
+ *   An array of referenceable user names, keyed by user id.
+ */
+function _user_reference_options($field, $flat = TRUE) {
+  $references = user_reference_potential_references($field);
+
+  $options = array();
+  foreach ($references as $key => $value) {
+    // The label, displayed in selects and checkboxes/radios, should have HTML
+    // entities unencoded. The widgets (core's options.module) take care of
+    // applying the relevant filters (strip_tags() or filter_xss()).
+    $label = html_entity_decode($value['rendered'], ENT_QUOTES);
+    if (empty($value['group']) || $flat) {
+      $options[$key] = $label;
+    }
+    else {
+      // The group name, displayed in selects, cannot contain tags, and should
+      // have HTML entities unencoded.
+      $group = html_entity_decode(strip_tags($value['group']), ENT_QUOTES);
+      $options[$group][$key] = $label;
+    }
+  }
+
+  return $options;
+}
+
+/**
+ * Retrieves an array of candidate referenceable users.
+ *
+ * This info is used in various places (aloowed values, autocomplete results,
+ * input validation...). Some of them only need the uids, others nid + names,
+ * others yet uid + names + rendered row (for display in widgets).
+ * The array we return contains all the potentially needed information, and lets
+ * consumers use the parts they actually need.
+ *
+ * @param $field
+ *   The field definition.
+ * @param $options
+ *   An array of options to limit the scope of the returned list. The following
+ *   key/value pairs are accepted:
+ *   - string: string to filter titles on (used by autocomplete).
+ *   - match: operator to match the above string against, can be any of:
+ *     'contains', 'equals', 'starts_with'. Defaults to 'contains'.
+ *   - ids: array of specific node ids to lookup.
+ *   - limit: maximum size of the the result set. Defaults to 0 (no limit).
+ *
+ * @return
+ *   An array of valid users in the form:
+ *   array(
+ *     uid => array(
+ *       'title' => The user name,
+ *       'rendered' => The text to display in widgets (can be HTML)
+ *     ),
+ *     ...
+ *   )
+ */
+function user_reference_potential_references($field, $options = array()) {
+  // Fill in default options.
+  $options += array(
+    'string' => '',
+    'match' => 'contains',
+    'ids' => array(),
+    'limit' => 0,
+  );
+
+  $results = &drupal_static(__FUNCTION__, array());
+
+  // Create unique id for static cache.
+  $cid = $field['field_name'] . ':' . $options['match'] . ':'
+    . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids']))
+    . ':' . $options['limit'];
+  if (!isset($results[$cid])) {
+    $references = FALSE;
+    if (module_exists('views') && !empty($field['settings']['view']['view_name'])) {
+      $references = _user_reference_potential_references_views($field, $options);
+    }
+
+    if ($references === FALSE) {
+      $references = _user_reference_potential_references_standard($field, $options);
+    }
+
+    // Store the results.
+    $results[$cid] = !empty($references) ? $references : array();
+  }
+
+  return $results[$cid];
+}
+
+/**
+ * Helper function for user_reference_potential_references().
+ *
+ * Case of Views-defined referenceable users.
+ */
+function _user_reference_potential_references_views($field, $options) {
+  $settings = $field['settings']['view'];
+  $options['title_field'] = 'name';
+  return references_potential_references_view('user', $settings['view_name'], $settings['display_name'], $settings['args'], $options);
+}
+
+/**
+ * Helper function for user_reference_potential_references().
+ *
+ * List of referenceable users defined by user role and status.
+ */
+function _user_reference_potential_references_standard($field, $options) {
+  // Avoid useless work.
+  $filter_roles = array_filter($field['settings']['referenceable_roles']);
+  $filter_status = array_filter($field['settings']['referenceable_status']);
+  if (!count($filter_status) && !count($filter_roles)) {
+    return array();
+  }
+
+  $query = db_select('users', 'u')
+    // Select the whole record, so that format_username() has enough
+    // information.
+    ->fields('u')
+    ->addMetaData('id', ' _user_reference_potential_references_standard')
+    ->addMetaData('field', $field)
+    ->addMetaData('options', $options);
+
+  // Enable this filter only if any statuses checked (and not both).
+  if (count($filter_status) == 1) {
+    $query->condition('u.status', array_keys($filter_status), 'IN');
+  }
+
+  // Skip filter when "authenticated user" choosen.
+  if ($filter_roles && !isset($filter_roles[DRUPAL_AUTHENTICATED_RID])) {
+    $query->join('users_roles', 'r', 'u.uid = r.uid');
+    $query->condition('r.rid', array_keys($filter_roles), 'IN');
+  }
+
+  if ($options['string'] !== '') {
+    switch ($options['match']) {
+      case 'contains':
+        $query->condition('u.name', '%' . $options['string'] . '%', 'LIKE');
+        break;
+
+      case 'starts_with':
+        $query->condition('u.name', $options['string'] . '%', 'LIKE');
+        break;
+
+      case 'equals':
+      default: // no match type or incorrect match type: use "="
+        $query->condition('u.name', $options['string'], '=');
+        break;
+    }
+  }
+
+  if ($options['ids']) {
+    $query->condition('u.uid', $options['ids'], 'IN');
+  }
+
+  // Explicitly exclude the anonymous user.
+  $query->condition('u.uid', 0, '<>');
+
+  if ($options['limit']) {
+    $query->range(0, $options['limit']);
+  }
+  $query->orderBy('u.name');
+
+  $result = $query->execute()->fetchAll();
+  $references = array();
+  foreach ($result as $account) {
+    $references[$account->uid] = array(
+      'title'    => $account->name,
+      'rendered' => check_plain(format_username($account)),
+    );
+  }
+  return $references;
+}
+
+/**
+ * Menu callback; Retrieve a pipe delimited string of autocomplete suggestions for existing users
+ */
+function user_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
+  $field = field_info_field($field_name);
+  $instance = field_info_instance($entity_type, $field_name, $bundle);
+
+  $options = array(
+    'string' => $string,
+    'match' => $instance['widget']['settings']['autocomplete_match'],
+    'limit' => 10,
+  );
+  $references = user_reference_potential_references($field, $options);
+
+  $matches = array();
+  foreach ($references as $id => $row) {
+    // Markup is fine in autocompletion results (might happen when rendered
+    // through Views) but we want to remove hyperlinks.
+    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
+    // Remove link tags Add a class wrapper for a few required CSS overrides.
+    $matches[$row['title'] . " [uid:$id]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
+  }
+  drupal_json_output($matches);
+}
+
+/**
+ * Implements hook_options_list().
+ */
+function user_reference_options_list($field) {
+  return _user_reference_options($field, FALSE);
+}
+
+/**
+ * Implementation of hook_user_load().
+ */
+/*function user_reference_user_load($accounts) {
+
+  // Only add links if we are on the user 'view' page.
+  if (arg(0) != 'user' || arg(2)) {
+    return;
+  }
+
+  foreach ($accounts as $uid => $account) {
+
+    // find CCK user_reference field tables
+    // search through them for matching user ids and load those nodes
+    $additions = array();
+    $fields = field_info_instances('user');
+
+    // TODO : replace with field_attach_query() + synchronize with latest D6 code.
+
+    // Find the table and columns to search through, if the same
+    // table comes up in more than one field type, we only need
+    // to search it once.
+    $search_tables = array();
+    $search_links = array();
+    foreach ($fields as $field) {
+      if ($field['type'] == 'user_reference' && !empty($field['widget']['reverse_link'])) {
+        $db_info = content_database_info($field);
+        $search_tables[$db_info['table']] = $db_info['columns']['uid']['column'];
+        $search_links[$db_info['table']] = $field['widget']['reverse_link'];
+      }
+    }
+    foreach ($search_tables as $table => $column) {
+      $ids = db_query(db_rewrite_sql("SELECT DISTINCT(n.nid) FROM {node} n LEFT JOIN {". $table ."} f ON n.vid = f.vid WHERE f.". $column ."=". $account->uid. " AND n.status = 1"));
+      while ($data = db_fetch_object($ids)) {
+        // TODO, do we really want a complete node_load() here? We only need the title to create a link.
+        $node = node_load($data->nid);
+        $node->reverse_link = $search_links[$table];
+        $additions[$node->type][] = $node;
+      }
+    }
+    $accounts[$uid]->user_reference = $additions;
+  }
+  return;
+}*/
+
+/**
+ * Implementation of hook_user_view().
+ */
+/*function user_reference_user_view($account, $view_mode, $langcode) {
+  if (!empty($account->user_reference)) {
+    $node_types = content_types();
+    $additions = array();
+    $values = array();
+    foreach ($account->user_reference as $node_type => $nodes) {
+      foreach ($nodes as $node) {
+        if ($node->reverse_link) {
+          $values[$node_type][] = l($node->title, 'node/' . $node->nid);
+        }
+      }
+      if (isset($values[$node_type])) {
+        $additions[] = array(
+          '#type' => 'user_profile_item',
+          '#title' => check_plain($node_types[$node_type]['name']),
+          '#value' => theme('item_list', $values[$node_type]),
+        );
+      }
+    }
+    if ($additions) {
+      $account->content['user_reference'] = $additions + array(
+        '#type' => 'user_profile_category',
+        '#attributes' => array('class' => array('user-member')),
+        '#title' => t('Related content'),
+        '#weight' => 10,
+      );
+    }
+  }
+}*/
+
+/**
+ * Implements hook_content_migrate_field_alter().
+ *
+ * Use this to tweak the conversion of field settings
+ * from the D6 style to the D7 style for specific
+ * situations not handled by basic conversion,
+ * as when field types or settings are changed.
+ *
+ * $field_value['widget_type'] is available to
+ * see what widget type was originally used.
+ */
+function user_reference_content_migrate_field_alter(&$field_value, $instance_value) {
+  switch ($field_value['module']) {
+    case 'userreference':
+      $field_value['module'] = 'user_reference';
+      $field_value['type'] = 'user_reference';
+
+      // Translate 'view' settings.
+      $view_name = isset($field_value['settings']['advanced_view']) ? $field_value['settings']['advanced_view'] : '';
+      $view_args = isset($field_value['settings']['advanced_view_args']) ? $field_value['settings']['advanced_view_args'] : '';
+      $view_args = array_map('trim', explode(',', $view_args));
+      $field_value['settings']['view'] = array(
+        'view_name' => $view_name,
+        'display_name' => 'default',
+        'args' => $view_args,
+      );
+      if ($view_name) {
+        $field_value['messages'][] = t("The field uses the view @view_name to determine referenceable users. You will need to manually edit the view and add a display of type 'References'.", array('@view_name' => $view_name));
+      }
+      unset($field_value['settings']['advanced_view']);
+      unset($field_value['settings']['advanced_view_args']);
+      break;
+  }
+}
+
+/**
+ * Implements hook_content_migrate_instance_alter().
+ *
+ * Use this to tweak the conversion of instance or widget settings
+ * from the D6 style to the D7 style for specific
+ * situations not handled by basic conversion, as when
+ * formatter or widget names or settings are changed.
+ */
+function user_reference_content_migrate_instance_alter(&$instance_value, $field_value) {
+  // The module name for the instance was corrected
+  // by the change in user_reference_content_migrate_field_alter().
+  switch ($field_value['type']) {
+    case 'userreference':
+      // The formatter names changed, all are prefixed
+      // with 'user_reference_'.
+      foreach ($instance_value['display'] as $context => $settings) {
+        $instance_value['display'][$context]['type'] = 'user_reference_' . $settings['type'];
+      }
+      // Massage the widget.
+      switch ($instance_value['widget']['type']) {
+        case 'userreference_autocomplete':
+          $instance_value['widget']['type'] = 'user_reference_autocomplete';
+          $instance_value['widget']['module'] = 'user_reference';
+          break;
+        case 'userreference_select':
+          $instance_value['widget']['type'] = 'options_select';
+          $instance_value['widget']['module'] = 'options';
+          break;
+        case 'userreference_buttons':
+          $instance_value['widget']['type'] = 'options_buttons';
+          $instance_value['widget']['module'] = 'options';
+      }
+      break;
+  }
+}
+
+/**
+ * Implements hook_field_views_data().
+ *
+ * In addition to the default field information we add the relationship for
+ * views to connect back to the users table.
+ */
+function user_reference_field_views_data($field) {
+  // No module_load_include(): this hook is invoked from
+  // views/modules/field.views.inc, which is where that function is defined.
+  $data = field_views_field_default_views_data($field);
+
+  $storage = $field['storage']['details']['sql'];
+
+  foreach ($storage as $age => $table_data) {
+    $table = key($table_data);
+    $columns = current($table_data);
+    $id_column = $columns['uid'];
+    if (isset($data[$table])) {
+      // Filter: swap the handler to the 'in' operator. The callback receives
+      // the field name instead of the whole $field structure to keep views
+      // data to a reasonable size.
+      $data[$table][$id_column]['filter']['handler'] = 'views_handler_filter_in_operator';
+      $data[$table][$id_column]['filter']['options callback'] = 'user_reference_views_filter_options';
+      $data[$table][$id_column]['filter']['options arguments'] = array($field['field_name']);
+
+      // Argument: display users.name in argument titles (handled in our custom
+      // handler) and summary lists (handled by the base views_handler_argument
+      // handler).
+      // Both mechanisms rely on the 'name table' and 'name field' information
+      // below, by joining to a separate copy of the base table from the field
+      // data table.
+      $data[$table][$id_column]['argument']['handler'] = 'references_handler_argument';
+      $data[$table][$id_column]['argument']['name table'] = $table . '_reference';
+      $data[$table][$id_column]['argument']['name field'] = 'name';
+      $data[$table . '_reference']['table']['join'][$table] = array(
+        'left_field' => $id_column,
+        'table' => 'users',
+        'field' => 'uid',
+      );
+
+      // Relationship.
+      $data[$table][$id_column]['relationship'] = array(
+        'handler' => 'references_handler_relationship',
+        'base' => 'users',
+        'base field' => 'uid',
+        'field' => $id_column,
+        'label' => $field['field_name'],
+        'field_name' => $field['field_name'],
+      );
+    }
+  }
+
+  return $data;
+}
+
+/**
+ * Implements hook_field_views_data_views_data_alter().
+ */
+function user_reference_field_views_data_views_data_alter(&$data, $field) {
+  foreach ($field['bundles'] as $entity_type => $bundles) {
+    $entity_info = entity_get_info($entity_type);
+    $pseudo_field_name = 'reverse_' . $field['field_name'] . '_' . $entity_type;
+
+    list($label, $all_labels) = field_views_field_label($field['field_name']);
+    $entity = $entity_info['label'];
+    if ($entity == t('Node')) {
+      $entity = t('Content');
+    }
+
+    // Only specify target entity type if the field is used in more than one.
+    if (count($field['bundles']) > 1) {
+      $title = t('@field (@field_name) - reverse (to @entity)', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name']));
+    }
+    else {
+      $title = t('@field (@field_name) - reverse', array('@entity' => $entity, '@field' => $label, '@field_name' => $field['field_name']));
+    }
+    $data['users'][$pseudo_field_name]['relationship'] = array(
+      'title' => $title,
+      'help' => t('Relate each @entity referencing the user through @field.', array('@entity' => $entity, '@field' => $label)),
+      'handler' => 'views_handler_relationship_entity_reverse',
+      'field_name' => $field['field_name'],
+      'field table' => _field_sql_storage_tablename($field),
+      'field field' => $field['field_name'] . '_uid',
+      'base' => $entity_info['base table'],
+      'base field' => $entity_info['entity keys']['id'],
+      'label' => t('!field_name', array('!field_name' => $field['field_name'])),
+    );
+  }
+}
+
+/**
+ * 'options callback' for the views_handler_filter_in_operator filter.
+ *
+ * @param $field_name
+ *   The field name.
+ *
+ * @return
+ *   The array of allowed options for the filter.
+ */
+function user_reference_views_filter_options($field_name) {
+  $options = array();
+
+  if ($field = field_info_field($field_name)) {
+    $options = _user_reference_options($field, TRUE);
+
+    // The options are displayed in checkboxes within the filter admin form, and
+    // in a select within an exposed filter. Checkboxes accept HTML, other
+    // entities should be encoded; selects require the exact opposite: no HTML,
+    // no encoding. We go for a middle ground: strip tags, leave entities
+    // unencoded.
+    foreach ($options as $key => $value) {
+      $options[$key] = strip_tags($value);
+    }
+  }
+
+  return $options;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/user_reference/user_reference.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,6 @@
+<?php
+
+/**
+ * @file
+ * Placeholder for the development of user_reference tests
+ */
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/views/references_handler_argument.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Provide handler to replace reference with title.
+ */
+class references_handler_argument extends views_handler_argument_numeric {
+
+  /**
+   *  Use entity title for % placeholders in argument titles.
+   */
+  function title_query() {
+    // Use the same table and field than those used for summary lists
+    // ('name table', 'name field').
+    $table_data = views_fetch_data($this->name_table);
+    $table_info = $table_data['table']['join'][$this->table];
+    $table = $table_info['table'];
+    $key_field = $table_info['field'];
+    $title_field = $this->name_field;
+
+    $results = db_select($table, 'base_table')
+      ->fields('base_table', array($key_field, $title_field))
+      ->condition("base_table.$key_field", $this->value)
+      ->execute()
+      // Grab results as 'key => title' array.
+      ->fetchAllKeyed();
+
+    // Sanitize titles and put them back in the correct order in an unkeyed
+    // array.
+    $titles = array();
+    foreach ($this->value as $key) {
+      if (isset($results[$key])) {
+        $titles[] = check_plain($results[$key]);
+      }
+    }
+
+    return $titles;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/views/references_handler_relationship.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Provide relationship handler for reference fields.
+ */
+class references_handler_relationship extends views_handler_relationship {
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['delta'] = array('default' => -1);
+
+    return $options;
+  }
+
+  /**
+   * Add a delta selector for multiple fields.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $field = field_info_field($this->definition['field_name']);
+    
+    // Only add the delta selector if the field is multiple.
+    if ($field['cardinality']) {
+      $max_delta = ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED) ? 10 : $field['cardinality'];
+
+      $options = array('-1' => t('All'));
+      for ($i = 0; $i < $max_delta; $i++) {
+        $options[$i] = $i + 1;
+      }
+      $form['delta'] = array(
+        '#type' => 'select',
+        '#options' => $options,
+        '#default_value' => $this->options['delta'],
+        '#title' => t('Delta'),
+        '#description' => t('The delta allows you to select which item in a multiple value field to key the relationship off of. Select "1" to use the first item, "2" for the second item, and so on. If you select "All", each item in the field will create a new row, which may appear to cause duplicates.'),
+      );
+    }
+  }
+
+  function ensure_my_table() {
+    $field = field_info_field($this->definition['field_name']);
+    
+    if (!isset($this->table_alias)) {
+      $join = $this->get_join();
+      if ($this->options['delta'] != -1 && $field['cardinality']) {
+        $join->extra[] = array(
+          'field' => 'delta',
+          'value' => $this->options['delta'],
+          'numeric' => TRUE,
+        );
+      }
+      $this->table_alias = $this->query->add_table($this->table, $this->relationship, $join);
+    }
+    return $this->table_alias;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/views/references_plugin_display.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * @file
+ * Handler for references_plugin_display.
+ */
+class references_plugin_display extends views_plugin_display {
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    // Force the style plugin to 'references_style' and the row plugin to
+    // 'fields'.
+    $options['style_plugin']['default'] = 'references_style';
+    $options['defaults']['default']['style_plugin'] = FALSE;
+    $options['defaults']['default']['style_options'] = FALSE;
+    $options['row_plugin']['default'] = 'references_fields';
+    $options['defaults']['default']['row_plugin'] = FALSE;
+    $options['defaults']['default']['row_options'] = FALSE;
+
+    // Set the display title to an empty string (not used in this display type).
+    $options['title']['default'] = '';
+    $options['defaults']['default']['title'] = FALSE;
+
+    return $options;
+  }
+
+  function get_style_type() {
+    return 'references';
+  }
+
+  function execute() {
+    return $this->view->render($this->display->id);
+  }
+
+  function render() {
+    if (!empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty'])) {
+      return $this->view->style_plugin->render($this->view->result);
+    }
+    return '';
+  }
+
+  function uses_exposed() {
+    return FALSE;
+  }
+
+  function query() {
+    $options = $this->get_option('references_options');
+
+    // Play nice with View UI 'preview' : if the view is not executed through
+    // _*_reference_potential_references_views(), don't alter the query.
+    if (empty($options)) {
+      return;
+    }
+
+    // Make sure the id field is included in the results, and save its alias
+    // so that references_plugin_style can retrieve it.
+    $this->id_field_alias = $this->view->query->add_field($this->view->base_table, $this->view->base_field);
+
+    // Restrict on the incoming string, or incoming ids.
+    if ($options['string'] !== '') {
+      switch ($options['match']) {
+        case 'equals':
+          $operator = '=';
+          $value = $options['string'];
+          break;
+
+        case 'starts_with':
+          $operator = 'LIKE';
+          $value = db_like($options['string']) . '%';
+          break;
+
+        case 'contains':
+        default:
+          $operator = 'LIKE';
+          $value = '%' . db_like($options['string']) . '%';
+          break;
+      }
+
+      $table_alias = $this->view->query->ensure_table($this->view->base_table);
+      $this->view->query->add_where(NULL, $table_alias . '.' . $options['title_field'], $value, $operator);
+    }
+    elseif ($options['ids']) {
+      $table_alias = $this->view->query->ensure_table($this->view->base_table);
+      $this->view->query->add_where(NULL, $table_alias . '.' . $this->view->base_field, $options['ids'], 'IN');
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/views/references_plugin_row_fields.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Handler for references_plugin_row_fields.
+ */
+class references_plugin_row_fields extends views_plugin_row_fields {
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['separator'] = array('default' => '-');
+
+    return $options;
+  }
+
+  /**
+   * Provide a form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Expand the description of the 'Inline field' checkboxes.
+    $form['inline']['#description'] .= '<br>' . t("<strong>Note:</strong> In 'References' displays, all fields will be displayed inline unless an explicit selection of inline fields is made here." );
+  }
+
+  function pre_render($row) {
+    // Force all fields to be inline by default.
+    if (empty($this->options['inline'])) {
+      $fields = $this->view->get_items('field', $this->display->id);
+      $this->options['inline'] = drupal_map_assoc(array_keys($fields));
+    }
+
+    return parent::pre_render($row);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/references/views/references_plugin_style.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Handler for references_plugin_style.
+ */
+class references_plugin_style extends views_plugin_style {
+  function render() {
+    $options = $this->display->handler->get_option('references_options');
+
+    // Play nice with View UI 'preview' : if the view is not executed through
+    // _*_reference_potential_references_views(), just display the HTML.
+    if (empty($options)) {
+      return parent::render();
+    }
+
+    $title_field = $options['title_field'];
+
+    // Group the rows according to the grouping field, if specified.
+    $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
+
+    // Grab the alias of the 'id' field added by references_plugin_display.
+    $id_field_alias = $this->display->handler->id_field_alias;
+
+    $results = array();
+    $this->view->row_index = 0;
+    foreach ($sets as $title => $records) {
+      foreach ($records as $label => $values) {
+        // Render the row.
+        $rendered = $this->row_plugin->render($values);
+        // Remove linebreaks and extra spaces introduced by templates.
+        $rendered = preg_replace('/\s+/', ' ', trim($rendered));
+
+        // Collect the rendered row, and the raw title value.
+        $results[$values->{$id_field_alias}] = array(
+          'rendered' => $rendered,
+          'group' => $title,
+          'title' => $this->view->field[$title_field]->get_value($values),
+        );
+
+        $this->view->row_index++;
+      }
+    }
+    unset($this->view->row_index);
+
+    return $results;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/CONCEPTS.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,102 @@
+-- SUMMARY --
+
+Describes relations between entities (comment, node, user etc).
+
+Here's how every relation looks:
+
+  Relation
+       |
+       +----+ entity 1
+       |
+       +----+ entity 2
+       |
+      ...
+       |
+       +----+ entity N
+
+
+Every relation looks like this. N is called the arity of the relation.
+For directional relations, entity 1 is called the source, the rest are called
+targets.
+
+An example of a non-directional, n-ary relation:
+
+  siblings(john, jen, jack, jess)
+
+A binary, directional relation:
+
+  child(bruno, Boglarka)
+
+Relations can be directional, ie:
+  parent(boglarka, bruno, sara)
+
+Where Bruno and Sara are siblings http://www.flickr.com/photos/pnegyesi/6041665852
+and Boglarka are their mother. Once again, the first entity has a special
+role, in this case, it's the parent.
+
+Relations are entities, so they can relate relations to other entities, for
+example:
+  CompanyA -> donation123 -> PartyB
+  donations123 -> transaction456 -> BankC
+  that is, "Company A made a donation to Political Pary B, via Bank C".
+
+The entities in the relation can be thought of as the subject and object(s)
+of the relation.
+
+  Entity relation type    = SUBJECT   + PREDICATE      + OBJECT
+  Node author relation    = node      + creator        + user
+  Taxonomy field relation = blog post + is tagged with + some term
+
+Relation bundles are fieldable, so you can add any relevant fields. For
+example, with the donation example above, you could add a text field denoting
+"amount ($)", or a date field specifying when the donation was made.
+
+Relations CAN NOT BE EDITED. That is, the end points that the relation relates
+can not be changed. If you want to change the relation, you need to delete it
+and start again. (The logic behind this is that if the relation is moving from
+one entity to another, then you're actually describing a different relation).
+Fields on a relation ARE editable.
+
+An entity relation API will let us visualize the content model of a Drupal
+site. With this, we could export an RDF schema of the entire content model of a
+site; we could build a "content explorer" that shows the linkings from any one
+piece of content (a user -> their nodes -> a particular node -> a term -> nodes
+tagged with that term). The first milestone for this module is to provide simple
+blocks that display specific corners of this graph, like a user's nodes, and
+terms a user has used. In the future, we would like to be able to add filters to
+the graph (like "a users nodes" + "only blog posts").
+
+There is a dummy field module that, while still does not allow editing
+relations, it opens the door for formatters.
+
+--- A little more thinking/rephrasing... ---
+
+Some relations are hard-coded properties of an entity; for example,
+nodes have an author, a creation date, and a last updated date. Other
+relations exist because of field values; putting a filefield on a node type
+creates a relation between file entities and node type entities. An
+entity_reference module could explicitly define relations between entities.
+
+Broadly speaking, Relation plans to be able to replace all logical relation
+types currently available in drupal core, and more.
+
+For a full description of the module, visit the project page:
+  http://drupal.org/project/relation
+To submit bug reports and feature suggestions, or to track changes:
+  http://drupal.org/project/issues/relation
+
+--- ROADMAP ---
+See the Live, Self-Organising RoadMap (LSORMâ„¢) at:
+http://drupal.org/project/issues/search/relation?status[]=Open&categories[]=task&categories[]=feature
+
+--- Some related discussions/projects: ---
+- http://drupal.org/node/533222 (nodereference/userreference fields in D7)
+- http://drupal.pastebin.com/avnKvCD0 (notes from chx)
+- http://drupal.org/project/graphapi - provides some relation-based graphing capabilities.
+
+-- CONTACT --
+
+Current maintainers:
+* Daniel F. Kudwien (sun) - http://drupal.org/user/54136
+* Ned Haughton (naught101) - http://drupal.org/user/44216
+* Karoly Negesi (chx) - http://drupal.org/user/9446
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+* Go to admin/structure/relation, and create a new relation type. Add fields if
+  neccesary.
+* Enable the relation_entity_collector block if it is not enabled on install - it
+  tries to insert itself after the system management block if that one is enabled.
+* To use the relation_entity_collector block, go to any page that loads entities,
+  and the entity selector will appear.
+* "Pick" as many entities as you need for your relation type (between min_ and
+  max_arity in the appropriate relation bundle). Picks remain until cleared
+  or the relation is created.
+* Click "Create Relation", your relation will be created, and you will be given
+  a link to the relation page.
+* Here you can view the relation, and edit it to add or change field data.
+* To see the relation later, the relation_dummy_field shows it on the entities
+  belonging to the relation.
+
+For details on why this works, and what the hell we were thinking, see CONCEPTS.txt
+
+-- CONTACT --
+
+Current maintainers:
+* Daniel F. Kudwien (sun) - http://drupal.org/user/54136
+* Ned Haughton (naught101) - http://drupal.org/user/44216
+* Karoly Negesi (chx) - http://drupal.org/user/9446
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/UNINSTALL.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,10 @@
+1. If you are using the relation dummy field, delete every field of 'relation'
+   type then run cron. This is the same as deleting any other field. 
+2. You also need to disable and uninstall every other module depending on the
+   Relation Endpoints module in the order allowed.
+3. Once relation module itself is disabled and uninstalled it marks the
+   endpoints field for deletion. You need to run cron to remove the contents
+   of the endpoints table. This might require several cron runs. You will see
+   on the modules page how relation endpoints can not be uninstalled because
+   there are fields using it.
+4. Now you can disable and uninstall relation endpoints itself.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,7 @@
+<?php
+
+/**
+ * @file
+ * API documentation for Relation module.
+ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.ctools.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * @file
+ * ctools import and export for Relation module.
+ */
+
+/**
+ * Page callback for ctools exports.
+ */
+function relation_export_relation_type($form, &$form_state, $type) {
+  drupal_set_title($type->label);
+  ctools_include('export');
+  $result = ctools_export_load_object('relation_type', 'names', array($type->relation_type));
+  $code = relation_relation_type_export($result[$type->relation_type]);
+  $lines = substr_count($code, "\n");
+  if (!function_exists('ctools_export_crud_load_multiple')) {
+    drupal_set_message(t('While manual import works, if you want to save this into a relation_type_default.inc file you need a newer CTools for relation to pick it up later.'), 'warning');
+  }
+
+  $form['export'] = array(
+    '#title' => t('Export data'),
+    '#type' => 'textarea',
+    '#value' => $code,
+    '#rows' => $lines,
+    '#description' => t('Copy the export text and paste it into another myobj using the import function.'),
+  );
+  return $form;
+}
+
+/**
+ * Exports a relation type.
+ */
+function relation_relation_type_export($relation_type, $indent = '') {
+  ctools_include('export');
+  $additional2 = array(
+    'source_bundles' => $relation_type->source_bundles,
+    'target_bundles' => $relation_type->target_bundles,
+  );
+  $output = ctools_export_object('relation_type', $relation_type, $indent, NULL, array(), $additional2);
+  return $output;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.database.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Database query functions.
+ */
+
+/**
+ * Handler class for entity relations.
+ */
+class RelationQuery extends EntityFieldQuery {
+
+  /**
+   * Delta group placeholder.
+   */
+  protected $delta_group = 0;
+
+  /**
+   * Constructor for RelationQuery.
+   */
+  function __construct($entity_type = NULL, $entity_id = NULL, $r_index = NULL) {
+    if (isset($entity_type)) {
+      $this->related($entity_type, $entity_id, $r_index);
+    }
+    $this->entityCondition('entity_type', 'relation');
+  }
+
+  /**
+   * Add a related entity to the query.
+   *
+   * @param $entity_type
+   *   Entity type of the related entity.
+   * @param $entity_id
+   *   Entity id of the related entity. Can be an array of entity IDs.
+   * @param $r_index
+   *   The index of the related entity within the requested relation(s).
+   *
+   * @return RelationQuery
+   */
+  function related($entity_type, $entity_id, $r_index = NULL) {
+    $this->fieldCondition('endpoints', 'entity_type', $entity_type, '=', $this->delta_group);
+    $this->fieldCondition('endpoints', 'entity_id', $entity_id, NULL, $this->delta_group);
+    if (isset($r_index)) {
+      $this->fieldCondition('endpoints', 'r_index', $r_index, '=', $this->delta_group);
+    }
+    $this->delta_group++;
+    return $this;
+  }
+
+  function execute() {
+    $results = parent::execute();
+    if ($this->count) {
+      return $results;
+    }
+    return isset($results['relation']) ? $results['relation'] : array();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.drush.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,129 @@
+<?php
+
+/**
+ * @file
+ * Drush integration for the relation module.
+ */
+
+/**
+ * Implements hook_drush_command().
+ */
+function relation_drush_command() {
+  $items['relation-generate'] = array(
+    'description' => dt('Generates relations.'),
+    'arguments' => array(
+      'number_relations' => dt('The number of relations to generate.'),
+    ),
+    'options' => array(
+      'kill' => 'Delete all relations before generating new ones.',
+      'types' => 'A comma delimited list of relation types to create.',
+    ),
+    'aliases' => array('genrel'),
+  );
+  return $items;
+}
+
+/**
+ * Drush callback to generate relations.
+ *
+ * @param $number_relations
+ *   Number of entities to generate of each entity_type.
+ */
+function drush_relation_generate($number_relations) {
+  $types = drush_get_option('types');
+  $types = $types ? explode(',', $types) : array();
+  $kill = drush_get_option('kill');
+  relation_generate_relations($number_relations, $types, $kill);
+}
+
+/**
+ * Sends message to drush log, if enabled.
+ *
+ * @param $message
+ *   Text of message.
+ */
+function relation_generate_message($message) {
+  if (function_exists('drush_log')) {
+    drush_log($message, 'ok');
+  }
+  else {
+    drupal_set_message($message);
+  }
+}
+
+/**
+ * Generates pseudorandom relations. Appropriate entities must already exist.
+ *
+ * @param $number_relations
+ *   Number of entities to generate of each entity_type.
+ * @param $types
+ *   Array of relation_type to generate relations for.
+ * @param $kill
+ *   Whether to delete all existing relations before creating new ones.
+ *
+ * @return
+ *   Array of rids of the generated relations.
+ */
+function relation_generate_relations($number_relations = 10, $types = array(), $kill = FALSE) {
+  if ($kill) {
+    $query = new EntityFieldQuery();
+    $results = $query->entityCondition('entity_type', 'relation')
+      ->execute();
+    if ($results) {
+      $rids = array_keys($results['relation']);
+      relation_delete_multiple($rids);
+    }
+  }
+  $relation_types = relation_get_types($types);
+  $new_rids = array();
+  foreach ($relation_types as $type => $relation_type) {
+    $available_types = array();
+    foreach ($relation_type->source_bundles as $bundle_key) {
+      list($entity_type, $bundle) = explode(':', $bundle_key, 2);
+      $available_types['source'][$entity_type][] = $bundle;
+    }
+    foreach ($relation_type->target_bundles as $bundle_key) {
+      list($entity_type, $bundle) = explode(':', $bundle_key, 2);
+      $available_types['target'][$entity_type][] = $bundle;
+    }
+    $arity = rand($relation_type->min_arity, $relation_type->min_arity);
+    for ($i = $number_relations; $i > 0; $i--) { // start new relation
+      $entity_keys = array();
+      for ($r_index = 0; $r_index < $arity; $r_index++) {
+        if ($relation_type->directional && $r_index > 0) {
+          $direction = 'target';
+        }
+        else { // use source bundles
+          $direction = 'source';
+        }
+        $entity_type = array_rand($available_types[$direction]);
+        $query = new EntityFieldQuery();
+        $query->entityCondition('entity_type', $entity_type, '=')
+          // Would be nice to ->entityOrderBy('RAND()'); here, and set
+          // range(0, 1). See http://drupal.org/node/1174806
+          ->range(0, 2 * $number_relations);
+        if (!in_array('*', $available_types[$direction][$entity_type])) {
+          // Entities with a single bundle don't support EFQ bundle condition.
+          $entity_info = entity_get_info($entity_type);
+          if (count($entity_info['bundles']) > 1) {
+            $query->entityCondition('bundle', $available_types[$direction][$entity_type], 'IN');
+          }
+        }
+        $results = $query->execute();
+        if ($results) {
+          $entity_ids = array_keys(reset($results));
+          $key = array_rand($entity_ids); // pseudorandomise until EFQ does random.
+          $entity_keys[] = array(
+            'entity_type' => $entity_type,
+            'entity_id'   => $entity_ids[$key],
+            'r_index'     => $r_index,
+          );
+        }
+      }
+      $relation = relation_create($type, $entity_keys);
+      $new_rids[] = relation_save($relation);
+    }
+  }
+  relation_generate_message(t('Generated @number_relations relations.', array('@number_relations' => $number_relations)), 'ok');
+  return $new_rids;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,21 @@
+name = Relation
+description = Describes relationships between entities.
+core = 7.x
+package = Relation
+files[] = relation.database.inc
+files[] = tests/relation.test
+files[] = tests/relation.rules.test
+files[] = tests/relation.views.test
+files[] = views/relation_handler_relationship.inc
+files[] = views/views_handler_field_relation_link.inc
+files[] = views/views_handler_field_relation_link_delete.inc
+files[] = views/views_handler_field_relation_link_edit.inc
+dependencies[] = relation_endpoint
+;dependencies[] = ctools (!=7.x-1.0-rc1)
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-1.0-rc4"
+core = "7.x"
+project = "relation"
+datestamp = "1360240967"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,286 @@
+<?php
+
+/**
+ * @file
+ * Installation functions for Relation module.
+ */
+
+/**
+ * Create our field.
+ */
+function relation_install() {
+  $install = &drupal_static('relation_install');
+  $install = TRUE;
+  $field = array(
+    'field_name' => 'endpoints',
+    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+    'type' => 'relation_endpoint',
+  );
+  field_info_cache_clear();
+  field_create_field($field);
+  $install = FALSE;
+  entity_info_cache_clear();
+}
+
+/**
+ * Implements hook_schema().
+ */
+function relation_schema() {
+  $schema['relation'] = array(
+    'description' => 'Keeps track of relation entities.',
+    'fields' => array(
+      'rid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Unique relation id (entity id).',
+      ),
+      'relation_type' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Relation type (see relation_type table).',
+      ),
+      'vid' => array(
+        'description' => 'The current {relation_revision}.vid version identifier.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'uid' => array(
+        'description' => 'The {users}.uid that owns this relation; initially, this is the user that created it.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'created' => array(
+        'description' => 'The Unix timestamp when the relation was created.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'changed' => array(
+        'description' => 'The Unix timestamp when the relation was most recently saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'arity' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The number rows in this relation. Cannot exceed max_arity, or be less than min_arity in relation_type table.',
+      ),
+    ),
+    'primary key' => array('rid'),
+    'indexes' => array(
+      'relation_types' => array('relation_type', 'rid'),
+    ),
+  );
+  $schema['relation_revision'] = array(
+    'description' => 'Keeps track of relation entities.',
+    'fields' => array(
+      'rid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Unique relation id (entity id).',
+      ),
+      'relation_type' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Relation type (see relation_type table).',
+      ),
+      'vid' => array(
+        'description' => 'The current {relation_revision}.vid version identifier.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'uid' => array(
+        'description' => 'The {users}.uid that owns this relation; initially, this is the user that created it.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'changed' => array(
+        'description' => 'The Unix timestamp when the relation was most recently saved.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'arity' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'The number rows in this relation. Cannot exceed max_arity, or be less than min_arity in relation_type table.',
+      ),
+    ),
+    'primary key' => array('vid'),
+    'indexes' => array(
+      'rid_vid' => array('rid', 'vid'),
+    ),
+  );
+  $schema['relation_type'] = array(
+    'description' => 'Relation settings.',
+    // Add exportability when using ctools.
+    'export' => array(
+      'key' => 'relation_type',
+      'identifier' => 'relation_type',
+      'default hook' => 'relation_default_relation_types',  // Function hook name.
+      'api' => array(
+        'owner' => 'relation',
+        'api' => 'relation_type_default',  // Base name for api include files.
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+      // the callback to load the available bundles
+      'subrecords callback' => '_relation_get_types_bundles',
+      'export callback' => 'relation_relation_type_export',
+    ),
+    'fields' => array(
+      'relation_type' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The machine-readable name of this type.',
+      ),
+      'label' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The human-readable name of this type.',
+      ),
+      'reverse_label' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The reverse human-readable name of this type. Only used for directional relations.',
+      ),
+      'directional' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Whether this relation type is directional. If not, all indexes are ignored.',
+      ),
+      'transitive' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Whether this relation type is transitive.',
+      ),
+      'r_unique' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Whether relations of this type are unique.',
+      ),
+      'min_arity' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 2,
+        'description' => 'The minimum number of rows that can make up a relation of this type.',
+      ),
+      'max_arity' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 2,
+        'description' => 'The maximum number of rows that can make up a relation of this type. Similar to field cardinality.',
+      ),
+    ),
+    'primary key' => array('relation_type'),
+  );
+  $schema['relation_bundles'] = array(
+    'description' => 'Relation type available bundles',
+    'fields' => array(
+      'relation_type' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The relation type.',
+      ),
+      'entity_type' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Entity type that is available to this relation.',
+      ),
+      'bundle' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Entity bundle that is available to this relation.',
+      ),
+      'r_index' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Direction index for relations: 0=from, 1=to. The index is ignored if the directional column in the relation_type table is 0.',
+      ),
+    ),
+  );
+  return $schema;
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function relation_uninstall() {
+  // Remove fields attached to relation type bundles.
+  $types = db_query("SELECT relation_type FROM {relation_type}")->fetchCol();
+  foreach ($types as $type) {
+    field_attach_delete_bundle('relation', $type);
+  }
+  field_delete_field('endpoints');
+}
+
+/**
+ * Enable the new endpoint module and ctools.
+ */
+function relation_update_7001() {
+  module_enable(array('relation_endpoint'));
+  db_update('field_config')
+    ->fields(array('module' => 'relation_endpoint'))
+    ->condition('field_name', 'endpoints')
+    ->execute();
+}
+
+/**
+ * Update empty rid in relation_revision table
+ */
+function relation_update_7002() {
+  // Update statements with JOINs are not portable across SQL dialects.
+  // First get revisions needing update;
+  // retrieve all results before updating anything.
+  $query = db_select('relation_revision', 'v');
+  $query->join('relation', 'r', 'v.vid = r.vid');
+  $results = $query->fields('r', array('rid', 'vid'))
+    ->condition('v.rid', 0, '=')
+    ->execute()
+    ->fetchAll();
+  // Update all those revisions with the correct rid.
+  foreach ($results as $result) {
+    db_update('relation_revision')
+      ->fields(array('rid' => $result->rid))
+      ->condition('vid', $result->vid, '=')
+      ->execute();
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1008 @@
+<?php
+
+require_once dirname(__FILE__) . '/relation.rules.inc';
+if (module_exists('ctools')) {
+  require_once dirname(__FILE__) . '/relation.ctools.inc';
+}
+
+/**
+ * @file
+ * Describes relations between entities.
+ */
+
+/**
+ * Implements hook_entity_info().
+ */
+function relation_entity_info() {
+  $entities['relation'] = array(
+    'label' => t('Relation'),
+    'base table' => 'relation',
+    'revision table' => 'relation_revision',
+    'fieldable' => TRUE,
+    'controller class' => 'RelationController',
+    'save callback' => 'relation_save',
+    'creation callback' => 'relation_rules_create',
+    'deletion callback' => 'relation_delete',
+    'access callback' => 'relation_rules_access',
+    'uri callback' => 'relation_uri',
+    'view callback' => 'relation_multiple_view',
+    'entity keys' => array(
+      'id' => 'rid',
+      'revision' => 'vid',
+      'bundle' => 'relation_type',
+      'label' => 'rid',
+    ),
+    'bundle keys' => array(
+      'bundle' => 'relation_type',
+    ),
+    'bundles' => array(),
+    'view modes' => array(),
+  );
+  foreach (relation_get_types() as $type => $info) {
+    $entities['relation']['bundles'][$type] = (array) $info;
+    $entities['relation']['bundles'][$type]['admin'] = array(
+      'path' => 'admin/structure/relation/manage/%relation_type',
+      'real path' => 'admin/structure/relation/manage/' . $type,
+      'bundle argument' => 4,
+      'access arguments' => array('administer relation types'),
+    );
+  }
+  return $entities;
+}
+
+/**
+ * Implements hook_entity_property_info().
+ */
+function relation_entity_property_info() {
+  $info = array();
+  $properties = &$info['relation']['properties'];
+
+  $properties = array(
+    'rid' => array(
+      'label' => t('Relation ID'),
+      'description' => t('The internal numeric ID of the relation.'),
+      'type' => 'integer',
+      'schema field' => 'rid',
+    ),
+    'relation_type' => array(
+      'label' => t('Relation type'),
+      'type' => 'token',
+      'description' => t('The type of the relation.'),
+      'setter callback' => 'entity_property_verbatim_set',
+      'setter permission' => 'administer nodes',
+      'options list' => 'relation_rules_get_type_options',
+      'required' => TRUE,
+      'schema field' => 'relation_type',
+    ),
+    'endpoints' => array(
+      'label' => t('Endpoints'),
+      'type' => 'list<entity>',
+      'description' => t('The endpoints of the relation.'),
+      'setter callback' => 'relation_rules_set_endpoints',
+      'getter callback' => 'relation_rules_get_endpoints',
+      'setter permission' => 'administer nodes',
+      'required' => TRUE,
+    ),
+  );
+  return $info;
+}
+
+/**
+ * Implements hook_entity_property_info_alter().
+ */
+function relation_entity_property_info_alter(&$info) {
+  // Add relation type-specific information, so that it is easily available
+  // for modules that need to introspect the
+  // relation structure (ie. Search API).
+  foreach (relation_get_types() as $relation_type => $relation) {
+    foreach ($relation->source_bundles as $key => $bundles) {
+      list($entity_type, $bundle) = explode(':', $bundles, 2);
+      $info['relation']['bundles'][$bundle]['properties']['endpoints_source_' . $entity_type] = array(
+        'label' => t('@type (source endpoint)', array('@type' => $entity_type)),
+        'type' => 'list<' . $entity_type . '>',
+        'getter callback' => 'relation_rules_get_specific_endpoints',
+        'endpoint_type' => 'source',
+        'relation_directional' => $relation->directional,
+      );
+    }
+
+    foreach ($relation->target_bundles as $key => $bundles) {
+      list($entity_type, $bundle) = explode(':', $bundles, 2);
+      $info['relation']['bundles'][$bundle]['properties']['endpoints_target_' . $entity_type] = array(
+        'label' => t('@type (target endpoint)', array('@type' => $entity_type)),
+        'type' => 'list<' . $entity_type . '>',
+        'getter callback' => 'relation_rules_get_specific_endpoints',
+        'endpoint_type' => 'target',
+        'relation_directional' => $relation->directional,
+      );
+    }
+
+    $source_bundles = $relation->source_bundles;
+    $original_sb = array_values($source_bundles);
+    $directional = FALSE;
+    // If its a directional relation, merge the source and target bundles.
+    if (count($relation->target_bundles) >= 1) {
+      $original_tb = array_values($relation->target_bundles);
+      $target_bundles = array_merge($source_bundles, $relation->target_bundles);
+      $source_bundles = $target_bundles;
+      $directional = TRUE;
+    }
+    else {
+      $target_bundles = $source_bundles;
+    }
+    foreach ($target_bundles as $target_key => $target_bundle) {
+      list($entity_target) = explode(':', $target_bundle, 2);
+      foreach ($source_bundles as $source_key => $source_bundle) {
+        $property_reverse = ($directional && !in_array($source_bundle, $original_sb) && !in_array($target_bundle, $original_tb));
+        $property = ($property_reverse) ? 'relation_' . $relation_type . '_' . $entity_target . '_reverse' : 'relation_' . $relation_type . '_' . $entity_target;
+        list($entity_source) = explode(':', $source_bundle, 2);
+        if (!$directional || ($property_reverse) || (in_array($target_bundle, $original_tb) && in_array($source_bundle, $original_sb))) {
+          $info[$entity_source]['properties'][$property] = array(
+            'label' => t('Relation @relation_type (to @entity' . (($property_reverse) ? ' reverse)' : ')'), array('@relation_type' => $relation_type, '@entity' => $entity_target)),
+            'type' => 'list<' . $entity_target . '>',
+            'relation_type' => $relation_type,
+            'target_type' => $entity_target,
+            'description' => t("A list of entities related."),
+            'getter callback' => 'relation_rules_get_related_entities',
+          );
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_permission().
+ */
+function relation_permission() {
+  return array(
+    'administer relation types' => array(
+      'title' => t('Administer Relation types'),
+      'description' => t('Create, edit, delete, and perform administration tasks for relation types.'),
+    ),
+    'export relation types' => array(
+      'title' => t('Export Relation types'),
+    ),
+    'access relations' => array(
+      'title' => t('View Relations'),
+      'description' => t('Grant access to view the endpoints of Relations.'),
+    ),
+    'create relations' => array(
+      'title' => t('Create Relations'),
+    ),
+    'edit relations' => array(
+      'title' => t('Edit Relations'),
+    ),
+    'delete relations' => array(
+      'title' => t('Delete Relations'),
+    ),
+    'administer relations' => array(
+      'title' => t('Administer Relations'),
+    ),
+  );
+}
+
+/**
+ * Creates a relation bundle.
+ *
+ * @param $info
+ *   Array of relation type settings. All but relation_type are optional,
+ *   although if the bundles arrays are empty, relations might be difficult to
+ *   create! Keys are:
+ *   - relation_type: Relation type machine name (string).
+ *   - label: Relation type human-readable name (string). Defaults to
+ *     duplicating relation_type.
+ *   - directional: whether relation is directional (boolean). Defaults to
+ *     FALSE.
+ *   - transitive: whether relation is transitive (boolean). Defaults to FALSE.
+ *   - r_unique: whether relations of this type are unique (boolean). Defaults
+ *     to FALSE.
+ *   - min_arity: minimum number of entities in relations of this type
+ *     (int >= 2). Defaults to 2.
+ *   - max_arity: maximum number of entities in relations of this type
+ *     (int >= min_arity). Defaults to 2.
+ *   - source_bundles: array containing allowed bundle keys. This is used for
+ *     both directional and non-directional relations. Bundle key arrays are
+ *     of the form 'entity:bundle', eg. 'node:article', or 'entity:*' for all
+ *     bundles of the type.
+ *   - target_bundles: array containing arrays allowed target bundle keys.
+ *     This is the same format as source_bundles, but is only used for
+ *     directional relations.
+ *
+ * @return
+ *   Relation type object, or FALSE if creation fails.
+ */
+function relation_type_create($info = array()) {
+  $info = (array) $info;
+  if (empty($info['relation_type'])) {
+    return FALSE;
+  }
+  $info += array(
+    'min_arity' => 2,
+    'max_arity' => 2,
+    'directional' => FALSE,
+    'transitive' => FALSE,
+    'r_unique' => FALSE,
+    'source_bundles' => array(),
+    'target_bundles' => array(),
+  );
+  if (empty($info['label'])) {
+    $info['label'] = $info['relation_type'];
+  }
+  if (empty($info['reverse_label'])) {
+    // Directional relations should have a reverse label, but if they don't,
+    // or if they are symmetric:
+    $info['reverse_label'] = $info['label'];
+  }
+
+  return (object) $info;
+}
+
+/**
+ * Saves a relation bundle.
+ *
+ * @param $relation_type
+ *   stdClass object with relation type properties. See relation_type_create().
+ * @param $write_record_keys
+ *   Array containing the primary key of the relation ('relation_type'), if
+ *   updating a relation, or an empty array if creating a new relation.
+ * @param $rebuild_menu
+ *   Boolean indicating whether the the database tables used by various menu
+ *   functions should be rebuilt. Setting this to FALSE is useful if multiple
+ *   relation types are being created programmatically.
+ */
+function relation_type_save($relation_type, $write_record_keys = array(), $rebuild_menu = TRUE) {
+  // Make sure all keys are populated.
+  $relation_type = relation_type_create($relation_type);
+  $existing_relation_type = relation_get_types(array($relation_type->relation_type));
+
+  $type = $relation_type->relation_type;
+  $source_bundles = $relation_type->source_bundles;
+  $target_bundles = $relation_type->target_bundles;
+  unset($relation_type->source_bundles, $relation_type->target_bundles);
+
+  $transaction = db_transaction();
+  drupal_write_record('relation_type', $relation_type, $write_record_keys);
+
+  // Remove all existing bundles from the relation type before re-adding.
+  db_delete('relation_bundles')
+    ->condition('relation_type', $type)
+    ->execute();
+  $query = db_insert('relation_bundles')
+    ->fields(array('relation_type', 'entity_type', 'bundle', 'r_index'));
+  foreach ($source_bundles as $entity_bundles) {
+    list($entity_type, $bundle) = explode(':', $entity_bundles, 2);
+    $query->values(array($type, $entity_type, $bundle, 0));
+  }
+  if ($relation_type->directional) {
+    foreach ($target_bundles as $entity_bundles) {
+      list($entity_type, $bundle) = explode(':', $entity_bundles, 2);
+      $query->values(array($type, $entity_type, $bundle, 1));
+    }
+  }
+  $query->execute();
+  relation_type_ensure_instance($type);
+  if ($rebuild_menu) {
+    menu_rebuild();
+  }
+  if (empty($existing_relation_type)) {
+    field_attach_create_bundle('relation', $relation_type->relation_type);
+  }
+}
+
+/**
+ * Make sure the instance exists for this type.
+ */
+function relation_type_ensure_instance($type) {
+  if (!drupal_static('relation_install') && !field_read_instance('relation', 'endpoints', $type)) {
+    $instance = array(
+      'field_name' => 'endpoints',
+      'entity_type' => 'relation',
+      'bundle' => $type,
+    );
+    field_create_instance($instance);
+  }
+}
+
+/**
+ * Loads a relation type (bundle).
+ *
+ * @param $relation_type
+ *   The machine name of the relation type (bundle) to be loaded.
+ *
+ * @return
+ *   A relation type record (as an Object) in the same format as expected by
+ *   relation_type_save().
+ */
+function relation_type_load($relation_type) {
+  $types = relation_get_types(array($relation_type));
+  return isset($types[$relation_type]) ? $types[$relation_type] : FALSE;
+}
+
+/**
+ * Loads a relation type (bundle), or all relation bundles.
+ *
+ * @param $types
+ *   An array of machine names of the relation types to be loaded. If $types
+ *   is empty, load all relation types.
+ *
+ * @return
+ *   A an array of relation type records in the same format as expected by
+ *   relation_type_save(), keyed by relation_type.
+ */
+function relation_get_types($types = array()) {
+  if (module_exists('ctools')) {
+    ctools_include('export');
+  }
+  if (function_exists('ctools_export_crud_load_multiple')) {
+    $relation_types = $types ? ctools_export_crud_load_multiple('relation_type', $types) : ctools_export_crud_load_all('relation_type');
+    static $recurse = FALSE;
+    if (!$recurse) {
+      $recurse = TRUE;
+      foreach ($relation_types as $type => $data) {
+        if (!empty($data->in_code_only)) {
+          relation_type_ensure_instance($type);
+        }
+      }
+    }
+    $recurse = FALSE;
+  }
+  else {
+    $query = db_select('relation_type', 'rt')
+      ->fields('rt', array('relation_type', 'label', 'reverse_label', 'directional', 'transitive', 'r_unique', 'min_arity', 'max_arity'));
+    if ($types) {
+      $query->condition('relation_type', $types);
+    }
+    $results = $query->execute();
+    $relation_types = array();
+    foreach ($results as $relation_type) {
+      $relation_types[$relation_type->relation_type] = $relation_type;
+    }
+    _relation_get_types_bundles($relation_types);
+  }
+  return $relation_types;
+}
+
+/**
+ * Returns all relation types in a way which can be used on form options.
+ */
+function relation_get_types_options() {
+  $types = relation_get_types();
+  $options = array();
+  foreach ($types as $type => $relation_type) {
+    $options[$type] = $relation_type->label;
+  }
+
+  return $options;
+}
+
+/**
+ * Helper function. Attaches bundles to relation type objects in an array.
+ */
+function _relation_get_types_bundles(&$relation_types) {
+  foreach ($relation_types as &$relation_type) {
+    if (empty($relation_type->in_code_only) && empty($relation_type->bundles_loaded)) {
+      // If overridden or not exported at all, reset the bundles before
+      // loading from the database to avoid duplication.
+      $relation_type->source_bundles = array();
+      $relation_type->target_bundles = array();
+      foreach (db_query('SELECT relation_type, entity_type, bundle, r_index FROM {relation_bundles} WHERE relation_type = :relation_type', array(':relation_type' => $relation_type->relation_type)) as $record) {
+        $endpoint = $record->r_index ? 'target_bundles' : 'source_bundles';
+        $relation_type->{$endpoint}[] = "$record->entity_type:$record->bundle";
+      }
+      // Do not run this twice. ctools static caches the types but runs the
+      // subrecord callback on the whole cache, every already loaded relation
+      // type.
+      $relation_type->bundles_loaded = TRUE;
+    }
+  }
+}
+
+/**
+ * Lists all relation types.
+ *
+ * @return
+ *   Array of relation type names in the format "Label (type)", keyed by
+ *   relation_type.
+ */
+function relation_list_types() {
+  $results = db_select('relation_type', 'rt')
+    ->fields('rt', array('relation_type', 'label'))
+    ->execute()->fetchAllAssoc('relation_type');
+  $relation_types = array();
+  foreach ($results as $type => $relation_type) {
+    $relation_types[$type] = $relation_type->label . ' (' . $type . ')';
+  }
+  return $relation_types;
+}
+
+/**
+ * Deletes a relation type (bundle).
+ *
+ * @param $relation_type
+ *   The machine name of the relation type (bundle) to be deleted.
+ */
+function relation_type_delete($relation_type) {
+  db_delete('relation_type')->condition('relation_type', $relation_type)->execute();
+  db_delete('relation_bundles')->condition('relation_type', $relation_type)->execute();
+}
+
+/**
+ * Loads a relation from a relation id.
+ *
+ * @param $rid
+ *   Numerical id of the relation to be loaded.
+ *
+ * @return
+ *   Loaded relation object. Relation objects are stdClass Object of the form:
+ *   - rid: numeric relation id.
+ *   - relation_type: relation bundle machine name.
+ *   - arity: the number of entities in the relation
+ *   - rdf_mapping: not yet implemented (empty array)
+ *   - endpoints: Field holding the entities that make up the relation.
+ *     Field columns are:
+ *     - entity_type: The type of the entity (eg. node).
+ *     - entity_id: Numeric entity ID.
+ */
+function relation_load($rid, $vid = NULL, $reset = FALSE) {
+  $conditions = (isset($vid) ? array('vid' => $vid) : array());
+  $relations = relation_load_multiple(array($rid), $conditions, $reset);
+  return reset($relations);
+}
+
+/**
+ * Loads a set of relations from an array of relation ids.
+ *
+ * @param $rids
+ *   Array of numerical relation ids of the relations to be loaded.
+ *
+ * @return
+ *   Associative array of loaded relation objects, keyed by relation id.
+ *
+ * @see relation_load()
+ */
+function relation_load_multiple($rids, $conditions = array(), $reset = FALSE) {
+  // Entity load handles field_attach_load for us.
+  return entity_load('relation', $rids, $conditions, $reset);
+}
+
+/**
+ * Relation display page. Currently only displays related entities.
+ *
+ * @TODO: implement directionality, possibly give more details on entities?
+ */
+function relation_page($relation) {
+  $view_mode = 'full';
+  return relation_view($relation);
+}
+
+function relation_view($relation, $view_mode = 'full') {
+  $entity_type = 'relation';
+  $entity = $relation;
+  $entities = array($relation->rid => $relation);
+
+  field_attach_prepare_view($entity_type, $entities, $view_mode);
+  entity_prepare_view($entity_type, $entities);
+  $build = field_attach_view($entity_type, $entity, $view_mode);
+  $build += array(
+    '#entity' => $relation,
+    '#view_mode' => $view_mode,
+    '#language' => LANGUAGE_NONE,
+  );
+  module_invoke_all('entity_view', $entity, $entity_type, $view_mode, LANGUAGE_NONE);
+  drupal_alter('entity_view', $build, $entity_type);
+  return $build;
+}
+
+function relation_multiple_view($relations, $view_mode) {
+  $build = array();
+  foreach ($relations as $relation) {
+    $build['relation'][$relation->rid] = relation_view($relation, $view_mode);
+  }
+  return $build;
+}
+
+/**
+ * Relation type display/edit page title callback.
+ */
+function relation_type_page_title($type) {
+  return $type->label;
+}
+
+/**
+ * Relation edit form.
+ */
+function relation_edit_form($form, &$form_state, $relation) {
+  $form_state['relation'] = $relation;
+  field_attach_form('relation', $relation, $form, $form_state);
+  $form['actions']['#weight'] = 100;
+  $form['actions']['save'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  return $form;
+}
+
+function relation_edit_form_submit($form, &$form_state) {
+  $relation = $form_state['relation'];
+  entity_form_submit_build_entity('relation', $relation, $form, $form_state);
+  $rid = relation_save($relation);
+  if ($rid) {
+    $form_state['redirect'] = 'relation/' . $rid;
+  }
+}
+
+/**
+ * Checks if a relation exists.
+ *
+ * The following example demonstrates how to check if a relation of type
+ * 'likes' exists between two entities, user 17 and node 253.
+ *
+ * @code
+ *   $entity_keys = array(
+ *     array('entity_type' => 'user', 'entity_id' => 17),
+ *     array('entity_type' => 'node', 'entity_id' => 253),
+ *   );
+ *   $relation_type = 'likes';
+ *   $results = relation_relation_exists($entity_keys, $relation_type);
+ * @endcode
+ *
+ * @param $entity_keys
+ *   The entity keys of the relation to found. Entity_keys are arrays keyed by
+ *   'entity_type' and 'entity_id'.
+ * @param $relation_type
+ *   (Optional) The relation type (bundle) of the relation to be checked.
+ * @param $enforce_direction
+ *   (Optional) Whether to enforce direction as specified in $entity_keys.
+ *
+ * @return
+ *   Return FALSE if no relation exists, or an array of matching relations.
+ */
+function relation_relation_exists($entity_keys, $relation_type = NULL, $enforce_direction = FALSE) {
+  $query = relation_query();
+  foreach ($entity_keys as $r_index => $entity_key) {
+    $query->related($entity_key['entity_type'], $entity_key['entity_id'], $enforce_direction ? $r_index : NULL);
+  }
+  if ($relation_type) {
+    $query->propertyCondition('relation_type', $relation_type);
+  }
+  $query->propertyCondition('arity', count($entity_keys));
+  // Avoid Node Access restrictions when checking for a relation
+  $query->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');
+  $relation_ids = $query->execute();
+  return $relation_ids ? $relation_ids : FALSE;
+}
+
+/**
+ * Constructs a relation from a machine name and a list of endpoints.
+ *
+ * @param $relation_type
+ *   The relation type (bundle) of the relation to be created.
+ * @param $endpoints
+ *   A list of endpoint entities. Each endpoint is defined by an associate
+ *   array, with an entity_type and entity_id key. For example:
+ *   @code
+ *   array(
+ *     array('entity_type' => 'node', 'entity_id' => 1),
+ *     array('entity_type' => 'user', 'entity_id' => 5),
+ *   array);
+ *   @endcode
+ *
+ * @return
+ *   The new relation object.
+ */
+function relation_create($type, $endpoints, $account = NULL) {
+  if (!isset($account)) {
+    $account = $GLOBALS['user'];
+  }
+  $relation = new stdClass();
+  $relation->is_new = TRUE;
+  $relation->relation_type = $type;
+  $relation->uid = $account->uid;
+  $relation->endpoints[LANGUAGE_NONE] = $endpoints;
+  return $relation;
+}
+
+/**
+ * Saves a relation.
+ *
+ * @param $relation
+ *   The relation entity data object. See relation_create() for the appropriate
+ *   format (or just use it).
+ *
+ * @return
+ *   The new relation id.
+ */
+function relation_save($relation, $account = NULL) {
+  if (!isset($account)) {
+    $account = $GLOBALS['user'];
+  }
+  global $user;
+  try {
+    field_attach_validate('relation', $relation);
+  }
+  catch (FieldValidationException $e) {
+    watchdog_exception('relation', $e, t('Field validation failed.'), NULL, 
+      WATCHDOG_ERROR);
+    return FALSE;
+  }
+  // Determine if we will be inserting a new relation.
+  if (!isset($relation->is_new)) {
+    $relation->is_new = empty($relation->rid);
+  }
+  $transaction = db_transaction();
+  $endpoints = field_get_items('relation', $relation, 'endpoints');
+  $relation->arity = count($endpoints);
+  // use time() instead of REQUEST_TIME, because otherwise tests
+  // RelationQuery::order() are impossible.
+  $relation->changed = time();
+  if (!$relation->is_new) {
+    $keys = array('rid');
+    $op = 'update';
+    $relation->original = relation_load($relation->rid, $relation->vid);
+  }
+  else {
+    $relation->created = $relation->changed;
+    $keys = array();
+    $op = 'insert';
+  }
+  field_attach_presave('relation', $relation);
+  module_invoke_all('entity_presave', $relation, 'relation');
+  unset($relation->vid);
+  $temp_uid = $relation->uid;
+  $relation->uid = $account->uid;
+  drupal_write_record('relation_revision', $relation);
+  $relation->uid = $temp_uid;
+  drupal_write_record('relation', $relation, $keys);
+  if ($relation->is_new) {
+    db_update('relation_revision')
+      ->fields(array('rid' => $relation->rid))
+      ->condition('vid', $relation->vid)
+      ->execute();
+  }
+  call_user_func("field_attach_$op", 'relation', $relation);
+  module_invoke_all('entity_' . $op, $relation, 'relation');
+  module_invoke('rules', 'invoke_event', 'relation_' . $op, $relation);
+  relation_clear_related_entities_cache($endpoints);
+
+  return $relation->rid;
+}
+
+/**
+ * Clear the cache for a set of endpoints.
+ *
+ * @param $endpoints
+ *   An array of endpoints, with entity_type and entity_id as keys.
+ */
+function relation_clear_related_entities_cache($endpoints) {
+  drupal_static_reset('relation_get_related_entity');
+  foreach ($endpoints as $endpoint) {
+    cache_clear_all('relation:' . $endpoint['entity_type'] . ':' . $endpoint['entity_id'], 'cache', TRUE);
+  }
+}
+
+/**
+ * Insert a new relation in the database.
+ */
+function relation_insert($type, $endpoints) {
+  $relation = relation_create($type, $endpoints);
+  return relation_save($relation);
+}
+
+/**
+ * Updates a relation.
+ */
+function relation_update($relation) {
+  relation_save($relation);
+}
+
+/**
+ * Deletes a relation.
+ *
+ * @param $rid
+ *   The numeric id of the relation to be deleted.
+ */
+function relation_delete($rid) {
+  relation_delete_multiple(array($rid));
+}
+
+/**
+ * Deletes a relation.
+ *
+ * @param $rid
+ *   An array of numeric ids of the relation to be deleted.
+ */
+function relation_delete_multiple($rids) {
+  $relations = relation_load_multiple($rids);
+  foreach ($relations as $rid => $relation) {
+    db_delete('relation')->condition('rid', $rid)->execute();
+    db_delete('relation_revision')->condition('rid', $rid)->execute();
+    module_invoke_all('entity_delete', $relation, 'relation');
+    module_invoke('rules', 'invoke_event', 'relation_delete', $relation);
+    field_attach_delete('relation', $relation);
+    $endpoints = field_get_items('relation', $relation, 'endpoints');
+    relation_clear_related_entities_cache($endpoints);
+  }
+}
+
+/**
+ * Menu callback: ask for confirmation of relation deletion.
+ */
+function relation_delete_confirm($form, &$form_state, $relation) {
+  $form['#relation'] = $relation;
+  // Always provide entity id in the same form key as in the entity edit form.
+  $form['rid'] = array('#type' => 'value', '#value' => $relation->rid);
+  return confirm_form($form,
+    t('Are you sure you want to delete relation %rid?', array('%rid' => $relation->rid)),
+    'relation/' . $relation->rid,
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Executes relation deletion.
+ */
+function relation_delete_confirm_submit($form, &$form_state) {
+  if ($form_state['values']['confirm']) {
+    $relation = $form['#relation'];
+    relation_delete($form_state['values']['rid']);
+    watchdog('relation', '@type: deleted %title.', array('@type' => $relation->relation_type, '%title' => $relation->rid));
+    drupal_set_message(t('@type %title has been deleted.', array('@type' => $relation->relation_type, '%title' => $relation->rid)));
+  }
+
+  $form_state['redirect'] = '<front>';
+}
+
+/**
+ * Gets a relation's URI.
+ *
+ * @see entity_uri()
+ */
+function relation_uri($relation) {
+  return array('path' => 'relation/' . $relation->rid);
+}
+
+/**
+ * Returns a query object to find related entities.
+ *
+ * @param $entity_type
+ *   (optional) The entity type of one of the endpoints.
+ * @param $entity_id
+ *   (optional) The entity id of one of the endpoints. Can also be an array of
+ *   entity IDs.
+ * @param $r_index
+ *   (optional) The index of the search entity in the relation to be found
+ *   (0 = source, 1 = target).
+ *
+ * @return RelationQuery
+ *   The query object itself.
+ */
+function relation_query($entity_type = NULL, $entity_id = NULL, $r_index = NULL) {
+  return new RelationQuery($entity_type, $entity_id, $r_index);
+}
+
+/**
+ * Return endpoint entities.
+ *
+ * @param $relation
+ *   Full relation object containing the endpoints
+ *
+ * @param $entity_type
+ *   (optional) Filter endpoints by entity type. Return all endpoint entities
+ *   if empty.
+ */
+function relation_get_endpoints($relation, $entity_type = NULL) {
+  $entities = array();
+  foreach ($relation->endpoints[LANGUAGE_NONE] as $endpoint) {
+    if (!empty($entity_type) && $endpoint['entity_type'] != $entity_type) {
+      continue;
+    }
+    $entities[$endpoint['entity_type']][] = $endpoint['entity_id'];
+  }
+  if (empty($entities)) {
+    return FALSE;
+  }
+  foreach ($entities as $entity_type => $ids) {
+    $entities[$entity_type] = entity_load($entity_type, $ids);
+  }
+  return $entities;
+}
+
+/**
+ * Returns a related entity.
+ *
+ * Returns the entity object of the first other entity in the first relation
+ * that matches the given conditions. Do not expect to get exactly what you
+ * want, especially if you have multiple relations of the same type on the
+ * search entity.
+ *
+ * @param $entity_type
+ *   The entity type of one of the endpoints.
+ * @param $entity_id
+ *   The entity id of one of the endpoints.
+ * @param $relation_type
+ *   (optional) The relation type of the relation to find.
+ * @param $r_index
+ *   (optional) The index of the search entity in the relation to be found
+ *   (0 = source, 1 = target).
+ *
+ * @return
+ *   The entity object from the other endpoint.
+ */
+function relation_get_related_entity($entity_type, $entity_id, $relation_type = NULL, $r_index = NULL) {
+
+  // Static cache the results of relation_query() and relation_load() to avoid
+  // duplicate queries if this is called multiple times with the same arguments
+  // during a request.
+  $items = &drupal_static(__FUNCTION__);
+  $request_key = "$entity_type:$entity_id";
+  $cache_key = "$request_key:$relation_type:$r_index";
+
+  if (isset($items[$cache_key])) {
+    $entities = $items[$cache_key];
+  }
+  elseif ($cached = cache_get('relation:' . $cache_key)) {
+    $entities = $cached->data;
+    $items[$cache_key] = $entities;
+  }
+  else {
+    $query = relation_query($entity_type, $entity_id, $r_index)->range(0, 1);
+    if ($relation_type) {
+      $query->entityCondition('bundle', $relation_type);
+    }
+    $results = $query->execute();
+    $result = reset($results);
+    if ($result) {
+      $relation = relation_load($result->rid);
+      $entities = field_get_items('relation', $relation, 'endpoints');
+    }
+    else {
+      $entities = FALSE;
+    }
+    cache_set('relation:' . $cache_key, $entities);
+    $items[$cache_key] = $entities;
+  }
+
+  if ($entities) {
+    $first_entity_key = $entities[0]['entity_type'] . ':' . $entities[0]['entity_id'];
+    if (isset($r_index)) {
+      $request_key = $request_key . ':' . $r_index;
+      $first_entity_key = $first_entity_key . ':' . $entities[0]['r_index'];
+    }
+    if ($request_key == $first_entity_key) {
+      $other_endpoints = entity_load($entities[1]['entity_type'], array($entities[1]['entity_id']));
+      return reset($other_endpoints);
+    }
+    $other_endpoints = entity_load($entities[0]['entity_type'], array($entities[0]['entity_id']));
+    return reset($other_endpoints);
+  }
+  return FALSE;
+}
+
+/**
+ * Returns the relation types that can have the given entity as an endpoint.
+ *
+ * @param $entity_type
+ *   The entity type of the endpoint.
+ * @param $bundle
+ *   The bundle of the endpoint.
+ * @param $endpoint
+ *   (optional) the type of endpoint. This is only used for directional
+ *   relation types. Possible options are 'source', 'target', or 'both'.
+ *
+ * @return
+ *   An array of relation types, keyed by relation_type.
+ */
+function relation_get_available_types($entity_type, $bundle, $endpoint = 'source') {
+  $bundle_key = $entity_type . ':' . $bundle;
+  $all_bundle_key = $entity_type . ':*';
+  $relation_types = relation_get_types();
+
+  foreach ($relation_types as $type => $relation_type) {
+    $available = FALSE;
+    if ($endpoint == 'source' || $endpoint == 'both') {
+      if (in_array($bundle_key, $relation_type->source_bundles) || in_array($all_bundle_key, $relation_type->source_bundles)) {
+        $available = TRUE;
+      }
+    }
+    if ($endpoint == 'target' || $endpoint == 'both') {
+      if (in_array($bundle_key, $relation_type->target_bundles) || in_array($all_bundle_key, $relation_type->target_bundles)) {
+        $available = TRUE;
+      }
+    }
+    if (!$available) {
+      unset($relation_types[$type]);
+    }
+  }
+  return $relation_types;
+}
+
+/**
+ * Implements hook_entity_delete().
+ */
+function relation_entity_delete($entity, $entity_type) {
+  list($entity_id) = entity_extract_ids($entity_type, $entity);
+  $relations = relation_query($entity_type, $entity_id)->execute();
+  $relations_to_delete = array();
+  foreach ($relations as $row) {
+    // Remove any endpoints pointing to entity
+    $relation = relation_load($row->rid);
+    foreach ($relation->endpoints[LANGUAGE_NONE] as $key => $endpoint) {
+      if ($endpoint['entity_id'] == $entity_id
+        && $endpoint['entity_type'] == $entity_type) {
+        unset($relation->endpoints[LANGUAGE_NONE][$key]);
+      }
+    }
+    // Check if relation remains valid with regards to arity
+    $type = relation_get_types(array($relation->relation_type));
+    $min_arity = $type[$relation->relation_type]->min_arity;
+    $arity = count($relation->endpoints[LANGUAGE_NONE]);
+    if ($arity < $min_arity) {
+      // Not valid - delete
+      array_push($relations_to_delete, $relation->rid);
+    }
+    else {
+      // Valid - save
+      relation_save($relation);
+    }
+  }
+  if (!empty($relations_to_delete)) {
+    relation_delete_multiple($relations_to_delete);  
+    drupal_set_message(t('Relations @relations have been deleted.', 
+      array('@relations' => implode(', ', $relations_to_delete))));
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function relation_views_api() {
+  return array(
+    'api' => 3.0,
+    'path' => drupal_get_path('module', 'relation') . '/views',
+  );
+}
+
+/**
+ * Gets the label of the relation type of the given relation
+ *
+ * @param $relation
+ *   A relation object.
+ * @param $reverse
+ *   optional: whether to get the reverse label (boolean).
+ *
+ * @return
+ *   The label of the relation type.
+ */
+function relation_get_type_label($relation, $reverse = FALSE) {
+  $type = relation_type_load($relation->relation_type);
+  if ($type->directional && $reverse) {
+    return $type->reverse_label;
+  }
+  else {
+    return $type->label;
+  }
+}
+
+/**
+ * Controller class for relation.
+ *
+ * This extends the DrupalDefaultEntityController class, adding required
+ * special handling for relation revisions, very similar to what's being done
+ * with nodes.
+ */
+class RelationController extends DrupalDefaultEntityController {
+
+  protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
+    // Ensure that uid is taken from the {relation} table
+    $query = parent::buildQuery($ids, $conditions, $revision_id);
+    $fields =& $query->getFields();
+    $fields['uid']['table'] = 'base';
+    $query->addField('revision', 'uid', 'revision_uid');
+    $fields['changed']['table'] = 'base';
+    $query->addField('revision', 'changed', 'changed');
+    return $query;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.rules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,457 @@
+<?php
+
+/**
+ * @file
+ * Implements the Rules module API for Relation.
+ */
+
+/**
+ * Implements hook_rules_event_info().
+ */
+function relation_rules_event_info() {
+  return array(
+    'relation_insert' => array(
+      'label' => t('After saving a new relation'),
+      'group' => t('Relation'),
+      'variables' => array(
+        'relation' => array('type' => 'relation', 'label' => t('relation'), 'description' => t('The relation.')),
+      ),
+    ),
+    'relation_update' => array(
+      'label' => t('After updating a relation'),
+      'group' => t('Relation'),
+      'variables' => array(
+        'relation' => array('type' => 'relation', 'label' => t('relation'), 'description' => t('The relation.')),
+        'relation_unchanged' => array('type' => 'relation', 'label' => t('unchanged relation'), 'description' => t('The unchanged relation.'), 'handler' => 'rules_events_entity_unchanged'),
+      ),
+    ),
+    'relation_delete' => array(
+      'label' => t('After deleting a relation'),
+      'group' => t('Relation'),
+      'variables' => array(
+        'relation' => array('type' => 'relation', 'label' => t('relation')),
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_rules_action_info().
+ */
+function relation_rules_action_info() {
+  $items = array(
+    'relation_rules_load_related' => array(
+      'label' => t('Loads related entities'),
+      'group' => t('Relation'),
+      'parameter' => array(
+        'left' => array(
+          'type' => 'entity',
+          'label' => t('Entity'),
+        ),
+        'relation_type' => array(
+          'type' => 'text',
+          'label' => t('Relation type'),
+          'options list' => 'relation_rules_get_type_options',
+        ),
+      ),
+      'provides' => array(
+        'endpoints' => array(
+          'type' => 'list<entity>',
+          'label' => t('List of related entities'),
+        ),
+      ),
+    ),
+    'relation_rules_fetch_endpoint' => array(
+      'label' => t('Fetch relation endpoints'),
+      'group' => t('Relation'),
+      'description' => 'Fetch relation endpoint(s) of at a particular entity type.',
+      'parameter' => array(
+        'relation' => array(
+          'type' => 'relation',
+          'label' => t('Relation'),
+          'restriction' => 'selector',
+        ),
+      ),
+      'provides' => array(
+        'endpoint_fetched' => array(
+          'type' => 'entity',
+          'label' => t('Fetched Endpoint'),
+        ),
+      ),
+    ),
+  );
+  return $items;
+}
+
+
+/**
+ * Options list callback for fetching relation types.
+ */
+function relation_rules_get_type_options() {
+  $options = array();
+  $types = relation_get_types();
+  foreach ($types as $type) {
+    $options[$type->relation_type] = $type->label;
+  }
+  return $options;
+}
+
+/**
+ * Callback for creating a relation, in the form Rules wants it.
+ */
+function relation_rules_create($values = array()) {
+  return relation_create($values['relation_type'], array());
+}
+
+/**
+ * Access callback for creating a relation.
+ *
+ * For now, everyone has permission to trigger the creation of a relation.
+ */
+function relation_rules_access($op, $entity = NULL, $account = NULL) {
+  return TRUE;
+}
+
+/**
+ * Endpoint property getter callback.
+ */
+function relation_rules_get_endpoints($relation, array $options, $property_name, $entity_type) {
+  $array = array();
+  foreach (relation_get_endpoints($relation) as $entity_type => $entities) {
+    foreach ($entities as $entity) {
+      $array[] = entity_metadata_wrapper($entity_type, $entity);
+    }
+  }
+  return $array;
+}
+
+/**
+ * Entity-type specific property getter callback.
+ */
+function relation_rules_get_specific_endpoints($relation, array $options, $property_name, $entity_type, $info) {
+  if ($info['endpoint_type'] == 'source') {
+    if ($info['relation_directional']) {
+      $endpoints = array($relation->endpoints[LANGUAGE_NONE][0]);
+    }
+    else {
+      $endpoints = $relation->endpoints[LANGUAGE_NONE];
+    }
+  }
+  else {
+    $endpoints = array_slice($relation->endpoints[LANGUAGE_NONE], 1);
+  }
+
+  $array = array();
+  foreach ($endpoints as $endpoint) {
+    $entities = entity_load($endpoint['entity_type'], array($endpoint['entity_id']));
+    $entity_id = entity_extract_ids($endpoint['entity_type'], reset($entities));
+    $array[] = $entity_id[0];
+  }
+  return $array;
+}
+
+/**
+ * Endpoint property setter callback.
+ *
+ * @param $data
+ *   The relation object that we are going to modify.
+ * @param $name
+ *   Name of the provided Rules variable.
+ * @param $endpoint_wrappers
+ *   Array of entity wrappers that we are going to add to the relation object.
+ */
+function relation_rules_set_endpoints(&$relation = NULL, $name = NULL, $entity_wrappers = NULL) {
+  // Check that we are creating a new relation. Updating existing relations
+  // aren't supported.
+  if (isset($relation->rid) || empty($entity_wrappers)) {
+    return;
+  }
+
+  foreach ($entity_wrappers as $i => $entity_wrapper) {
+    $entity = $entity_wrapper->value();
+    $entity_type = $entity_wrapper->type();
+    $id_key = $entity_wrapper->entityKey('id');
+    $bundle_key = $entity_wrapper->entityKey('bundle');
+
+    if (isset($entity->{$id_key})) {
+      $relation->endpoints[LANGUAGE_NONE][$i] = array(
+        'entity_type' => $entity_wrapper->type(),
+        'entity_id' => $entity->{$id_key},
+        'entity_bundle' => isset($entity->{$bundle_key}) ? $entity->{$bundle_key} : $entity_type,
+        'r_index' => $i,
+      );
+    }
+  }
+}
+
+/**
+ * Related entities getter callback.
+ */
+function relation_rules_get_related_entities($entity, array $options, $name, $type, $info) {
+  $source_entity = entity_metadata_wrapper($type, $entity);
+  $source_entity_type = $source_entity->type();
+  $source_entity_id = $source_entity->getIdentifier();
+  $results = relation_query($source_entity_type, $source_entity_id)
+    ->entityCondition('bundle', $info['relation_type'])
+    ->range(0, 50)
+    ->execute();
+  $rids = array_keys($results);
+  $entities_ids = array();
+  if (!$rids) {
+    return $entities_ids;
+  }
+  foreach (relation_load_multiple($rids) as $relation) {
+    foreach ($relation->endpoints[LANGUAGE_NONE] as $endpoint) {
+      if ($endpoint['entity_type'] == $info['target_type']) {
+        $entities_ids[] = $endpoint['entity_id'];
+      }
+    }
+  }
+  return $entities_ids;
+}
+
+/**
+ * Info alter callback for the load_related action.
+ */
+function relation_rules_load_related_info_alter(&$element_info, $element) {
+  if (!empty($element->settings['relation_type'])) {
+    // We only make this parameter available after we've selected the relation type. This way we
+    // can limit the entity type list to only those relative to the selected relation.
+    $element_info['parameter']['entity_type_op'] = array(
+      'type' => 'text',
+      'label' => t('Entity type'),
+      'options list' => 'relation_rules_fetch_endpoint_type_options',
+      'optional' => TRUE,
+      'default value' => '',
+      'description' => t('Optional: Select the specific type of entities to return. This will allow you to access their field/property data.'),
+    );
+    if (!empty($element->settings['entity_type_op'])) {
+      // Set the returned entity type so we can access all the data.
+      $element_info['provides']['endpoints']['type'] = 'list<' . $element->settings['entity_type_op'] . '>'; // more then one.
+    }
+  }
+}
+
+/**
+ * Form alter callback for the load_related action.
+ */
+function relation_rules_load_related_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+  $first_step  = empty($element->settings['relation_type']);
+  $form['reload'] = array(
+    '#weight' => 5,
+    '#type' => 'submit',
+    '#name' => 'reload',
+    '#value' => $first_step ? t('Continue') : t('Reload form'),
+    '#submit' => array('rules_action_type_form_submit_rebuild'),
+    '#ajax' => rules_ui_form_default_ajax(),
+    '#description' => $first_step ? '' : t('Reload the form to change the entity types list.'),
+  );
+
+  if ($first_step) {
+    // In the first step only show relevant parameters.
+    foreach (element_children($form['parameter']) as $key) {
+      if (($key != 'relation_type') && ($key != 'left')) {
+        unset($form['parameter'][$key]);
+      }
+    }
+    unset($form['submit']);
+    unset($form['provides']);
+  }
+  // Add #ajax to the relation_type selection dropdown to reload the form.
+  if(isset($form['parameter']['relation_type'])) {
+    $form['parameter']['relation_type']['#ajax'] = rules_ui_form_default_ajax() + array(
+      'event' => 'change',
+      'trigger_as' => array('name' => 'reload'),
+    );
+  }
+}
+
+/**
+ * Action callback loading all related entities.
+ */
+function relation_rules_load_related($source_entity, $relation_type, $entity_type_op = NULL) {
+  $endpoints = array();
+  $source_entity_type = $source_entity->type();
+  $source_entity_id = $source_entity->getIdentifier();
+  foreach ($source_entity->getPropertyInfo() as $property_name => $property) {
+    if (isset($property['relation_type']) && $property['relation_type'] == $relation_type && isset($property['target_type'])) {
+      $related_entities = $source_entity->$property_name->value();
+      if (!empty($related_entities)) {
+        foreach ($related_entities as $related_entity) {
+          if (empty($entity_type_op) || $entity_type_op == $property['target_type'])
+          {
+            $endpoint_wrapper = entity_metadata_wrapper($property['target_type'], $related_entity);
+            if ($endpoint_wrapper->type() != $source_entity_type || $endpoint_wrapper->getIdentifier() != $source_entity_id) {
+              $endpoints[] = $related_entity;
+            }
+          }
+        }
+      }
+    }
+  }
+  return array('endpoints' => $endpoints);
+}
+
+/**
+ * Returns the options list of available endpoint entity types for the chosen relation type.
+ */
+function relation_rules_fetch_endpoint_type_options(RulesAbstractPlugin $element, $param_name=null) {
+  $options = $types = array();
+  // The parameter is optional
+  if ($param_name = 'entity_type_op') {
+    $options[''] = t('--All types--');
+  }
+  $all_entity_types = rules_entity_type_options();
+  if (!empty($element->settings['relation_type'])) {
+    $types[] = $element->settings['relation_type'];
+  } elseif ($wrapper = $element->applyDataSelector($element->settings['relation:select'])) {
+    // If we can: limit the list of entity types to those relative to the selected relation type.
+    if (($info = $wrapper->info()) && !empty($info['bundle'])) {
+      $types[] = $info['bundle'];
+    }
+  }
+  $relation_types = relation_get_types($types);
+  foreach ($relation_types as $name => $relation_type) {
+    // Add the allowed source entity types to the list
+    if (!empty($relation_type->source_bundles)) {
+      foreach ($relation_type->source_bundles as $source_bundle) {
+        list($entity_type,) = explode(':', $source_bundle, 2);
+        $options[$entity_type] = $all_entity_types[$entity_type];
+      }
+    }
+    // Add the allowed target entity types to the list
+    if (!empty($relation_type->target_bundles)) {
+      foreach ($relation_type->target_bundles as $target_bundle) {
+        list($entity_type,) = explode(':', $target_bundle, 2);
+        $options[$entity_type] = $all_entity_types[$entity_type];
+      }
+    }
+  }
+  return $options;
+}
+
+/**
+ * Info alter callback for the fetch_endpoint action.
+ */
+function relation_rules_fetch_endpoint_info_alter(&$element_info, $element) {
+  $element->settings += array('relation:select' => NULL);
+  if ($wrapper = $element->applyDataSelector($element->settings['relation:select'])) {
+    // We only make this parameter available after we've selected the relation. This way we
+    // can limit the entity type list to only those relative to the selected relation.
+    $element_info['parameter']['entity_type'] = array(
+      'type' => 'text',
+      'label' => t('Entity type'),
+      'options list' => 'relation_rules_fetch_endpoint_type_options',
+      'description' => t('Select the specific entity type to return.'),
+    );
+    if (!empty($element->settings['entity_type'])) {
+      // Having a number parameter allows us to be flexible between returning a list or a single entity.
+      $element_info['parameter']['number'] = array(
+        'type' => 'integer',
+        'label' => t('How many endpoints to return'),
+        'default value' => 1,
+        'description' => t('The number of enitites to return that match the above entity type criteria and in what form (single entity or a list). !zero returns a list containing every entity found; The default !one will return a single entity; !gt1 returns a list with maximum the specified number of entities.', array('!zero' => '<strong>0</strong>', '!one' => '<strong>1</strong>', '!gt1' => '<strong># &gt; 1</strong>')),
+      );
+      // Set the returned entity type so we can access all the data.
+      if (!empty($element->settings['number']) && (1 == $element->settings['number'])) {
+        $element_info['provides']['endpoint_fetched']['type'] = $element->settings['entity_type']; // only one.
+      } else {
+        $element_info['provides']['endpoint_fetched']['type'] = 'list<' . $element->settings['entity_type'] . '>'; // more then one.
+      }
+    }
+  }
+}
+
+/**
+ * Form alter callback for the fetch_endpoint action.
+ */
+function relation_rules_fetch_endpoint_form_alter(&$form, &$form_state, $options, RulesAbstractPlugin $element) {
+  $first_step  = empty($element->settings['relation:select']);
+  $second_step = (!$first_step && empty($element->settings['entity_type']));
+  $form['reload'] = array(
+    '#weight' => 5,
+    '#type' => 'submit',
+    '#name' => 'reload',
+    '#value' => $first_step ? t('Continue') : t('Reload form'),
+    '#limit_validation_errors' => array(array('parameter', 'relation')),
+    '#submit' => array('rules_action_type_form_submit_rebuild'),
+    '#ajax' => rules_ui_form_default_ajax(),
+    '#description' => $first_step ? '' : t('Reload the form to change the entity/bundle types list.'),
+  );
+  // Use ajax and trigger as the reload button.
+  $form['parameter']['relation']['settings']['relation:select']['#ajax'] = $form['reload']['#ajax'] + array(
+    'event' => 'blur',
+    'trigger_as' => array('name' => 'reload'),
+  );
+
+  if ($first_step  || $second_step) {
+    // In the first step and second step only show relevant parameters.
+    foreach (element_children($form['parameter']) as $key) {
+      if (($key != 'relation') && !($second_step && ($key == 'entity_type'))) {
+        unset($form['parameter'][$key]);
+      }
+    }
+    unset($form['submit']);
+    unset($form['provides']);
+  } else {
+    // Change the entity parameter to be not editable.
+    $form['parameter']['relation']['settings']['#access'] = FALSE;
+    $form['parameter']['relation']['info'] = array(
+      '#prefix' => '<p>',
+      '#markup' => t('<strong>Selected relation:</strong> %selector', array('%selector' => $element->settings['relation:select'])),
+      '#suffix' => '</p>',
+    );
+    // Hide the reload button in case js is enabled and it's not the first step.
+    $form['reload']['#attributes'] = array('class' => array('rules-hide-js'));
+  }
+  // Add #ajax to the entity_type selection dropdown to reload the form.
+  if(isset($form['parameter']['entity_type'])) {
+    $form['parameter']['entity_type']['#ajax'] = rules_ui_form_default_ajax() + array(
+      'event' => 'change',
+      'trigger_as' => array('name' => 'reload'),
+    );
+  }
+  // Add #ajax to the number parameter to allow us to change the type of the provided variable.
+  if(isset($form['parameter']['number'])) {
+    $form['parameter']['number']['#ajax'] = rules_ui_form_default_ajax() + array(
+      'event' => 'change',
+      'trigger_as' => array('name' => 'reload'),
+    );
+  }
+
+  // Disable #ajax for the 'relation:select' as it has troubles with lazy-loaded JS.
+  // @TODO: Re-enable once JS lazy-loading is fixed in core.
+  unset($form['parameter']['relation']['settings']['relation:select']['#ajax']);
+}
+
+/**
+ * Action callback fetching a given number of endpoint entities for a particular relation.
+ */
+function relation_rules_fetch_endpoint($relation, $entity_type, $number = 1) {
+  // Make sure we have the fully loaded relation entity.
+  $loaded_relation = relation_load($relation->rid);
+  // Load the endpoints
+  $endpoints = field_get_items('relation', $loaded_relation, 'endpoints');
+
+  $entity_ids = array();
+  foreach ($endpoints as $endpoint) {
+    // We only want to return entities of the selected type.
+    if (!empty($endpoint['entity_type']) && $entity_type == $endpoint['entity_type']) {
+      $entity_ids[] = $endpoint['entity_id'];
+      if ($number == count($entity_ids)) break;
+    }
+  }
+  if ($entity_ids) {
+    $return = entity_load($entity_type, $entity_ids);
+    // Return a list unless we are only supposed to return a single entity.
+    if (1 == $number) {
+      $return = reset($return);
+      if (!$return) {
+        throw new RulesEvaluationException('Unable to load relation endpoint of type "@type" for @entity with id "@id".', array('@type' => $entity_type,'@entity' => $relation->relation_type, '@id' => $relation->rid));
+      }
+    }
+    return array('endpoint_fetched' => $return);
+  }
+  // We didn't find any entities in the relation that matched the provided conditions.
+  return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation.tokens.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,155 @@
+<?php
+
+/**
+ * @file
+ * Builds placeholder replacement tokens for relation data.
+ */
+
+/**
+ * Implements hook_token_info().
+ */
+function relation_token_info() {
+  $type = array(
+    'name' => t('Relation'),
+    'description' => t('Tokens related to individual relations.'),
+    'needs-data' => 'relation',
+  );
+
+  // Core tokens for relations.
+  $relation['rid'] = array(
+    'name' => t("Relation ID"),
+    'description' => t('The unique ID of the relation.'),
+  );
+  $relation['vid'] = array(
+    'name' => t("Revision ID"),
+    'description' => t("The unique ID of the relation's latest revision."),
+  );
+  $relation['relation_type'] = array(
+    'name' => t("Relation type"),
+    'description' => t("The type of the relation."),
+  );
+  $relation['relation_type_label'] = array(
+    'name' => t("Relation type label"),
+    'description' => t("The human-readable name of the relation type."),
+  );
+//   $relation['title'] = array(
+//     'name' => t("Title"),
+//     'description' => t("The title of the relation."),
+//   );
+  $relation['url'] = array(
+    'name' => t("URL"),
+    'description' => t("The URL of the relation."),
+  );
+  $relation['edit-url'] = array(
+    'name' => t("Edit URL"),
+    'description' => t("The URL of the relation's edit page."),
+  );
+
+  // Chained tokens for relations.
+  $relation['created'] = array(
+    'name' => t("Date created"),
+    'description' => t("The date the relation was created."),
+    'type' => 'date',
+  );
+  $relation['changed'] = array(
+    'name' => t("Date changed"),
+    'description' => t("The date the relation was most recently updated."),
+    'type' => 'date',
+  );
+  $relation['author'] = array(
+    'name' => t("Author"),
+    'description' => t("The author of the relation."),
+    'type' => 'user',
+  );
+
+  return array(
+    'types' => array('relation' => $type),
+    'tokens' => array('relation' => $relation),
+  );
+}
+
+/**
+ * Implements hook_tokens().
+ */
+function relation_tokens($type, $tokens, array $data = array(), array $options = array()) {
+  $url_options = array('absolute' => TRUE);
+  if (isset($options['language'])) {
+    $url_options['language'] = $options['language'];
+    $language_code = $options['language']->language;
+  }
+  else {
+    $language_code = NULL;
+  }
+  $sanitize = !empty($options['sanitize']);
+
+  $replacements = array();
+
+  if ($type == 'relation' && !empty($data['relation'])) {
+    $relation = $data['relation'];
+
+    foreach ($tokens as $name => $original) {
+      switch ($name) {
+        // Simple key values on the relation.
+        case 'rid':
+          $replacements[$original] = $relation->rid;
+          break;
+
+        case 'vid':
+          $replacements[$original] = $relation->vid;
+          break;
+
+        case 'relation_type':
+          $replacements[$original] = $sanitize ? check_plain($relation->relation_type) : $relation->type;
+          break;
+
+        case 'type-name':
+          $type_label = relation_get_type_label($relation);
+          $replacements[$original] = $sanitize ? check_plain($type_label) : $type_label;
+          break;
+
+        case 'url':
+          $replacements[$original] = url('relation/' . $relation->rid, $url_options);
+          break;
+
+        case 'edit-url':
+          $replacements[$original] = url('relation/' . $relation->rid . '/edit', $url_options);
+          break;
+
+        // Default values for the chained tokens handled below.
+        case 'author':
+          if ($relation->uid == 0) {
+            $name = variable_get('anonymous', t('Anonymous'));
+          }
+          else {
+            $user = user_load($relation->uid);
+            $name = $user->name;
+          }
+          $replacements[$original] = $sanitize ? filter_xss($name) : $name;
+          break;
+
+        case 'created':
+          $replacements[$original] = format_date($relation->created, 'medium', '', NULL, $language_code);
+          break;
+
+        case 'changed':
+          $replacements[$original] = format_date($relation->changed, 'medium', '', NULL, $language_code);
+          break;
+      }
+    }
+
+    if ($author_tokens = token_find_with_prefix($tokens, 'author')) {
+      $author = user_load($relation->uid);
+      $replacements += token_generate('user', $author_tokens, array('user' => $author), $options);
+    }
+
+    if ($created_tokens = token_find_with_prefix($tokens, 'created')) {
+      $replacements += token_generate('date', $created_tokens, array('date' => $relation->created), $options);
+    }
+
+    if ($changed_tokens = token_find_with_prefix($tokens, 'changed')) {
+      $replacements += token_generate('date', $changed_tokens, array('date' => $relation->changed), $options);
+    }
+  }
+
+  return $replacements;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_dummy_field/relation_dummy_field.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Relation Dummy Field
+description = Dummy field to display relation data inline on entities.
+core = 7.x
+package = Relation
+dependencies[] = relation
+files[] = tests/relation_dummy_field.test
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-1.0-rc4"
+core = "7.x"
+project = "relation"
+datestamp = "1360240967"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_dummy_field/relation_dummy_field.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,210 @@
+<?php
+
+/**
+ * @file
+ * A field storing arbitrary relations between entities.
+ */
+
+/**
+ * Implements hook_field_info().
+ */
+function relation_dummy_field_field_info() {
+  return array(
+    'relation' => array(
+      'label' => t('Relation'),
+      'description' => t('Stores relationships between entities.'),
+      'settings' => array(),
+      'default_widget' => 'relation_default',
+      'default_formatter' => 'relation_default',
+      'instance_settings' => array('relation_type' => ''),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function relation_dummy_field_field_is_empty($item, $field) {
+  return FALSE;
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function relation_dummy_field_field_instance_settings_form($field, $instance) {
+  $relation_types = relation_get_types();
+  $bundle_key = $instance['entity_type'] . ':' . $instance['bundle'];
+  $bundle_wildcard_key = $instance['entity_type'] . ':' . '*';
+  $options = array();
+  foreach ($relation_types as $relation_type => $relation_type_data) {
+    foreach ($relation_type_data->source_bundles as $relation_bundle_key) {
+      if ($bundle_key == $relation_bundle_key || $bundle_wildcard_key == $relation_bundle_key) {
+        $options[$relation_type] = $relation_type_data->label;
+      }
+    }
+  }
+  $form['relation_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Relation types'),
+    '#description' => t('Select all the relation types you want to display in the dummy field. Only relation types applicable to this entity bundle are show here. If no relation_types are selected, relations of all types will be displayed.'),
+    '#default_value' => $instance['settings']['relation_type'],
+    '#options' => $options,
+    '#multiple' => TRUE,
+  );
+  return $form;
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function relation_dummy_field_field_widget_info() {
+  return array(
+    'relation_default' => array(
+      'label' => t('No edit widget'),
+      'field types' => array('relation'),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function relation_dummy_field_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function relation_dummy_field_field_formatter_info() {
+  return array(
+    'relation_default' => array(
+      'label' => t('Default'),
+      'field types' => array('relation'),
+    ),
+    'relation_otherendpoint' => array(
+      'label' => t('Other endpoint'),
+      'field types' => array('relation'),
+    ),
+    'relation_natural' => array(
+      'label' => t('Natural language'),
+      'field types' => array('relation'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function relation_dummy_field_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $element = array();
+  list($entity_id) = entity_extract_ids($entity_type, $entity);
+  switch ($display['type']) {
+    case 'relation_default':
+    case 'relation_otherendpoint':
+      foreach ($items as $delta => $item) {
+        $links = array();
+        $relation = (object) $item;
+        foreach (array_filter($relation->endpoints[LANGUAGE_NONE]) as $endpoint) {
+          $related_entities = entity_load($endpoint['entity_type'], array($endpoint['entity_id']));
+          $related_entity = reset($related_entities);
+          if ($endpoint['entity_type'] == $entity_type && $endpoint['entity_id'] == $entity_id) {
+            if ($display['type'] == 'relation_otherendpoint') {
+              continue;
+            }
+            $link = array();
+          }
+          else {
+            $link = entity_uri($endpoint['entity_type'], $related_entity);
+            $link['href'] = $link['path'];
+          }
+          $link['title'] = entity_label($endpoint['entity_type'], $related_entity);
+          $links[] = $link;
+        }
+        $uri = entity_uri('relation', $relation);
+        $relation_link = l(t('Relation @rid', array('@rid' => $relation->rid)), $uri['path'], $uri['options']);
+        // Can't use #heading as it's mercilessly check_plain'd.
+        $element[$delta]['relation']['heading']['#markup'] = t('<h4>Part of !link</h4>', array('!link' => $relation_link));
+        $element[$delta]['relation']['heading']['#access'] = $display['type'] == 'relation_default';
+        $element[$delta]['relation']['links'] = array(
+          '#theme' => 'links',
+          '#links' => $links,
+        );
+      }
+      break;
+
+    case 'relation_natural':
+      $sentences = array();
+      foreach ($items as $delta => $item) {
+        list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
+        $relation = (object) $item;
+        $relation_type = relation_type_load($relation->relation_type);
+
+        $subject = entity_label($entity_type, $entity) . ' '; // Subject of the sentence.
+        $subject_is_source = ($relation->endpoints[LANGUAGE_NONE]['0']['entity_id']) == $id ? TRUE : FALSE;
+        $count = 0; // For comma separation of objects.
+        $duplicate = FALSE; // To make sure duplicates of $entity get included in object list.
+        $objects = ''; // Comma separated list of entities that are the object of the sentence.
+        // Gramatical predicate of teh sentence.
+        $predicate = $relation_type->directional ? $relation_type->reverse_label : $relation_type->label;
+
+        foreach ($relation->endpoints[LANGUAGE_NONE] as $endpoint) {
+          // Add all entities that aren't this entity to the sentence $objects.
+          // Check for duplicates of the $subject first.
+          if ($endpoint['entity_type'] == $entity_type && $endpoint['entity_id'] == $id && $duplicate == FALSE) {
+            $duplicate = TRUE;
+            // Use the forward label as sentence predicate if r_index == 0.
+            // (only makes a difference if relation is directional).
+            if ($endpoint['r_index'] == 0) {
+              $predicate = ' ' . $relation_type->label;
+            }
+          }
+          else {
+            // If the relation is directional and the subject isn't the source,
+            // we want to list the source without any siblings. If it is
+            // directional and the subject is a source, list all targets.
+            // If non-directional, list everything as normal.
+            if (!$relation_type->directional || $subject_is_source || $endpoint['r_index'] == 0) {
+              $object_entities = entity_load($endpoint['entity_type'], array($endpoint['entity_id']));
+              $object_entity = reset($object_entities);
+              $object_label = entity_label($endpoint['entity_type'], $object_entity);
+              $object_uri = entity_uri($endpoint['entity_type'], $object_entity);
+              // Just add a space before the first element, comma and space before further ones.
+              $objects .= $count ? ', ' : ' ';
+              $count += 1;
+              $objects .= l($object_label, $object_uri['path']);
+            }
+          }
+        }
+        $element[$delta]['relation'] = array(
+          '#theme' => 'item_list',
+          '#items' => array($subject . $predicate . $objects),
+        );
+      }
+      break;
+  }
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_prepare_view().
+ */
+function relation_dummy_field_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
+  foreach ($entities as $id => $entity) {
+    $relation_types = $instances[$id]['settings']['relation_type'];
+    $query = relation_query($entity_type, $id)->range(0, 50);
+    if ($relation_types) {
+      $query->entityCondition('bundle', $relation_types, 'IN');
+    }
+    $relation_ids = array_keys($query->execute());
+    // Who knows why but field does not like if the delta does not start at 0...
+    $items[$id] = array();
+    foreach (entity_load('relation', $relation_ids) as $relation) {
+      $items[$id][] = (array) $relation;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_dummy_field/tests/relation_dummy_field.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Tests for Relation Dummy Field module.
+ */
+
+/**
+ * Functional test of Relation's integration with the Dummy Field.
+ */
+class RelationDummyFieldTestCase extends RelationTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Relation Dummy Field test',
+      'description' => 'Tests the Relation Dummy Field.',
+      'group' => 'Relation',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('relation', 'relation_dummy_field');
+  }
+
+  /**
+   * Create a relation field on the Article node type, and
+   * check if it displays the relations correctly on the node page.
+   */
+  function testDummyFieldDisplayed() {
+    $this->drupalGet('node/' . $this->node1->nid);
+    $this->assertNoRaw($this->node4->title, 'Node 4 title is not found');
+    $this->field_name = drupal_strtolower($this->randomName()) . '_field_name';
+    $field = array(
+      'field_name' => $this->field_name,
+      'type' => 'relation',
+      'entity_types' => array('node'),
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => $this->field_name,
+      'entity_type' => 'node',
+      'bundle' => 'article',
+      'label' => $this->randomString(),
+      'widget_type' => 'relation_default',
+      'display' => array(
+        'default' => array(
+          'label' => 'hidden',
+          'type' => 'relation_default',
+        ),
+        'teaser' => array(
+          'label' => 'hidden',
+          'type' => 'hidden',
+        ),
+      ),
+    );
+    field_create_instance($instance);
+    $this->drupalGet('node/' . $this->node1->nid);
+    // As we have asserted Node 4 title not being on the page the only way this
+    // click can succeed if the field formatter put it there.
+    $this->clickLink($this->node4->title);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_endpoint.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,11 @@
+name = Relation Endpoints Field
+description = Helper module for Relation. Defines endpoints field (not usable except by relation).
+core = 7.x
+package = Relation
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-1.0-rc4"
+core = "7.x"
+project = "relation"
+datestamp = "1360240967"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_endpoint.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Installation functions for Relation Endpoint field type module.
+ */
+
+/**
+ * Implements hook_field_schema().
+ */
+function relation_endpoint_field_schema() {
+  $columns = array(
+    'entity_type' => array(
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => TRUE,
+      'default' => '',
+      'description' => 'Entity_type of this relation end-point.',
+    ),
+    'entity_id' => array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'default' => 0,
+      'description' => 'Entity_id of this relation end-point.',
+    ),
+    'r_index' => array(
+      'type' => 'int',
+      'unsigned' => TRUE,
+      'not null' => TRUE,
+      'default' => 0,
+      'description' => 'The index of this row in this relation. The highest index in the relation is stored as "arity" in the relation table.',
+    ),
+  );
+  return array(
+    'columns' => $columns,
+    'indexes' => array(
+      'relation' => array('entity_type', 'entity_id', 'r_index'),
+    ),
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_endpoint.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+<?php
+
+/**
+ * @file
+ * Relation endpoints field.
+ */
+
+/**
+ * Implements hook_field_info().
+ */
+function relation_endpoint_field_info() {
+  return array(
+    'relation_endpoint' => array(
+      'label' => t('Relation endpoint'),
+      'description' => t('This field contains the endpoints of the relation'),
+      'default_widget' => 'relation_endpoint',
+      'default_formatter' => 'relation_endpoint',
+      'entity types' => array('relation'),
+      'no_ui' => TRUE,
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_validate().
+ */
+function relation_endpoint_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+  if (empty($entity_type) && empty($entity)) {
+    return;
+  }
+
+  $relation_type = relation_type_load($entity->relation_type);
+  // Check that relation_type exists.
+  if (!$relation_type) {
+    $errors[$field['field_name']][$langcode][$delta][] = array(
+      'error' => 'relation_nonexistent_type',
+      'message' => t("The !relation_type relation type does not exist.", array('!relation_type' => $entity->relation_type)),
+    );
+  }
+  // Check if the relation type is unique and if so, check if a relation between
+  // those items exist already.
+  if ($relation_type->r_unique) {
+    $rids = relation_relation_exists($items, $entity->relation_type);
+    if ($rids && (!isset($entity->rid) || !isset($rids[$entity->rid]))) {
+      $errors[$field['field_name']][$langcode][0][] = array(
+        'error' => 'relation_already_exists',
+        'message' => t("The !relation_type is unique but the relation already exists.", array('!relation_type' => $entity->relation_type)),
+      );
+    }
+  }
+  // Check that arity is within acceptable bounds.
+  if (count($items) < $relation_type->min_arity && empty($entity->in_progress)) {
+    $errors[$field['field_name']][$langcode][0][] = array(
+      'error' => 'relation_too_few_endpoints',
+      'message' => t("Relation has too few end points (:relation_type min arity :min_arity)", array(':relation_type' => $entity->relation_type, ':min_arity' => $relation_type->min_arity)),
+    );
+  }
+  if ($relation_type->max_arity && count($items) > $relation_type->max_arity) {
+    $errors[$field['field_name']][$langcode][0][] = array(
+      'error' => 'relation_too_many_endpoints',
+      'message' => t("Relation has too many end points (:relation_type max arity :max_arity)", array(':relation_type' => $entity->relation_type, ':max_arity' => $relation_type->max_arity)),
+    );
+  }
+
+  // Load all entities referenced in $items via multiple load.
+  $items_to_load = array();
+  $loaded_items = array();
+  foreach ($items as $delta => $item) {
+    if (!isset($item['entity_bundle'])) {
+      $items_to_load[$item['entity_type']][] = $item['entity_id'];
+    }
+  }
+  foreach ($items_to_load as $entity_type => $ids) {
+    $loaded_items[$entity_type] = entity_load($entity_type, $ids);
+  }
+
+  // Check that each entity is has acceptable bundle type and index.
+  foreach ($items as $delta => $item) {
+    $acceptable = FALSE;
+    $directional = $relation_type->directional;
+    $endpoint = ($directional && ($delta > 0)) ? 'target' : 'source';
+    $end_bundles = $endpoint . '_bundles';
+    foreach ($relation_type->$end_bundles as $relation_bundle) {
+      if (!isset($item['entity_bundle'])) {
+        $endpoint_entity = $loaded_items[$item['entity_type']][$item['entity_id']];
+        list(, , $item['entity_bundle']) = entity_extract_ids($item['entity_type'], $endpoint_entity);
+      }
+      $relation_bundle_array = explode(':', $relation_bundle, 2);
+      if (($relation_bundle == $item['entity_type'] . ':' . $item['entity_bundle']) || (($item['entity_type'] == $relation_bundle_array[0]) && ($relation_bundle_array[1] == '*'))) {
+        $acceptable = TRUE;
+        break;
+      }
+    }
+    if (!$acceptable) {
+      $t_arguments = array('%relation_type' => $entity->relation_type, '@bundle' => $item['entity_bundle']);
+      if ($relation_type->directional) {
+        if ($endpoint == 'target') {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'relation_unsupported_target',
+            'message' => t("The %relation_type relation type does not allow @bundle entities as target.", $t_arguments),
+          );
+        }
+        else {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'relation_unsupported_source',
+            'message' => t("The %relation_type relation type does not allow @bundle entities as source.", $t_arguments),
+          );
+        }
+      }
+      else {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'relation_unsupported_endpoint',
+          'message' => t("The %relation_type relation type does not allow @bundle entities as an endpoint.", $t_arguments),
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_presave().
+ */
+function relation_endpoint_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // We need r_index here because EntityFieldQuery can't query on deltas.
+  foreach ($items as $delta => &$item) {
+    $item['r_index'] = $delta;
+  }
+}
+
+/**
+ * Implements hook_field_update().
+ */
+function relation_endpoint_field_update($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  // We do not update.
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function relation_endpoint_field_is_empty($item, $field) {
+  // We are never empty.
+  return FALSE;
+}
+
+/**
+ * Helper to create an HTML table representing a relation.
+ */
+function _relation_endpoint_field_create_html_table($endpoints) {
+  $entity_info = entity_get_info();
+  $list_items = array();
+  foreach ($endpoints as $delta => $endpoint) {
+    $entities = entity_load($endpoint['entity_type'], array($endpoint['entity_id']));
+    $entity = reset($entities);
+    $label = entity_label($endpoint['entity_type'], $entity);
+    $uri = entity_uri($endpoint['entity_type'], $entity);
+    if ($uri) {
+      $list_items[$delta] = array(l($label, $uri['path'], $uri['options']), $entity_info[$endpoint['entity_type']]['label']);
+    }
+    else {
+      $list_items[$delta] = array($label, $entity_info[$endpoint['entity_type']]['label']);
+    }
+  }
+  $headers = array(
+    t('Entity'),
+    array('width' => '22%', 'data' => t('Entity type')),
+  );
+  return array(
+    '#theme' => 'table',
+    '#header' => $headers,
+    '#rows' => $list_items,
+  );
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function relation_endpoint_field_widget_info() {
+  return array(
+    'relation_endpoint' => array(
+      'label' => t('Endpoints table'),
+      'field types' => array('relation_endpoint'),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function relation_endpoint_field_formatter_info() {
+  $info = array(
+    'relation_endpoint' => array(
+      'label' => t('Endpoints table'),
+      'field types' => array('relation_endpoint'),
+    ),
+    'relation_endpoint_full' => array(
+      'label' => t('Full entities list'),
+      'field types' => array('relation_endpoint'),
+    ),
+  );
+  foreach (entity_get_info() as $entity_type => $data) {
+    $info['relation_endpoint_full']['settings']['view_modes'][$entity_type] = 'default';
+    $info['relation_endpoint']['settings']['view_modes'][$entity_type] = 'default';
+  }
+  return $info;
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function relation_endpoint_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $view_modes_settings = $instance['display'][$view_mode]['settings']['view_modes'];
+  foreach (_relation_endpoint_get_endpoint_entity_types($instance) as $endpoint_entity_type => $v) {
+    $entity_info = entity_get_info($endpoint_entity_type);
+    $options = array();
+    foreach ($entity_info['view modes'] as $entity_view_mode => $data) {
+      $options[$entity_view_mode] = $data['label'];
+    }
+    $element['#tree'] = TRUE;
+    $element['view_modes'][$endpoint_entity_type] = array(
+      '#title' => t('@endpoint_entity_type view mode', array('@endpoint_entity_type' => $endpoint_entity_type)),
+      '#type' => 'select',
+      '#default_value' => $view_modes_settings[$endpoint_entity_type],
+      '#options' => $options,
+    );
+  }
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function relation_endpoint_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $view_modes_settings = $instance['display'][$view_mode]['settings']['view_modes'];
+  foreach (_relation_endpoint_get_endpoint_entity_types($instance) as $endpoint_entity_type => $v) {
+    $items[] = "$endpoint_entity_type: " . $view_modes_settings[$endpoint_entity_type];
+  }
+  return theme('item_list', array('items' => $items));
+}
+
+/**
+ * Helper getting endpoint entity types for the bundle specified in $instance.
+ */
+function _relation_endpoint_get_endpoint_entity_types($instance) {
+  $relation_type = relation_type_load($instance['bundle']);
+  $bundles = $relation_type->source_bundles + $relation_type->target_bundles;
+  foreach ($bundles as $bundle_key) {
+    list($endpoint_entity_type) = explode(':', $bundle_key);
+    $endpoint_entity_types[$endpoint_entity_type] = TRUE;
+  }
+  return $endpoint_entity_types;
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function relation_endpoint_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  switch ($display['type']) {
+    case 'relation_endpoint':
+      $build[] = _relation_endpoint_field_create_html_table($items);
+      break;
+    case 'relation_endpoint_full':
+      $list_items = array();
+      $endpoint_entity_type = '';
+      $multiple = TRUE;
+      foreach ($items as $delta => $endpoint) {
+        if (!$endpoint_entity_type) {
+          $endpoint_entity_type = $endpoint['entity_type'];
+        }
+        if ($endpoint_entity_type == $endpoint['entity_type']) {
+          $entity_ids[] = $endpoint['entity_id'];
+        }
+        else {
+          $multiple = FALSE;
+          break;
+        }
+      }
+      $view_mode = isset($display['settings']['view_modes'][$endpoint_entity_type]) ? $display['settings']['view_modes'][$endpoint_entity_type] : 'full';
+      if ($multiple) {
+        $entities = entity_load($endpoint_entity_type, $entity_ids);
+        if (function_exists('entity_view')) {
+          return array(entity_view($endpoint_entity_type, $entities, $view_mode));
+        }
+        $function = $endpoint_entity_type . '_view_multiple';
+        if (function_exists($function)) {
+          return array($function($entities, $view_mode));
+        }
+      }
+      $build = array();
+      foreach ($items as $delta => $endpoint) {
+        if ($multiple) {
+          $entity = $entities[$endpoint['entity_id']];
+        }
+        else {
+          $entities = entity_load($endpoint['entity_type'], array($endpoint['entity_id']));
+          $entity = reset($entities);
+        }
+        if (function_exists('entity_view')) {
+          $build[$delta] = entity_view($endpoint['entity_type'], array($entity), $view_mode);
+        }
+        else {
+          $function = $endpoint['entity_type'] . '_view';
+          $build[$delta] = $function($entity, $view_mode);
+        }
+      }
+  }
+  return $build;
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function relation_endpoint_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  foreach ($items as $delta => $item) {
+    foreach (array('entity_type', 'entity_id') as $column) {
+      $element[$delta][$column] = array(
+        '#type' => 'value',
+        '#value' => $item[$column],
+      );
+    }
+  }
+  $element['link_list'] = _relation_endpoint_field_create_html_table($items);
+  return $element;
+}
+
+/**
+ * Implements hook_form_field_ui_field_overview_form_alter().
+ */
+function relation_endpoint_form_field_ui_field_overview_form_alter(&$form, $form_state) {
+  // Deleting endpoints would make the module useless.
+  if ($form['#entity_type'] == 'relation') {
+    $form['fields']['endpoints']['delete'] = array(
+      '#type' => 'markup',
+      '#markup' => '&nbsp;',
+    );
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_entity_collector/relation_entity_collector.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,3 @@
+#relation-entity-collector input.form-text, #relation-entity-collector select.form-select {
+  width: 100%;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_entity_collector/relation_entity_collector.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+name = Relation Entity Collector block
+description = A block to collect entities loaded on any page(s), and create relations from them.
+core = 7.x
+package = Relation
+dependencies[] = relation
+dependencies[] = block
+files[] = tests/relation_entity_collector.test
+stylesheets[all][] = relation_entity_collector.css
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-1.0-rc4"
+core = "7.x"
+project = "relation"
+datestamp = "1360240967"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_entity_collector/relation_entity_collector.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,515 @@
+<?php
+
+/**
+ * @file
+ * Relation Entity Collector Block.
+ */
+
+/**
+ * Implements hook_block_info().
+ */
+function relation_entity_collector_block_info() {
+  return array(
+    'block' => array(
+      'info' => t('Relation Entity Collector'),
+      'status' => 1,
+      'weight' => 100,
+      'region' => 'content',
+    ),
+  );
+}
+
+/**
+ * Implements hook_block_view().
+ */
+function relation_entity_collector_block_view() {
+  if (_relation_entity_collector_user_has_access()) {
+    $block['subject'] = t('Entity Collector');
+    $block['content']['#pre_render'] = array('relation_entity_collector_pre_render');
+    return $block;
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function relation_entity_collector_theme() {
+  return array(
+    'relation_entity_collector_table' => array(
+      'render element' => 'form',
+    ),
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function relation_entity_collector_menu() {
+  $items['relation_entity_collector/%relation'] = array(
+    'title' => '',
+    'access callback' => TRUE,
+    'page callback' => 'relation_entity_collector_store',
+    'page arguments' => array(1),
+  );
+  return $items;
+}
+
+/**
+ * Page callback copying a relation into SESSION.
+ */
+function relation_entity_collector_store($relation) {
+  $_SESSION['relation_edit'] = $relation;
+  $_SESSION['relation_type'] = $relation->relation_type;
+  $_SESSION['relation_entity_keys'] = array();
+  foreach ($relation->endpoints[LANGUAGE_NONE] as $delta => $endpoint) {
+    $entities = entity_load($endpoint['entity_type'], array($endpoint['entity_id']));
+    $entity = $entities[$endpoint['entity_id']];
+    list( , , $entity_bundle) = entity_extract_ids($endpoint['entity_type'], $entity);
+    $_SESSION['relation_entity_keys'][] = array(
+      'entity_type' => $endpoint['entity_type'],
+      'entity_id' => $endpoint['entity_id'],
+      'entity_bundle' => $entity_bundle,
+      'r_index' => $delta,
+      'entity_label' => "$entity_bundle: " . entity_label($endpoint['entity_type'], $entity),
+      'entity_key' => $endpoint['entity_type'] . ':' . $endpoint['entity_id'],
+    );
+  }
+  drupal_set_message(t('The relation is ready for edit'));
+  drupal_goto();
+}
+
+/**
+ * Implements hook_entity_view_alter().
+ */
+function relation_entity_collector_entity_view_alter(&$build, $entity_type) {
+  if ($entity_type == 'relation' && _relation_entity_collector_user_has_access()) {
+    $relation = $build['#entity'];
+    $text = t('Edit @relation_type endpoints', array('@relation_type' => $relation->relation_type));
+    $build['link']['#markup'] = l($text, "relation_entity_collector/$relation->rid", drupal_get_destination());
+  }
+}
+
+/**
+ * Access check helper.
+ */
+function _relation_entity_collector_user_has_access() {
+  return user_access('administer relations') || user_access('create relations');
+}
+
+/**
+ * Pre render callback for the entity_collector block.
+ */
+function relation_entity_collector_pre_render($element) {
+  $element['form'] = drupal_get_form('relation_entity_collector');
+  return $element;
+}
+
+/**
+ * Implements hook_entity_load().
+ */
+function relation_entity_collector_entity_load($entities, $type) {
+  $entities_store = &drupal_static('relation_entities', array());
+  $entities_store += array($type => array());
+  $entities_store[$type] += $entities;
+}
+
+/**
+ * The entity_collector form.
+ */
+function relation_entity_collector($form, &$form_state) {
+  $form['#attached']['css'] = array(
+    drupal_get_path('module', 'relation_entity_collector') . '/relation_entity_collector.css',
+  );
+  $types = relation_get_types();
+  if (empty($types)) {
+    $form['explanation']['#markup'] = t('Before you can create relations, you need to create one or more !link. Once you\'ve done that, visit any page that loads one or more entities, and use this block to add entities to a new relation. Picked entities stay in the entity_collector until cleared or a relation is created so it is possible to collect the entities from several pages.', array(
+      '!link' => module_exists('relation_ui') ? l(t('relation types'), 'admin/structure/relation') : t('relation types')
+    ));
+    return $form;
+  }
+  $relation_types = array();
+  foreach ($types as $type) {
+    $relation_types[$type->relation_type] = $type->label;
+  }
+  $relation_type = isset($_SESSION['relation_type']) ? $_SESSION['relation_type'] : '';
+  // forget the selected relation type if it's no longer available
+  if (!isset($relation_types[$relation_type])) {
+    unset($_SESSION['relation_type']);
+    $relation_type = '';
+  }
+  if ($relation_entities = drupal_static('relation_entities', array())) {
+    $options = array();
+    foreach ($relation_entities as $entity_type => $entities) {
+      foreach ($entities as $entity_id => $entity) {
+        list( , , $entity_bundle) = entity_extract_ids($entity_type, $entity);
+        if ($relation_type) {
+          $relation_type_object = relation_type_load($relation_type);
+          $valid = FALSE;
+          foreach (array('source_bundles', 'target_bundles') as $property) {
+            foreach ($relation_type_object->$property as $allowed_bundle) {
+              if ($allowed_bundle == "$entity_type:$entity_bundle" || $allowed_bundle == "$entity_type:*") {
+                $valid = TRUE;
+                break;
+              }
+            }
+          }
+        }
+        else {
+          $valid = TRUE;
+        }
+        if ($valid) {
+          $options["$entity_type:$entity_id"] = "$entity_bundle: " . entity_label($entity_type, $entity);
+        }
+      }
+    }
+    asort($options);
+    $form_state['relation_entities_options'] = $options;
+  }
+  if (empty($form_state['relation_entities_options'])) {
+    $form['explanation']['#markup'] = t('This block shows all loaded entities on a page and allows adding them to a relation. Please navigate to a page where entities are loaded. Entities picked stay in the entity_collector until cleared or a relation is created so it is possible to collect the entities from several pages.');
+    return $form;
+  }
+  $form['relation_type'] = array(
+    '#type'          => 'select',
+    '#title'         => t('Relation type'),
+    '#default_value' => $relation_type,
+    '#options'       => $relation_types,
+    '#empty_value'   => '',
+    '#empty_option'  => t('Select a relation type'),
+    '#access'        => empty($_SESSION['relation_edit']),
+  );
+  $form['entity_key'] = array(
+    '#type'           => 'select',
+    '#title'          => t('Select an entity'),
+    '#options'        => $form_state['relation_entities_options'],
+    '#default_value'  => '',
+    '#description'     => t('Selector shows all !entities loaded on this page.', array('!entities' => l(t('entities'), 'http://drupal.org/glossary#entity', array('absolute' => TRUE, 'external' => TRUE)))),
+  );
+  $form['pick'] = array(
+    '#type' => 'submit',
+    '#value' => t('Pick'),
+    '#submit' => array('relation_entity_collector_pick'),
+    '#ajax' => array(
+      'wrapper' => 'relation_entity_collector_reload',
+      'callback' => '_relation_entity_collector_ajax',
+    ),
+  );
+  $form['reload'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Picked entities'),
+  );
+  $form['reload']['#prefix'] = '<span id="relation_entity_collector_reload">';
+  $form['reload']['#suffix'] = '</span>';
+  if (!empty($_SESSION['relation_entity_keys'])) {
+    $form['reload']['table']['#entity_collector_columns'] = array(
+      'weight',
+      'remove',
+    );
+    foreach ($_SESSION['relation_entity_keys'] as $delta => $entity_key) {
+      // The structure is (entity_type, entity_id, entity label).
+      $form['reload']['table']['weight'][] = array(
+        '#type' => 'weight',
+        '#delta' => count($_SESSION['relation_entity_keys']),
+        '#default_value' => $delta,
+        '#title_display' => 'invisible',
+        '#title' => '',
+      );
+      $form['reload']['table']['remove'][] = array(
+        '#name' => 'remove-' . $entity_key['entity_key'],
+        '#type' => 'submit',
+        '#value' => t('Remove'),
+        '#entity_key' => $entity_key,
+        '#submit' => array('relation_entity_collector_remove'),
+        '#ajax' => array(
+          'wrapper' => 'relation_entity_collector_reload',
+          'callback' => '_relation_entity_collector_ajax',
+        ),
+      );
+      $form['reload']['table']['#tree'] = TRUE;
+      $form['reload']['table']['#theme'] = 'relation_entity_collector_table';
+    }
+    if (count($_SESSION['relation_entity_keys']) > 1) {
+      $form['reload']['save'] = array(
+        '#type' => 'submit',
+        '#value' => t('Save relation'),
+        '#submit' => array('relation_entity_collector_save'),
+      );
+    }
+    if (isset($_SESSION['relation_entity_keys'])) {
+      $form['reload']['clear'] = array(
+        '#type' => 'submit',
+        '#value' => t('Clear'),
+        '#submit' => array('relation_entity_collector_clear'),
+        '#ajax' => array(
+          'wrapper' => 'relation_entity_collector_reload',
+          'callback' => '_relation_entity_collector_ajax',
+        ),
+      );
+    }
+  }
+  $form['explanation'] = array(
+    '#prefix' => '<div id=\'relation-entity-collector-explanation\'>',
+    '#markup' => t('Picked entities stay in the Entity Collector until cleared or a relation is created so it is possible to collect the entities from several pages.'),
+    '#suffix' => '</div>',
+  );
+  return $form;
+}
+
+/**
+ * Trivial AJAX helper.
+ */
+function _relation_entity_collector_ajax($form) {
+  return $form['reload'];
+}
+
+/**
+ * Helper to get a item_list render structure out of the entities in session.
+ */
+function _relation_stored_entity_keys_list() {
+  $list = array();
+  foreach ($_SESSION['relation_entity_keys'] as $entity_key) {
+    $list[] = $entity_key['entity_label'];
+  }
+  return array(
+    '#theme' => 'item_list',
+    '#items' => $list,
+  );
+}
+
+/**
+ * Validate form submission for the entity_collector.
+ */
+function relation_entity_collector_validate($form, &$form_state) {
+  switch ($form_state['triggering_element']['#value']) {
+    case t('Pick'):
+      // Require values.
+      $relation_type = $form_state['values']['relation_type'];
+      $entity_key = $form_state['values']['entity_key'];
+      $errors = FALSE;
+      if (empty($relation_type)) {
+        form_set_error('relation_type', t('Please select a relation type.'));
+        $errors = TRUE;
+      }
+      if (empty($entity_key)) {
+        form_set_error('entity_key', t('Please select an entity.'));
+        $errors = TRUE;
+      }
+      // If either of these are not selected we can not continue.
+      if ($errors) {
+        return;
+      }
+      // Here we get (entity_type, entity_id).
+      $break = explode(':', $entity_key);
+      // Add the label for later display. #options is check_plain'd but we need
+      // to do that ourselves.
+      $entity_label = check_plain($form['entity_key']['#options'][$entity_key]);
+      $entity_label_array = explode(':', $entity_label, 2);
+      // Indexes are added in ascending order, starting from 0.
+      $_SESSION += array('relation_entity_keys' => array());
+      $next_index = count($_SESSION['relation_entity_keys']);
+      // If validation succeeds we will add this in the submit handler.
+      $form_state['pick'] = array(
+        'entity_type' => $break[0],
+        'entity_id' => $break[1],
+        'entity_bundle' => $entity_label_array[0],
+        'r_index' => $next_index,
+        'entity_label' => $entity_label,
+        'entity_key' => $entity_key,
+      );
+      $endpoints = $_SESSION['relation_entity_keys'];
+      $endpoints[] = $form_state['pick'];
+      $relation = _relation_entity_collector_get_entity($form_state['values']['relation_type'], $endpoints);
+      $relation->in_progress = TRUE;
+      _relation_entity_collector_endpoints_validate($relation, $form, $form_state);
+      field_attach_form_validate('relation', $relation, $form, $form_state);
+      break;
+    case t('Save relation'):
+      _relation_entity_collector_endpoints_validate(_relation_entity_collector_get_entity(), $form, $form_state);
+      break;
+  }
+}
+
+function _relation_entity_collector_endpoints_validate($relation, $form, &$form_state) {
+  // Perform field_level validation.
+  try {
+    field_attach_validate('relation', $relation);
+  }
+  catch (FieldValidationException $e) {
+    $index = 0;
+    // We do not look anything like a field widget so just pile the errors on
+    // nonexistent form elements.
+    foreach ($e->errors as $field_name => $field_errors) {
+      foreach ($field_errors as $langcode => $multiple_errors) {
+        foreach ($multiple_errors as $delta => $item_errors) {
+          foreach ($item_errors as $item_error) {
+            form_set_error('error' . $index++, $item_error['message']);
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Retrieves the relation being edited or picked.
+ */
+function _relation_entity_collector_get_entity($relation_type = NULL, $endpoints = NULL) {
+  if (!isset($relation_type) && isset($_SESSION['relation_type'])) {
+    $relation_type = $_SESSION['relation_type'];
+  }
+  if (!isset($endpoints) && isset($_SESSION['relation_entity_keys'])) {
+    $endpoints = $_SESSION['relation_entity_keys'];
+  }
+  if (isset($_SESSION['relation_edit'])) {
+    $relation = $_SESSION['relation_edit'];
+    if (isset($endpoints)) {
+      $relation->endpoints[LANGUAGE_NONE] = $endpoints;
+    }
+    return $relation;
+  }
+  if (isset($relation_type)) {
+    return relation_create($relation_type, $endpoints);
+  }
+}
+
+/**
+ * Submit handler for the pick button.
+ */
+function relation_entity_collector_pick($form, &$form_state) {
+  $_SESSION['relation_entity_keys'][] = $form_state['pick'];
+  $_SESSION['relation_type'] = $form_state['values']['relation_type'];
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Submit handler for the remove button.
+ */
+function relation_entity_collector_remove($form, &$form_state) {
+  $entity_key = $form_state['triggering_element']['#entity_key']['entity_key'];
+  foreach ($_SESSION['relation_entity_keys'] as $key => $entity) {
+    if ($entity['entity_key'] == $entity_key) {
+      unset($_SESSION['relation_entity_keys'][$key]);
+      $form_state['rebuild'] = TRUE;
+      return;
+    }
+  }
+}
+
+/**
+ * Submit handler for the save button.
+ */
+function relation_entity_collector_save($form, $form_state) {
+  $relation = _relation_entity_collector_get_entity();
+  if ($relation) {
+    array_multisort($form_state['values']['table']['weight'], SORT_ASC, $relation->endpoints[LANGUAGE_NONE]);
+    $rid = relation_save($relation);
+    if ($rid) {
+      $link = l(relation_get_type_label($relation), "relation/$rid");
+      $list = _relation_stored_entity_keys_list();
+      $rendered_list = drupal_render($list);
+      $t_arguments = array('!link' => $link, '!list' => $rendered_list);
+      if (isset($_SESSION['relation_edit'])) {
+        $message = t('Edited !link containing !list', $t_arguments);
+      }
+      else {
+        $message = t('Created new !link from !list', $t_arguments);
+      }
+      drupal_set_message($message);
+      relation_entity_collector_clear($form, $form_state);
+    }
+    else {
+      drupal_set_message(t('Relation not created.'), 'error');
+    }
+  }
+}
+
+/**
+ * Submit handler for the clear button.
+ */
+function relation_entity_collector_clear($form, &$form_state) {
+  unset($_SESSION['relation_type'], $_SESSION['relation_entity_keys'], $_SESSION['relation_edit']);
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Implements hook_views_post_execute().
+ *
+ * Make sure entities are loaded even if only fields are used.
+ */
+function relation_entity_collector_views_post_execute($view) {
+  if (_relation_entity_collector_user_has_access()) {
+    $properties = get_object_vars($view->query);
+    if (!empty($properties['fields']) && !empty($view->result)) {
+      foreach (entity_get_info() as $entity_type => $entity_info) {
+        $map[$entity_info['base table']] = array(
+          'id' => $entity_info['entity keys']['id'],
+          'entity_type' => $entity_type,
+        );
+      }
+      $collect = array();
+      foreach ($view->query->fields as $alias => $field) {
+        if (isset($field['table'])) {
+          $table_name = $view->query->table_queue[$field['table']]['table'];
+          if (isset($map[$table_name]) && $map[$table_name]['id'] == $field['field']) {
+            $collect[$map[$table_name]['entity_type']] = $alias;
+          }
+        }
+      }
+      $ids = array();
+      foreach ($view->result as $row) {
+        foreach ($collect as $entity_type => $alias) {
+          // Skip empty values, which may happen for entities that are obtained
+          // via a non-required relationship in the view.
+          if (!empty($row->$alias)) {
+            $ids[$entity_type][] = $row->$alias;
+          }
+        }
+      }
+      foreach ($ids as $entity_type => $entity_ids) {
+        entity_load($entity_type, $entity_ids);
+      }
+    }
+  }
+}
+
+/**
+ * Creates a draggable table out of the entities already picked.
+ */
+function theme_relation_entity_collector_table($variables) {
+  $form = $variables['form'];
+  $table['header'] = array();
+  $table['attributes']['id'] = 'relation-entity-collector-table';
+  $table['rows'] = array();
+  drupal_add_tabledrag($table['attributes']['id'], 'order', 'sibling', 'relation-entity-collector-weight');
+  foreach (element_children($form['weight']) as $key) {
+    $form['weight'][$key]['#attributes']['class'] = array('relation-entity-collector-weight');
+    $data = array($form['remove'][$key]['#entity_key']['entity_label']);
+    foreach ($form['#entity_collector_columns'] as $column) {
+      $data[] = drupal_render($form[$column][$key]);
+    }
+    $table['rows'][] = array(
+      'data' => $data,
+      'class' => array('draggable'),
+    );
+  }
+  $output = '';
+  if ($table['rows']) {
+    $output .= theme('table', $table);
+  }
+  return $output . drupal_render_children($form);
+}
+
+/**
+ * Implements hook_preprocess_username().
+ *
+ * We capture every user printed this way.
+ */
+function relation_entity_collector_preprocess_username($variables) {
+  if (_relation_entity_collector_user_has_access() && isset($variables['account']->nid)) {
+    // This looks like a node passed to theme('username') in
+    // template_preprocess_node() and user_node_load() doesn't load the user
+    // so we do instead. It does not work with modules using render arrays
+    // because it is called too late but Views renders early.
+    user_load($variables['account']->uid);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_entity_collector/tests/relation_entity_collector.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Tests for Relation Entity Collector module.
+ */
+
+/**
+ * Functional test of Relation's integration with the Entity Collector.
+ */
+class RelationEntityCollectorTestCase extends RelationTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Relation Entity Collector test',
+      'description' => 'Tests the Relation Entity Collector.',
+      'group' => 'Relation',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('relation', 'relation_ui', 'relation_entity_collector');
+    $this->drupalLogin($this->web_user);
+  }
+
+  /**
+   * Add relations to Node 1 and to Node 3 and then check that they are related.
+   */
+  function testEntityCollector() {
+    $node1key = 'node:' . $this->node1->nid;
+    $node3key = 'node:' . $this->node3->nid;
+
+    $relation_type = $this->relation_types['symmetric']['relation_type'];
+    $edit = array(
+      "relation_type" => $relation_type,
+      "entity_key" => $node1key,
+    );
+    $this->drupalPost('node', $edit, t('Pick'));
+    $edit = array(
+      "relation_type" => $relation_type,
+      "entity_key" => $node3key,
+    );
+    $this->drupalPost('node', $edit, t('Pick'));
+    $this->drupalPost('node', array(), t('Save relation'));
+    // Now figure out the new rid.
+    $result = array_keys(relation_query('node', $this->node3->nid)
+      ->propertyCondition('relation_type', $relation_type)
+      ->execute());
+    $path = 'relation/' . $result[0];
+    $link = l($relation_type, $path);
+    // Rebuild the message. Use the known node labels to make sure the message
+    // contains those.
+    $node1_label = entity_label('node', $this->node1);
+    $node3_label = entity_label('node', $this->node3);
+    $items = array(
+      "article: " . $node1_label,
+      "page: " . $node3_label,
+    );
+    $item_list = array(
+      '#theme' => 'item_list',
+      '#items' => $items,
+    );
+    $list = drupal_render($item_list);
+    $message = t('Created new !link from !list', array('!link' => $link, '!list' => $list));
+    $this->assertRaw($message, 'Created a new relation.');
+    $this->drupalGet($path);
+    $node1_uri = entity_uri('node', $this->node1);
+    $node3_uri = entity_uri('node', $this->node3);
+    $this->assertRaw(l($node1_label, $node1_uri['path'], $node1_uri['options']), 'Node1 link found');
+    $this->assertRaw(l($node3_label, $node3_uri['path'], $node3_uri['options']), 'Node1 link found');
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/relation_migrate.destination.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,205 @@
+<?php
+
+/**
+ * @file
+ * Support for relation destinations.
+ */
+
+/**
+ * Destination class implementing migration into relation.
+ */
+class MigrateDestinationRelation extends MigrateDestinationEntity {
+  static public function getKeySchema() {
+    return array(
+      'rid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Unique relation id (entity id).',
+      ),
+    );
+  }
+
+  /**
+   * Basic initialization
+   *
+   * @param string $bundle
+   *  A.k.a. the content type (page, article, etc.) of the node.
+   * @param array $options
+   *  Options applied to nodes.
+   */
+  public function __construct($bundle, array $options = array()) {
+    parent::__construct('relation', $bundle, $options);
+  }
+
+  /**
+   * Returns a list of fields available to be mapped for the relation type (bundle)
+   *
+   * @return array
+   *  Keys: machine names of the fields (to be passed to addFieldMapping)
+   *  Values: Human-friendly descriptions of the fields.
+   */
+  public function fields() {
+    $fields = array();
+    // First the core (relation table) properties
+    $fields['rid'] = t('Relation: Existing relation ID');
+    $fields['is_new'] = t('Relation: Indicates a new relation with the specified rid should be created');
+    $fields['uid'] = t('Relation: Authored by (uid)');
+    $fields['created'] = t('Relation: Created timestamp');
+    $fields['changed'] = t('Relation: Modified timestamp');
+
+    // Then add in anything provided by handlers
+    $fields += migrate_handler_invoke_all('Entity', 'fields', $this->entityType, $this->bundle);
+    $fields += migrate_handler_invoke_all('Relation', 'fields', $this->entityType, $this->bundle);
+
+    return $fields;
+  }
+
+  /**
+   * Delete a batch of relations at once.
+   *
+   * @param $rids
+   *  Array of relation IDs to be deleted.
+   */
+  public function bulkRollback(array $rids) {
+    migrate_instrument_start('relation_delete_multiple');
+    $this->prepareRollback($rids);
+    relation_delete_multiple($rids);
+    $this->completeRollback($rids);
+    migrate_instrument_stop('relation_delete_multiple');
+  }
+
+  /**
+   * Import a single relation.
+   *
+   * @param $relation
+   *  Relation object to build. Prefilled with any fields mapped in the Migration.
+   * @param $row
+   *  Raw source data object - passed through to prepare/complete handlers.
+   * @return array
+   *  Array of key fields (rid only in this case) of the relation that was saved if
+   *  successful. FALSE on failure.
+   */
+  public function import(stdClass $relation, stdClass $row) {
+    // Updating previously-migrated content?
+    $migration = Migration::currentMigration();
+    if (isset($row->migrate_map_destid1)) {
+      // Make sure is_new is off
+      $relation->is_new = FALSE;
+      if (isset($relation->rid)) {
+        if ($relation->rid != $row->migrate_map_destid1) {
+          throw new MigrateException(t("Incoming rid !rid and map destination rid !destid1 don't match",
+            array('!rid' => $relation->rid, '!destid1' => $row->migrate_map_destid1)));
+        }
+      }
+      else {
+        $relation->rid = $row->migrate_map_destid1;
+      }
+      // Get the existing vid, so updates don't generate notices
+      $values = db_select('relation', 'r')
+                   ->fields('r', array('vid'))
+                   ->condition('rid', $relation->rid)
+                   ->execute()
+                   ->fetchAssoc();
+      $relation->vid = $values['vid'];
+    }
+    if ($migration->getSystemOfRecord() == Migration::DESTINATION) {
+      if (!isset($relation->rid)) {
+        throw new MigrateException(t('System-of-record is DESTINATION, but no destination rid provided'));
+      }
+      $old_relation = relation_load($relation->rid);
+      if (!isset($relation->created)) {
+        $relation->created = $old_relation->created;
+      }
+      if (!isset($relation->vid)) {
+        $relation->vid = $old_relation->vid;
+      }
+      if (!isset($relation->uid)) {
+        $relation->uid = $old_relation->uid;
+      }
+    }
+
+    // Set some required properties.
+    if (!isset($relation->uid)) {
+      $relation->uid = $GLOBALS['user']->uid;
+    }
+    // Set type before invoking prepare handlers - they may take type-dependent actions.
+    $relation->relation_type = $this->bundle;
+
+    if ($migration->getSystemOfRecord() == Migration::SOURCE) {
+
+      // relation_save() will blow these away, so save them here and
+      // save them later.
+      if (isset($relation->created)) {
+        $created = MigrationBase::timestamp($relation->created);
+      }
+      if (isset($relation->changed)) {
+        $changed = MigrationBase::timestamp($relation->changed);
+      }
+    }
+
+    // Trying to update an existing relation
+    if ($migration->getSystemOfRecord() == Migration::DESTINATION) {
+      // Incoming data overrides existing data, so only copy non-existent fields
+      foreach ($old_node as $field => $value) {
+        // An explicit NULL in the source data means to wipe to old value (i.e.,
+        // don't copy it over from $old_node)
+        if (property_exists($relation, $field) && $relation->$field === NULL) {
+          // Ignore this field
+        }
+        elseif (!isset($relation->$field)) {
+          $relation->$field = $old_relation->$field;
+        }
+      }
+    }
+
+    // Invoke migration prepare handlers
+    $this->prepare($relation, $row);
+
+    if (isset($relation->rid) && empty($relation->is_new)) {
+      $updating = TRUE;
+    }
+    else {
+      $updating = FALSE;
+    }
+
+    // Save relation object
+    migrate_instrument_start('relation_save');
+    $rid = relation_save($relation);
+    migrate_instrument_stop('relation_save');
+
+    if (isset($relation->rid)) {
+      if ($updating) {
+        $this->numUpdated++;
+      }
+      else {
+        $this->numCreated++;
+      }
+
+      // Update changed and created dates if needed.
+      if (isset($changed)) {
+        db_update('relation')
+          ->fields(array('changed' => $changed))
+          ->condition('rid', $relation->rid)
+          ->execute();
+        $relation->changed = $changed;
+      }
+
+      if (isset($created)) {
+        db_update('relation')
+          ->fields(array('created' => $created))
+          ->condition('rid', $relation->rid)
+          ->execute();
+        $relation->created = $created;
+      }
+
+      $return = array($relation->rid);
+    }
+    else {
+      $return = FALSE;
+    }
+
+    $this->complete($relation, $row);
+    return $return;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/relation_migrate.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,20 @@
+name = Relation migrate
+description = Migrate integration module for Relation.
+core = 7.x
+package = Relation
+
+files[] = relation_migrate.destination.inc
+files[] = relation_migrate.source.inc
+files[] = relation_migrate.migration.inc
+files[] = tests/relation.migrate.test
+
+dependencies[] = relation
+dependencies[] = relation_ui
+dependencies[] = migrate
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-1.0-rc4"
+core = "7.x"
+project = "relation"
+datestamp = "1360240967"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/relation_migrate.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,19 @@
+<?php
+
+/**
+ * @file
+ * Install, uninstall and update hooks for relation_migrate.module.
+ */
+
+/**
+ * Implements hook_uninstall().
+ */
+function relation_migrate_uninstall() {
+  $types = array('entityreference', 'taxonomy_term_reference', 'node_reference', 'user_reference');
+
+  foreach ($types as $type) {
+    variable_del('relation_migrate_' . $type . '_fields');
+    variable_del('relation_migrate_' . $type . '_relation_type');
+    variable_del('relation_migrate_' . $type . '_user');
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/relation_migrate.migration.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @file
+ * Migration for entityreference fields.
+ */
+
+abstract class RelationMigrateReference extends Migration {
+  /**
+   * Constructor.
+   *
+   * @param $field_type Field type machine name.
+   */
+  public function __construct($field_type) {
+    parent::__construct();
+    $this->fields = array_filter(variable_get('relation_migrate_' . $field_type . '_fields', array()));
+    $this->relation_type = variable_get('relation_migrate_' . $field_type . '_relation_type', NULL);
+    $this->dependencies = array();
+    $this->description = 'Copy the contents from the ' . $field_type . ' fields to relation entities.';
+    $this->map = new MigrateSQLMap($this->machineName,
+      array(
+        'source_type' => array(
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+        ),
+        'source_id' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        ),
+        'destination_type' => array(
+          'type' => 'varchar',
+          'length' => 128,
+          'not null' => TRUE,
+        ),
+        'destination_id' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        ),
+        'delta' => array(
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+        ),
+      ),
+      MigrateDestinationRelation::getKeySchema()
+    );
+
+    $this->destination = new MigrateDestinationRelation($this->relation_type);
+
+    $this->addFieldMapping('uid')
+      ->defaultValue(variable_get('relation_migrate_' . $field_type . '_user', 1))
+      ->description(t('The owner of relation.'));
+  }
+
+  public function prepare(stdClass $relation, stdClass $source_row) {
+    $relation->endpoints[LANGUAGE_NONE] = array(
+      array('entity_type' => $source_row->source_type, 'entity_id' => $source_row->source_id),
+      array('entity_type' => $source_row->destination_type, 'entity_id' => $source_row->destination_id),
+    );
+  }
+}
+
+class RelationMigrateEntityReference extends RelationMigrateReference {
+  public function __construct() {
+    parent::__construct('entityreference');
+    $this->source = new MigrateSourceEntityReference($this->fields);
+  }
+}
+
+class RelationMigrateNodeReference extends RelationMigrateReference {
+  public function __construct() {
+    parent::__construct('node_reference');
+    $this->source = new MigrateSourceNodeReference($this->fields);
+  }
+}
+
+class RelationMigrateUserReference extends RelationMigrateReference {
+  public function __construct() {
+    parent::__construct('user_reference');
+    $this->source = new MigrateSourceUserReference($this->fields);
+  }
+}
+
+class RelationMigrateTermReference extends RelationMigrateReference {
+  public function __construct() {
+    parent::__construct('taxonomy_term_reference');
+    $this->source = new MigrateSourceTermReference($this->fields);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/relation_migrate.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * @file
+ * Migrations between *reference fields and relations.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function relation_migrate_menu() {
+  $items['admin/structure/relation/migrate'] = array(
+    'title' => 'Migration',
+    'access arguments' => array('administer relation types'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('relation_migrate_configuration_form'),
+    'description' => 'Configure migration between *reference fields and relations.',
+    'type' => MENU_LOCAL_TASK,
+  );
+
+  return $items;
+}
+
+/**
+ * Configuration form callback.
+ */
+function relation_migrate_configuration_form($form, &$form_state) {
+  $field_types = array(
+    'entityreference',
+    'taxonomy_term_reference',
+    'node_reference',
+    'user_reference',
+  );
+
+  foreach ($field_types as $field_type_name) {
+    $field_type_info = field_info_field_types($field_type_name);
+    $fields = field_read_fields(array('type' => $field_type_name));
+    if (!empty($field_type_info) && !empty($fields)) {
+      $form[$field_type_name] = array(
+        '#type' => 'fieldset',
+        '#title' => check_plain($field_type_info['label']),
+      );
+
+      $options = array();
+      foreach ($fields as $name => $field) {
+        $options[$name] = check_plain($name);
+      }
+
+      $form[$field_type_name]['relation_migrate_' . $field_type_name . '_fields'] = array(
+        '#type' => 'checkboxes',
+        '#title' => t('Fields'),
+        '#options' => $options,
+        '#default_value' => variable_get('relation_migrate_' . $field_type_name . '_fields', array()),
+        '#description' => t('Select fields of type %type, that should be migrated to relation entites.', array('%type' => $field_type_info['label'])),
+      );
+
+      $types = relation_get_types();
+      $rel_types = array();
+      foreach ($types as $machine_name => $type) {
+        $rel_types[$machine_name] = check_plain($type->label);
+      }
+
+      $form[$field_type_name]['relation_migrate_' . $field_type_name . '_relation_type'] = array(
+        '#type' => 'select',
+        '#title' => t('Relation type'),
+        '#options' => $rel_types,
+        '#default_value' => variable_get('relation_migrate_' . $field_type_name . '_relation_type', NULL),
+        '#description' => t('Select relation type that should be used when migrating reference fields.'),
+        '#element_validate' => array('_relation_migrate_validate_type'),
+      );
+
+      $user = user_load(variable_get('relation_migrate_' . $field_type_name . '_user', 1));
+      $form[$field_type_name]['relation_migrate_' . $field_type_name . '_user'] = array(
+        '#type' => 'textfield',
+        '#title' => t('User'),
+        '#default_value' => $user->name,
+        '#description' => t('User that should own created relations.'),
+        '#autocomplete_path' => 'user/autocomplete',
+        '#element_validate' => array('_relation_migrate_uid_validate'),
+      );
+    }
+  }
+
+  return system_settings_form($form);
+}
+
+/**
+ * Validate function for UID field at configuration form.
+ * Transforms user name to UID.
+ */
+function _relation_migrate_uid_validate($element, &$form_state, $form) {
+  $user = user_load_by_name($form_state['values'][$element['#name']]);
+  if ($user) {
+    $form_state['values'][$element['#name']] = $user->uid;
+  }
+  else {
+    form_error($element, t('User not found.'));
+  }
+}
+
+
+/**
+ * Validates relation type selection on configuration form.
+ *
+ * Check if selected relation type allows usage of source bundle.
+ */
+function _relation_migrate_validate_type($element, &$form_state, $form) {
+  if (!empty($form_state['input']['relation_migrate_' . $element['#array_parents'][0] . '_relation_type'])) {
+    module_load_include('inc', 'relation_migrate', 'relation_migrate.modules');
+    $field_type = field_info_field_types($element['#array_parents'][0]);
+    $relation_type = relation_type_load($form_state['input']['relation_migrate_' . $element['#array_parents'][0] . '_relation_type']);
+
+    $function = $field_type['module'] . '_relation_migrate_type_target_validate';
+    if (function_exists($function)) {
+      if (!$function($element, $form_state, $form) || !_relation_migrate_validate_type_source($form_state['input']['relation_migrate_' . $element['#array_parents'][0] . '_fields'], $relation_type)) {
+        form_error($element, t('Relation type %relation_type cannot be used with one of the selected %field_type fields. <a href="@rel_type_url">Check allowed source/target bundles for the relation type</a>.', array('%relation_type' => $relation_type->label, '%field_type' => $field_type['label'], '@rel_type_url' => url('admin/structure/relation/manage/' . $relation_type->relation_type . '/edit'))));
+      }
+    }
+  }
+}
+
+/**
+ * Checks if selected relation type supports all possible source bundles of a
+ * given field.
+ */
+function _relation_migrate_validate_type_source($fields, $relation_type) {
+  $allowed_bundles = $relation_type->source_bundles;
+  $fields = array_filter($fields);
+
+  foreach ($fields as $field_name) {
+    $field = field_info_field($field_name);
+    foreach ($field['bundles'] as $entity_type => $bundles) {
+      if (!in_array($entity_type . ':*', $allowed_bundles)) {
+        foreach ($bundles as $bundle) {
+          if (!in_array($entity_type . ':' . $bundle, $allowed_bundles)) {
+            return FALSE;
+          }
+        }
+      }
+    }
+  }
+
+  return TRUE;
+}
+
+
+/**
+ * Implements hook_migrate_api().
+ */
+function relation_migrate_migrate_api() {
+  $api = array(
+    'api' => 2,
+    'migrations' => array(
+      'RelationMigrateEntityReference' => array('class_name' => 'RelationMigrateEntityReference'),
+      'RelationMigrateNodeReference' => array('class_name' => 'RelationMigrateNodeReference'),
+      'RelationMigrateUserReference' => array('class_name' => 'RelationMigrateUserReference'),
+      'RelationMigrateTermReference' => array('class_name' => 'RelationMigrateTermReference'),
+    )
+  );
+  return $api;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/relation_migrate.modules.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @files
+ * Hook implementations in behalf of core and supported contrib modules.
+ */
+
+/**
+ * Implements hook_relation_migrate_type_target_validate().
+ */
+function taxonomy_relation_migrate_type_target_validate($element, $form_state, $form) {
+  $fields = array_filter($form_state['input']['relation_migrate_taxonomy_term_reference_fields']);
+  $relation_type = relation_type_load($form_state['input']['relation_migrate_taxonomy_term_reference_relation_type']);
+  $supported_bundles = $relation_type->directional ? $relation_type->target_bundles : $relation_type->source_bundles;
+
+  $return = TRUE;
+  foreach ($fields as $field) {
+    $field_def = field_info_field($field);
+    $return &= in_array('taxonomy_term:' . $field_def['settings']['allowed_values'][0]['vocabulary'], $supported_bundles);
+  }
+
+  return in_array('taxonomy_term:*', $supported_bundles) || $return;
+}
+
+/**
+ * Implements hook_relation_migrate_type_target_validate().
+ */
+function user_reference_relation_migrate_type_target_validate($element, $form_state, $form) {
+  $fields = array_filter($form_state['input']['relation_migrate_user_reference_fields']);
+  if (empty($fields)) {
+    return TRUE;
+  }
+
+  $relation_type = relation_type_load($form_state['input']['relation_migrate_user_reference_relation_type']);
+  $supported_bundles = $relation_type->directional ? $relation_type->target_bundles : $relation_type->source_bundles;
+  foreach ($supported_bundles as $bundle) {
+    if (strpos($bundle, 'user:') !== FALSE) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+ * Implements hook_relation_migrate_type_target_validate().
+ */
+function node_reference_relation_migrate_type_target_validate($element, $form_state, $form) {
+  $fields = array_filter($form_state['input']['relation_migrate_node_reference_fields']);
+  $relation_type = relation_type_load($form_state['input']['relation_migrate_node_reference_relation_type']);
+  $supported_bundles = $relation_type->directional ? $relation_type->target_bundles : $relation_type->source_bundles;
+
+  $return = TRUE;
+  foreach ($fields as $field) {
+    $field_def = field_info_field($field);
+    $node_types = array_filter($field_def['settings']['referenceable_types']);
+    foreach ($node_types as $node_type) {
+      $return &= in_array('node:' . $node_type, $supported_bundles);
+    }
+  }
+
+  return in_array('node:*', $supported_bundles) || $return;
+}
+
+/**
+ * Implements hook_relation_migrate_type_target_validate().
+ */
+function entityreference_relation_migrate_type_target_validate($element, $form_state, $form) {
+  $fields = array_filter($form_state['input']['relation_migrate_entityreference_fields']);
+  $relation_type = relation_type_load($form_state['input']['relation_migrate_entityreference_relation_type']);
+  $supported_bundles = $relation_type->directional ? $relation_type->target_bundles : $relation_type->source_bundles;
+
+  $return = TRUE;
+  foreach ($fields as $field) {
+    $field_def = field_info_field($field);
+    $entity_type = $field_def['settings']['target_type'];
+    $bundles = array_filter($field_def['settings']['handler_settings']['target_bundles']);
+    $bundles_allowed = TRUE;
+    foreach ($bundles as $bundle) {
+      $bundles_allowed &= in_array($entity_type . ':' . $bundle, $supported_bundles);
+    }
+    $return &= in_array($entity_type . ':*', $supported_bundles) || $bundles_allowed;
+  }
+
+  return $return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/relation_migrate.source.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,243 @@
+<?php
+
+/**
+ * @file
+ * Source plugin for *reference fields.
+ */
+
+/**
+ * Migration source for *ference field. This source is primary used in
+ * relation_migrate to convert *reference entries into relation entities.
+ */
+abstract class MigrateSourceReference extends MigrateSource {
+
+  /**
+   * Place where data is stored during import.
+   */
+  protected $result = array();
+
+  /**
+   * ID of a row, that will be imported during next iteration.
+   */
+  protected $next_row = 0;
+
+  /**
+   * Machine names of fields that will be imported.
+   */
+  protected $fields = array();
+
+  /**
+   * Field type.
+   */
+  protected $field_type;
+
+  /**
+   * Constructor.
+   *
+   * @param string $field Field type machine name.
+   * @param array $fields List of fields to be migrated.
+   */
+  public function __construct($field_type, array $fields, array $options = array()) {
+    parent::__construct($options);
+    $this->fields = $fields;
+    $this->field_type = $field_type;
+  }
+
+  /**
+   * Return a string representing the source, for display in the UI.
+   */
+  public function __toString() {
+    return t('Migrate %type fields: %fields', array('%type' => $this->field_type, '%fields' => implode(',', $this->fields)));
+  }
+
+  /**
+   * Returns a list of fields available to be mapped from the source,
+   * keyed by field name.
+   */
+  public function fields() {
+    return array(
+      'source_type' => t('Source entity type'),
+      'source_id' => t('Source entity ID'),
+      'destination_type' => t('Destination entity type'),
+      'destination_id' => t('Destination entity ID'),
+      'field_name' => t('Field name'),
+    );
+  }
+
+  /**
+   * Return the number of available source records.
+   */
+  public function computeCount() {
+    $rows_count = 0;
+    foreach ($this->fields as $field_name) {
+      $rows_count += db_query('SELECT count(*) FROM {field_data_' . $field_name . '} WHERE deleted = 0')->fetchField();
+    }
+    return $rows_count;
+  }
+
+  /**
+   * Do whatever needs to be done to start a fresh traversal of the source data.
+   */
+  public function performRewind() {
+    $this->result = array();
+    $this->next_row = 0;
+
+    // Load data for each field and merge all records in result array.
+    foreach ($this->fields as $field_name) {
+      $field_info = field_read_field($field_name);
+      $columns = array_keys($field_info['columns']);
+
+      if (!empty($field_info) && $field_info['type'] == $this->field_type) {
+        $field_data = db_select('field_data_' . $field_name, 'f')
+          ->fields('f', array('entity_type', 'entity_id', 'delta', $field_name . '_' . $columns[0]))
+          ->condition('deleted', 0);
+        $field_data->addExpression(":name", 'field_name', array(':name' => $field_name));
+        $field_data = $field_data->execute()->fetchAll();
+
+        $this->result = array_merge($this->result, $field_data);
+      }
+    }
+
+  }
+
+  /**
+   * Constructs row object, that should be returned from $this->getNextRow().
+   *
+   * @param stdClass $item Row item as returned from DB.
+   * @param string $destination_type Destiantion entity type.
+   * @param string $field_name Field's machine name.
+   */
+  protected function _constructRow(stdClass $item, $destination_type, $field_name) {
+      $field_info = field_read_field($field_name);
+      $columns = array_keys($field_info['columns']);
+      $id_key = $field_name . '_' . $columns[0];
+
+      $ret = array(
+        'source_type' => $item->entity_type,
+        'source_id' => $item->entity_id,
+        'destination_type' => $destination_type,
+        'destination_id' => $item->{$id_key},
+        'field_name' => $field_name,
+        'delta' => $item->delta,
+      );
+
+      return (object)$ret;
+  }
+}
+
+/**
+ * Source migration plugin for entityreference.
+ */
+class MigrateSourceEntityReference extends MigrateSourceReference {
+  /**
+   * Constructor.
+   *
+   * @param array $fields List of fields to be migrated.
+   */
+  function __construct(array $fields, array $options = array()) {
+    parent::__construct('entityreference', $fields, $options);
+  }
+
+  /**
+   * Fetch the next row of data, returning it as an object. Return FALSE
+   * when there is no more data available.
+   */
+  public function getNextRow() {
+    if (!empty($this->result[$this->next_row])) {
+      $item = $this->result[$this->next_row];
+      $dest_type = field_read_field($item->field_name);
+      $this->next_row++;
+
+      return $this->_constructRow($item, $dest_type['settings']['target_type'], $item->field_name);
+    }
+
+    return FALSE;
+  }
+}
+
+/**
+ * Source migration plugin for node_reference.
+ */
+class MigrateSourceNodeReference extends MigrateSourceReference {
+  /**
+   * Constructor.
+   *
+   * @param array $fields List of fields to be migrated.
+   */
+  function __construct(array $fields, array $options = array()) {
+    parent::__construct('node_reference', $fields, $options);
+  }
+
+  /**
+   * Fetch the next row of data, returning it as an object. Return FALSE
+   * when there is no more data available.
+   */
+  public function getNextRow() {
+    if (!empty($this->result[$this->next_row])) {
+      $item = $this->result[$this->next_row];
+      $this->next_row++;
+
+      return $this->_constructRow($item, 'node', $item->field_name);
+    }
+
+    return FALSE;
+  }
+}
+
+/**
+ * Source migration plugin for user_reference.
+ */
+class MigrateSourceUserReference extends MigrateSourceReference {
+  /**
+   * Constructor.
+   *
+   * @param array $fields List of fields to be migrated.
+   */
+  function __construct(array $fields, array $options = array()) {
+    parent::__construct('user_reference', $fields, $options);
+  }
+
+  /**
+   * Fetch the next row of data, returning it as an object. Return FALSE
+   * when there is no more data available.
+   */
+  public function getNextRow() {
+    if (!empty($this->result[$this->next_row])) {
+      $item = $this->result[$this->next_row];
+      $this->next_row++;
+
+      return $this->_constructRow($item, 'user', $item->field_name);
+    }
+
+    return FALSE;
+  }
+}
+
+/**
+ * Source migration plugin for taxonomy_term_reference.
+ */
+class MigrateSourceTermReference extends MigrateSourceReference {
+  /**
+   * Constructor.
+   *
+   * @param array $fields List of fields to be migrated.
+   */
+  function __construct(array $fields, array $options = array()) {
+    parent::__construct('taxonomy_term_reference', $fields, $options);
+  }
+
+  /**
+   * Fetch the next row of data, returning it as an object. Return FALSE
+   * when there is no more data available.
+   */
+  public function getNextRow() {
+    if (!empty($this->result[$this->next_row])) {
+      $item = $this->result[$this->next_row];
+      $this->next_row++;
+
+      return $this->_constructRow($item, 'taxonomy_term', $item->field_name);
+    }
+
+    return FALSE;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/tests/relation.migrate.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,290 @@
+<?php
+
+/**
+ * @file
+ * Test case that tests relation_migrate.module.
+ */
+
+/**
+ * Functional tests of Relation's integration with Migrate.
+ */
+class RelationMigrateTestCase extends RelationTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Relation Migrate test',
+      'description' => 'Tests the Relation Migrate support.',
+      'group' => 'Relation',
+    );
+  }
+
+  function setUp() {
+    // Entity reference complains if views not enabled.
+    parent::setUp('relation');
+    module_enable(array('migrate_ui', 'relation_migrate_test', 'relation_migrate'), TRUE);
+    $this->resetAll();
+
+    if (!module_exists('migrate') || !module_exists('migrate_ui') || !module_exists('node_reference') || !module_exists('user_reference') || !module_exists('entityreference')) {
+      return;
+    }
+
+    $permissions = array(
+      'create article content',
+      'create page content',
+      'administer relation types',
+      'administer relations',
+      'access relations',
+      'create relations',
+      'edit relations',
+      'delete relations',
+      'administer content types',
+      'migration information',
+    );
+    $this->web_user = $this->drupalCreateUser($permissions);
+
+    $this->createNodes();
+    $this->anonymous_user = $this->drupalCreateUser(array('access content'));
+  }
+
+  private function createNodes() {
+    $this->node1 = $this->drupalCreateNode(array('type' => 'article'));
+    $this->node2 = $this->drupalCreateNode(array('type' => 'article'));
+    $this->node3 = $this->drupalCreateNode(array('type' => 'article'));
+    $this->node4 = $this->drupalCreateNode(array('type' => 'article'));
+    $this->node5 = $this->drupalCreateNode(array('type' => 'article'));
+    $this->tag = (object) array(
+      'name' => $this->randomName(8),
+      'vid' => 1,
+    );
+    taxonomy_term_save($this->tag);
+
+    // Node reference.
+    $this->node1->field_node[LANGUAGE_NONE][0]['nid'] = $this->node2->nid;
+    $this->node2->field_node[LANGUAGE_NONE][0]['nid'] = $this->node3->nid;
+    $this->node3->field_node[LANGUAGE_NONE][0]['nid'] = $this->node4->nid;
+    $this->node4->field_node[LANGUAGE_NONE][0]['nid'] = $this->node5->nid;
+    $this->node5->field_node[LANGUAGE_NONE][0]['nid'] = $this->node1->nid;
+
+    //User reference
+    $this->node1->field_user[LANGUAGE_NONE][0]['uid'] = $this->user1->uid;
+    $this->node2->field_user[LANGUAGE_NONE][0]['uid'] = $this->user1->uid;
+    $this->node3->field_user[LANGUAGE_NONE][0]['uid'] = $this->user1->uid;
+    $this->node4->field_user[LANGUAGE_NONE][0]['uid'] = $this->user1->uid;
+    $this->node5->field_user[LANGUAGE_NONE][0]['uid'] = $this->user1->uid;
+
+    // Entity reference
+    $this->node1->field_entity[LANGUAGE_NONE][0]['target_id'] = $this->node5->nid;
+    $this->node2->field_entity[LANGUAGE_NONE][0]['target_id'] = $this->node4->nid;
+    $this->node3->field_entity[LANGUAGE_NONE][0]['target_id'] = $this->node3->nid;
+    $this->node4->field_entity[LANGUAGE_NONE][0]['target_id'] = $this->node2->nid;
+    $this->node5->field_entity[LANGUAGE_NONE][0]['target_id'] = $this->node1->nid;
+
+    // Term reference
+    $this->node1->field_tags[LANGUAGE_NONE][0]['tid'] = $this->tag->tid;
+    $this->node2->field_tags[LANGUAGE_NONE][0]['tid'] = $this->tag->tid;
+    $this->node3->field_tags[LANGUAGE_NONE][0]['tid'] = $this->tag->tid;
+    $this->node4->field_tags[LANGUAGE_NONE][0]['tid'] = $this->tag->tid;
+    $this->node5->field_tags[LANGUAGE_NONE][0]['tid'] = $this->tag->tid;
+
+    // Save nodes again
+    node_save($this->node1); node_save($this->node2); node_save($this->node3);
+    node_save($this->node4); node_save($this->node5);
+  }
+
+  function testRelationMigrate() {
+    if (!module_exists('migrate') || !module_exists('migrate_ui') || !module_exists('node_reference') || !module_exists('user_reference') || !module_exists('entityreference')) {
+      return;
+    }
+
+    /*
+     * Test configuration form:
+     *   - not accessible to user with unproper permission
+     *   - saves when settings are OK
+     *   - refuses to save when using a relation type with insufficent source/target configuration
+     */
+    $this->drupalLogout();
+    $this->drupalGet('admin/structure/relation/migrate');
+    $this->assertResponse(403, t('Anonymous user is not allowed to access Relation migrate configuration page.'));
+
+    $this->drupalLogin($this->web_user);
+    $this->drupalGet('admin/structure/relation/migrate');
+    $this->assertResponse(200, t('User with right permission has access to Relation migrate configuration page.'));
+    $this->assertText('field_tags', t('Taxonomy term reference field is present on config form.'));
+    $this->assertText('field_user', t('User reference field is present on config form.'));
+    $this->assertText('field_node', t('Node reference field is present on config form.'));
+    $this->assertText('field_entity', t('Entity reference field is present on config form.'));
+
+    $this->drupalPost("admin/structure/relation/migrate", array(
+      'relation_migrate_entityreference_relation_type' => 'symmetric',
+      'relation_migrate_node_reference_relation_type' => 'symmetric',
+      'relation_migrate_user_reference_relation_type' => 'symmetric',
+      'relation_migrate_taxonomy_term_reference_relation_type' => 'symmetric',
+      'relation_migrate_entityreference_fields[field_entity]' => TRUE,
+      'relation_migrate_node_reference_fields[field_node]' => TRUE,
+      'relation_migrate_user_reference_fields[field_user]' => TRUE,
+      'relation_migrate_taxonomy_term_reference_fields[field_tags]' => TRUE,
+    ), t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'), t('Settings saved successfully.'));
+
+    $this->drupalPost("admin/structure/relation/manage/symmetric/edit", array('source_bundles[]' => array('node:*', 'taxonomy_term:*')), t('Save'));
+    $this->drupalPost("admin/structure/relation/migrate", array(), t('Save configuration'));
+    $this->assertNoText(t('The configuration options have been saved.'), t('Settings not saved due to unproper configuration.'));
+
+    $this->drupalPost("admin/structure/relation/manage/symmetric/edit", array('source_bundles[]' => array('node:*', 'user:*')), t('Save'));
+    $this->drupalPost("admin/structure/relation/migrate", array(), t('Save configuration'));
+    $this->assertNoText(t('The configuration options have been saved.'), t('Settings not saved due to unproper configuration.'));
+
+    $this->drupalPost("admin/structure/relation/manage/symmetric/edit", array('source_bundles[]' => array('taxonomy_term:*', 'user:*')), t('Save'));
+    $this->drupalPost("admin/structure/relation/migrate", array(), t('Save configuration'));
+    $this->assertNoText(t('The configuration options have been saved.'), t('Settings not saved due to unproper configuration.'));
+
+    $this->drupalPost(
+      "admin/structure/relation/manage/symmetric/edit",
+      array(
+        'directional' => TRUE,
+        'source_bundles[]' => array('user:*'),
+        'target_bundles[]' => array('node:*', 'taxonomy_term:*', 'user:*')
+      ),
+      t('Save')
+    );
+    $this->drupalPost("admin/structure/relation/migrate", array(), t('Save configuration'));
+    $this->assertNoText(t('The configuration options have been saved.'), t('Settings not saved due to unproper configuration.'));
+
+    $this->drupalPost(
+      "admin/structure/relation/manage/symmetric/edit",
+      array(
+        'directional' => TRUE,
+        'source_bundles[]' => array('node:*'),
+        'target_bundles[]' => array('node:page', 'taxonomy_term:*', 'user:*')
+      ),
+      t('Save')
+    );
+    $this->drupalPost("admin/structure/relation/migrate", array(), t('Save configuration'));
+    $this->assertNoText(t('The configuration options have been saved.'), t('Settings not saved due to unproper configuration.'));
+
+    $this->drupalPost(
+      "admin/structure/relation/manage/symmetric/edit",
+      array(
+        'directional' => TRUE,
+        'source_bundles[]' => array('node:*'),
+        'target_bundles[]' => array('node:*', 'user:*')
+      ),
+      t('Save')
+    );
+    $this->drupalPost("admin/structure/relation/migrate", array(), t('Save configuration'));
+    $this->assertNoText(t('The configuration options have been saved.'), t('Settings not saved due to unproper configuration.'));
+
+    $this->drupalPost(
+      "admin/structure/relation/manage/symmetric/edit",
+      array(
+        'directional' => TRUE,
+        'source_bundles[]' => array('node:*'),
+        'target_bundles[]' => array('node:*', 'user:*', 'taxonomy_term:*')
+      ),
+      t('Save')
+    );
+    $this->drupalPost("admin/structure/relation/migrate", array(), t('Save configuration'));
+    $this->assertText(t('The configuration options have been saved.'), t('Settings saved successfully.'));
+
+    $this->drupalPost(
+      "admin/structure/relation/migrate",
+      array(
+        'relation_migrate_entityreference_fields[field_entity]' => FALSE,
+        'relation_migrate_node_reference_fields[field_node]' => FALSE,
+        'relation_migrate_user_reference_fields[field_user]' => FALSE,
+        'relation_migrate_taxonomy_term_reference_fields[field_tags]' => FALSE,
+      ),
+      t('Save configuration')
+    );
+    $this->assertText(t('The configuration options have been saved.'), t('Settings saved successfully.'));
+
+    /*
+     * Test migration classes for *reference fields.
+     *   - check for presence of *reference migration classes
+     *   - check for correct count of relations to be migrated
+     *   - run migration
+     *   - check for correct count of relations that were migrated
+     *   - check integrity of migrated relations
+     */
+    $this->drupalGet('admin/content/migrate');
+    $this->assertText('RelationMigrateEntityReference', t('Entity reference migrate class is present.'));
+    $this->assertText('RelationMigrateUserReference', t('User reference migrate class is present.'));
+    $this->assertText('RelationMigrateNodeReference', t('Node reference migrate class is present.'));
+    $this->assertText('RelationMigrateTermReference', t('Term reference migrate class is present.'));
+    $this->assertRaw('RelationMigrateEntityReference</a></td><td>0</td>', t('There are 0 rows to be migrated from Entity reference.'));
+    $this->assertRaw('RelationMigrateUserReference</a></td><td>0</td>', t('There are 0 rows to be migrated from User reference.'));
+    $this->assertRaw('RelationMigrateNodeReference</a></td><td>0</td>', t('There are 0 rows to be migrated from Node reference.'));
+    $this->assertRaw('RelationMigrateTermReference</a></td><td>0</td>', t('There are 0 rows to be migrated from Term reference.'));
+
+    $this->drupalPost(
+      "admin/structure/relation/migrate",
+      array(
+        'relation_migrate_entityreference_fields[field_entity]' => TRUE,
+        'relation_migrate_node_reference_fields[field_node]' => TRUE,
+        'relation_migrate_user_reference_fields[field_user]' => TRUE,
+        'relation_migrate_taxonomy_term_reference_fields[field_tags]' => TRUE,
+      ),
+      t('Save configuration')
+    );
+    $this->drupalGet('admin/content/migrate');
+    $this->assertRaw('RelationMigrateEntityReference</a></td><td>5</td><td>0</td><td>5</td>', t('There are 5 rows to be migrated from Entity reference.'));
+    $this->assertRaw('RelationMigrateUserReference</a></td><td>5</td><td>0</td><td>5</td>', t('There are 5 rows to be migrated from User reference.'));
+    $this->assertRaw('RelationMigrateNodeReference</a></td><td>5</td><td>0</td><td>5</td>', t('There are 5 rows to be migrated from Node reference.'));
+    $this->assertRaw('RelationMigrateTermReference</a></td><td>5</td><td>0</td><td>5</td>', t('There are 5 rows to be migrated from Term reference.'));
+
+    $this->drupalPost(
+      "admin/content/migrate",
+      array(
+        'dashboard[RelationMigrateEntityReference]' => TRUE,
+        'dashboard[RelationMigrateUserReference]' => TRUE,
+        'dashboard[RelationMigrateTermReference]' => TRUE,
+        'dashboard[RelationMigrateNodeReference]' => TRUE,
+      ),
+      t('Execute')
+    );
+    $this->drupalGet('admin/content/migrate');
+    $this->assertRaw('RelationMigrateEntityReference</a></td><td>5</td><td>5</td><td>0</td>', t('5 rows were successfully migrated from Entity reference.'));
+    $this->assertRaw('RelationMigrateUserReference</a></td><td>5</td><td>5</td><td>0</td>', t('5 rows were successfully migrated from User reference.'));
+    $this->assertRaw('RelationMigrateNodeReference</a></td><td>5</td><td>5</td><td>0</td>', t('5 rows were successfully migrated from Node reference.'));
+    $this->assertRaw('RelationMigrateTermReference</a></td><td>5</td><td>5</td><td>0</td>', t('5 rows were successfully migrated from Term reference.'));
+
+    $this->drupalGet('admin/content/relation');
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node1->nid) . '">' . $this->node1->title . '</a> → <a href="' . url('node/' . $this->node2->nid) . '">' . $this->node2->title . '</a></td>', t('Node reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node2->nid) . '">' . $this->node2->title . '</a> → <a href="' . url('node/' . $this->node3->nid) . '">' . $this->node3->title . '</a></td>', t('Node reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node3->nid) . '">' . $this->node3->title . '</a> → <a href="' . url('node/' . $this->node4->nid) . '">' . $this->node4->title . '</a></td>', t('Node reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node4->nid) . '">' . $this->node4->title . '</a> → <a href="' . url('node/' . $this->node5->nid) . '">' . $this->node5->title . '</a></td>', t('Node reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node5->nid) . '">' . $this->node5->title . '</a> → <a href="' . url('node/' . $this->node1->nid) . '">' . $this->node1->title . '</a></td>', t('Node reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node1->nid) . '">' . $this->node1->title . '</a> → <a href="' . url('user/' . $this->user1->uid) . '">' . $this->user1->name . '</a></td>', t('User reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node2->nid) . '">' . $this->node2->title . '</a> → <a href="' . url('user/' . $this->user1->uid) . '">' . $this->user1->name . '</a></td>', t('User reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node3->nid) . '">' . $this->node3->title . '</a> → <a href="' . url('user/' . $this->user1->uid) . '">' . $this->user1->name . '</a></td>', t('User reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node4->nid) . '">' . $this->node4->title . '</a> → <a href="' . url('user/' . $this->user1->uid) . '">' . $this->user1->name . '</a></td>', t('User reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node5->nid) . '">' . $this->node5->title . '</a> → <a href="' . url('user/' . $this->user1->uid) . '">' . $this->user1->name . '</a></td>', t('User reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node1->nid) . '">' . $this->node1->title . '</a> → <a href="' . url('taxonomy/term/' . $this->tag->tid) . '">' . $this->tag->name . '</a></td>', t('Term reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node2->nid) . '">' . $this->node2->title . '</a> → <a href="' . url('taxonomy/term/' . $this->tag->tid) . '">' . $this->tag->name . '</a></td>', t('Term reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node3->nid) . '">' . $this->node3->title . '</a> → <a href="' . url('taxonomy/term/' . $this->tag->tid) . '">' . $this->tag->name . '</a></td>', t('Term reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node4->nid) . '">' . $this->node4->title . '</a> → <a href="' . url('taxonomy/term/' . $this->tag->tid) . '">' . $this->tag->name . '</a></td>', t('Term reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node5->nid) . '">' . $this->node5->title . '</a> → <a href="' . url('taxonomy/term/' . $this->tag->tid) . '">' . $this->tag->name . '</a></td>', t('Term reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node1->nid) . '">' . $this->node1->title . '</a> → <a href="' . url('node/' . $this->node5->nid) . '">' . $this->node5->title . '</a></td>', t('Entity reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node2->nid) . '">' . $this->node2->title . '</a> → <a href="' . url('node/' . $this->node4->nid) . '">' . $this->node4->title . '</a></td>', t('Entity reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node3->nid) . '">' . $this->node3->title . '</a> → <a href="' . url('node/' . $this->node3->nid) . '">' . $this->node3->title . '</a></td>', t('Entity reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node4->nid) . '">' . $this->node4->title . '</a> → <a href="' . url('node/' . $this->node2->nid) . '">' . $this->node2->title . '</a></td>', t('Entity reference migrated successfully.'));
+    $this->assertRaw('<td><a href="' . url('node/' . $this->node5->nid) . '">' . $this->node5->title . '</a> → <a href="' . url('node/' . $this->node1->nid) . '">' . $this->node1->title . '</a></td>', t('Entity reference migrated successfully.'));
+
+    // Test if duplicated relations get migrated properly - add one first
+    $this->node1->field_tags[LANGUAGE_NONE][1]['tid'] = $this->tag->tid;
+    node_save($this->node1);
+
+    // Check if new reference appeared and migrate it to relation.
+    $this->drupalGet('admin/content/migrate');
+    $this->assertRaw('RelationMigrateTermReference</a></td><td>6</td><td>5</td><td>1</td>', t('There is 1 new row to be migrated from Term reference.'));
+
+    $this->drupalPost(
+      "admin/content/migrate",
+      array(
+        'dashboard[RelationMigrateTermReference]' => TRUE,
+      ),
+      t('Execute')
+    );
+    $this->drupalGet('admin/content/migrate');
+    $this->assertRaw('RelationMigrateTermReference</a></td><td>6</td><td>6</td><td>0</td>', t('6 rows were successfully migrated from Term reference.'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/tests/relation_migrate_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+name = "Relation Migrate Tests"
+description = "Support module for the Relation - Migrate integration tests."
+package = Testing
+core = 7.x
+hidden = TRUE
+
+dependencies[] = node_reference
+dependencies[] = user_reference
+dependencies[] = entityreference
+dependencies[] = views
+
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-1.0-rc4"
+core = "7.x"
+project = "relation"
+datestamp = "1360240967"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_migrate/tests/relation_migrate_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * Implements hook_install().
+ */
+function relation_migrate_test_install() {
+    field_info_cache_clear();
+    // Node reference field
+    $field = array(
+      'field_name' => 'field_node',
+      'type' => 'node_reference',
+      'cardinality' => 1,
+      'settings' => array(
+        'referenceable_types' => array('article' => 'article', 'page' => 0),
+      ),
+    );
+    field_create_field($field);
+
+    $instance = array(
+      'field_name' => 'field_node',
+      'entity_type' => 'node',
+      'label' => 'Node reference',
+      'bundle' => 'article',
+    );
+    field_create_instance($instance);
+
+    // User reference field
+    $field = array(
+      'field_name' => 'field_user',
+      'type' => 'user_reference',
+      'cardinality' => 1,
+    );
+    field_create_field($field);
+
+    $instance = array(
+      'field_name' => 'field_user',
+      'entity_type' => 'node',
+      'label' => 'User reference',
+      'bundle' => 'article',
+    );
+    field_create_instance($instance);
+
+    // Entity reference field
+    $field = array(
+      'field_name' => 'field_entity',
+      'type' => 'entityreference',
+      'cardinality' => 1,
+      'settings' => array(
+        'target_type' => 'node',
+        'handler' => 'base',
+        'handler_settings' => array(
+          'target_bundles' => array('article' => 'article'),
+        ),
+      ),
+    );
+    field_create_field($field);
+
+    $instance = array(
+      'field_name' => 'field_entity',
+      'entity_type' => 'node',
+      'label' => 'Entity reference',
+      'bundle' => 'article',
+    );
+    field_create_instance($instance);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_ui.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,17 @@
+/**
+ * @file relation types form css
+ */
+
+.relation-type-form-table {
+  display: table;
+}
+
+.relation-type-form-table .form-item{
+  display: table-cell;
+  padding-right:10px;
+  width: 33%;
+}
+
+.relation-type-form-table .form-item:last-child {
+  padding-right: 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_ui.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,15 @@
+name = Relation UI
+description = Administrative interface to relation. Without this module, you cannot create or edit your relation types.
+package = Relation
+core = 7.x
+configure = admin/structure/relation
+dependencies[] = relation
+files[] = relation_ui.module
+files[] = tests/relation_ui.test
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-1.0-rc4"
+core = "7.x"
+project = "relation"
+datestamp = "1360240967"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/relation_ui.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,726 @@
+<?php
+
+/**
+ * @file
+ * Provide administration interface for relation type bundles.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function relation_ui_menu() {
+  $items['relation/%relation'] = array(
+    'title callback' => 'relation_page_title',
+    'title arguments' => array(1),
+    'access arguments' => array('access relations'),
+    'page callback' => 'relation_page',
+    'page arguments' => array(1),
+  );
+  $items['relation/%relation/view'] = array(
+    'title' => 'View',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['relation/%relation/edit'] = array(
+    'title' => 'Edit',
+    'access arguments' => array('edit relations'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('relation_edit_form', 1),
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['relation/%relation/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('relation_delete_confirm', 1),
+    'access arguments' => array('delete relations'),
+    'weight' => 10,
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['admin/structure/relation'] = array(
+    'title' => 'Relation types',
+    'access arguments' => array('administer relation types'),
+    'page callback' => 'relation_ui_type_list',
+    'description' => 'Manage relation types, including relation properties (directionality, transitivity etc), available bundles, and fields.',
+  );
+  $items['admin/structure/relation/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/structure/relation/add'] = array(
+    'title' => 'Add relation type',
+    'access arguments' => array('administer relation types'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('relation_ui_type_form'),
+    'type' => MENU_LOCAL_ACTION,
+    'description' => 'Add new relation types.',
+  );
+  $items['admin/structure/relation/import'] = array(
+    'title' => 'Import  relation type',
+    'access arguments' => array('administer relation types'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('relation_ui_type_import'),
+    'type' => MENU_LOCAL_ACTION,
+    'description' => 'Import existing relation types.',
+  );
+  $items['admin/structure/relation/manage/%relation_type'] = array(
+    'title' => 'Edit relation type',
+    'title callback' => 'relation_type_page_title',
+    'title arguments' => array(4),
+    'access arguments' => array('administer relation types'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('relation_ui_type_form', 4),
+    'description' => 'Edit an existing relation type, including relation properties (directionality, transitivity etc), available bundles, and fields.',
+  );
+  $items['admin/structure/relation/manage/%relation_type/edit'] = array(
+    'title' => 'Edit',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['admin/structure/relation/manage/%relation_type/delete'] = array(
+    'title' => 'Delete',
+    'page arguments' => array('relation_ui_type_delete_confirm', 4),
+    'access arguments' => array('administer relation types'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 20,
+    'description' => 'Delete an existing relation type.',
+  );
+  if (module_exists('ctools')) {
+    $items['admin/structure/relation/manage/%relation_type/export'] = array(
+      'title' => 'Export',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => array('relation_export_relation_type', 4),
+      'access arguments' => array('export relation types'),
+      'type' => MENU_LOCAL_TASK,
+      'file' => 'relation.ctools.inc',
+      'weight' => 10,
+    );
+  }
+  $items['admin/config/development/generate/relation'] = array(
+    'title' => 'Generate relations',
+    'access arguments' => array('administer relation types'),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('relation_ui_generate_form'),
+    'description' => 'Generate relations for testing.',
+  );
+  // Relations listing.
+  $items['admin/content/relation'] = array(
+    'title' => 'Relations',
+    'file' => 'relation_ui.module',
+    'page callback' => 'relation_ui_admin_content',
+    'access arguments' => array('administer relations'),
+    'description' => 'View, edit and delete all the available relations on your site.',
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['relation/endpoints_type/autocomplete'] = array(
+    'type' => MENU_CALLBACK,
+    'access arguments' => array('administer relations'),
+    'file' => 'relation_ui.module',
+    'page callback' => 'relation_ui_endpoints_type_autocomplete',
+  );
+  return $items;
+}
+
+/**
+ * List all relation_types (page callback).
+ */
+function relation_ui_type_list() {
+  $relation = relation_entity_info();
+  $field_ui = module_exists('field_ui');
+  $ctools = module_exists('ctools');
+  $ops_count = 2 + 2 * $field_ui + $ctools;
+
+  $headers = array(
+    array('data' => t('Name'), 'width' => '40%'),
+    array('data' => t('Operations'), 'colspan' => $ops_count));
+  $rows = array();
+  foreach ($relation['relation']['bundles'] as $type => $relation_type) {
+    $url = 'admin/structure/relation/manage/' . $type;
+    $row = array(l($relation_type['label'], $url));
+    $row[] = l(t('edit'), $url . '/edit');
+    if ($field_ui) {
+      $row[] =  l(t('manage fields'), $url . '/fields');
+      $row[] =  l(t('display fields'), $url . '/display');
+    }
+    if ($ctools) {
+      $row[] =  l(t('export'), $url . '/export');
+    }
+    $row[] =  empty($relation_type->in_code_only) ? l(t('delete'), $url . '/delete') : '&nbsp;';
+    $rows[] = $row;
+  }
+  $output = array(
+    '#theme' => 'table',
+    '#header' => $headers,
+    '#rows' => $rows,
+    '#empty' => t('No relationship types available.', array('@link' => l(t('Add relationship type'), url('admin/structure/relation/add')))),
+  );
+  return $output;
+}
+
+/**
+ * Relation relation type bundle settings form.
+ *
+ * @param $relation_type
+ *   Relation type machine name. If this is not provided, assume that we're
+ *   creating a new relation type.
+ */
+function relation_ui_type_form($form, &$form_state, $relation_type = array(), $op = 'edit') {
+  $form['#write_record_keys'] = array();
+  $form['#attached']['css'] = array(
+    drupal_get_path('module', 'relation') . '/relation_ui.css',
+  );
+
+  if ($relation_type) {
+    $relation_type = (object) $relation_type;
+    if (empty($relation_type->in_code_only)) {
+      $form['#write_record_keys'][] = 'relation_type';
+    }
+  }
+  else {
+    $relation_type = (object) array(
+      'relation_type' => '',
+      'label' => '',
+      'reverse_label' => '',
+      'bundles' => array(),
+      'directional' => FALSE,
+      'transitive' => FALSE,
+      'r_unique' => FALSE,
+      'min_arity' => 2,
+      'max_arity' => 2,
+      'source_bundles' => array(),
+      'target_bundles' => array(),
+    );
+  }
+  $form['labels'] = array(
+    '#type' => 'container',
+    '#attributes' => array(
+      'class' => array('relation-type-form-table'),
+    ),
+    '#suffix' => '<div class="clearfix"></div>',
+  );
+  $form['labels']['name'] = array( // use 'name' for /misc/machine-name.js
+    '#type'          => 'textfield',
+    '#title'         => t('Label'),
+    '#description'   => t('Display name of the relation type. This is also used as the predicate in natural language formatters (ie. if A is related to B, you get "A [label] B")'),
+    '#default_value' => $relation_type->label,
+    '#size'          => 40,
+    '#required'      => TRUE,
+  );
+  $form['labels']['relation_type'] = array(
+    '#type'          => 'machine_name',
+    '#default_value' => $relation_type->relation_type,
+    '#maxlength' => 32,
+    '#disabled'      => $relation_type->relation_type,
+    '#machine_name' => array(
+      'source' => array('labels', 'name'),
+      'exists' => 'relation_type_load',
+    ),
+  );
+  $form['labels']['reverse_label'] = array(
+    '#type'          => 'textfield',
+    '#size'          => 40,
+    '#title'         => t('Reverse label'),
+    '#description'   => t('Reverse label of the relation type. This is used as the predicate by formatters of directional relations, when you need to display the reverse direction (ie. from the target entity to the source entity). If this is not supplied, the forward label is used.'),
+    '#default_value' => $relation_type->reverse_label,
+    '#states' => array(
+      'visible' => array(   // action to take.
+        ':input[name="directional"]' => array('checked' => TRUE),
+      ),
+    ),
+  );
+  $form['directional'] = array(
+    '#type'           => 'checkbox',
+    '#title'          => 'Directional',
+    '#description'   => t('A directional relation is one that does not imply the reverse relation. For example, a "likes" relation is directional (A likes B does not neccesarily mean B likes A), whereas a "similar to" relation is non-directional (A similar to B implies B similar to A. Non-directional relations are also known as symmetric relations.'),
+    '#default_value'  => $relation_type->directional,
+  );
+  // More advanced options, hide by default.
+  $form['advanced'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Advanced options'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#weight' => 50,
+    '#tree' => TRUE,
+  );
+  $form['advanced']['transitive'] = array(
+    '#type'           => 'checkbox',
+    '#title'          => t('Transitive'),
+    '#description'   => t('A transitive relation implies that the relation passes through intermediate entities (ie. A=>B and B=>C implies that A=>C). For example "Ancestor" is transitive: your ancestor\'s ancestor is also your ancestor. But a "Parent" relation is non-transitive: your parent\'s parent is not your parent, but your grand-parent.'),
+    '#default_value'  => $relation_type->transitive,
+  );
+  $form['advanced']['r_unique'] = array(
+    '#type'           => 'checkbox',
+    '#title'          => t('Unique'),
+    '#description'    => t('Whether relations of this type are unique (ie. they can not contain exactly the same end points as other relations of this type).'),
+    '#default_value'  => $relation_type->r_unique,
+  );
+  // these should probably be changed to numerical (validated) textfields.
+  $options = array('2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', '7' => '7', '8' => '8');
+  $form['advanced']['min_arity'] = array(
+    '#type' => 'select',
+    '#title' => t('Minimum Arity'),
+    '#options' => $options,
+    '#description' => t('Minimum number of entities joined by relations of this type (e.g. three siblings in one relation). <em>In nearly all cases you will want to leave this set to 2</em>.'),
+    '#default_value' => $relation_type->min_arity ? $relation_type->min_arity : 2,
+  );
+
+  $options = array('2' => '2', '3' => '3', '4' => '4', '5' => '5', '6' => '6', '7' => '7', '8' => '8', '0' => t('Infinite'));
+  $form['advanced']['max_arity'] = array(
+    '#type' => 'select',
+    '#title' => t('Maximum Arity'),
+    '#options' => $options,
+    '#description' => t('Maximum number of entities joined by relations of this type. <em>In nearly all cases you will want to leave this set to 2</em>.'),
+    '#default_value' => isset($relation_type->max_arity) ? $relation_type->max_arity : 2,
+  );
+  $counter = 0;
+  foreach (entity_get_info() as $entity_type => $entity) {
+    $bundles[$entity['label']]["$entity_type:*"] = 'all ' . $entity['label'] . ' bundles';
+    $counter += 2;
+    if (isset($entity['bundles'])) {
+      foreach ($entity['bundles'] as $bundle_id => $bundle) {
+        $bundles[$entity['label']]["$entity_type:$bundle_id"] = $bundle['label'];
+        $counter++;
+      }
+    }
+  }
+  $form['endpoints'] = array(
+    '#type' => 'container',
+    '#attributes' => array(
+      'class' => array('relation-type-form-table'),
+    ),
+    '#suffix' => '<div class="clearfix"></div>',
+  );
+  $form['endpoints']['source_bundles'] = array(
+    '#type'          => 'select',
+    '#title'         => t('Available source bundles'),
+    '#options'       => $bundles,
+    '#size'          => max(12, $counter),
+    '#default_value' => $relation_type->source_bundles,
+    '#multiple'      => TRUE,
+    '#description'   => 'Bundles that are not selected will not be available as sources for directional, or end points of non-directional relations relations. Ctrl+click to select multiple. Note that selecting all bundles also include bundles not yet created for that entity type.',
+  );
+  $form['endpoints']['target_bundles'] = array(
+    '#type'          => 'select',
+    '#title'         => t('Available target bundles'),
+    '#options'       => $bundles,
+    '#size'          => max(12, $counter),
+    '#default_value' => $relation_type->target_bundles,
+    '#multiple'      => TRUE,
+    '#description'   => 'Bundles that are not selected will not be available as targets for directional relations. Ctrl+click to select multiple.',
+    '#states' => array(
+      '!visible' => array(   // action to take.
+        ':input[name="directional"]' => array('checked' => FALSE),
+      ),
+    ),
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#weight' => 100,
+    '#value' => t('Save'),
+  );
+  return $form;
+}
+
+/**
+ * Submit data from bundle settings page.
+ */
+function relation_ui_type_form_submit($form, &$form_state) {
+  $relation_type = $form_state['values']['relation_type'];
+  $min_arity = $form_state['values']['advanced']['min_arity'];
+  $max_arity = $form_state['values']['advanced']['max_arity'];
+  $record = array(
+    'relation_type'   => $relation_type,
+    'min_arity'   => $min_arity,
+    'max_arity'   => $max_arity,
+    'label' => $form_state['values']['name'],
+    'reverse_label' => $form_state['values']['reverse_label'],
+    'directional' => $form_state['values']['directional'],
+    'transitive' => $form_state['values']['advanced']['transitive'],
+    'r_unique' => $form_state['values']['advanced']['r_unique'],
+    'source_bundles' => $form_state['values']['source_bundles'],
+    'target_bundles' => $form_state['values']['target_bundles'],
+  );
+  relation_type_save($record, $form['#write_record_keys']);
+  $form_state['redirect'] = "admin/structure/relation/edit/$relation_type";
+
+  drupal_set_message(t('The %relation_type relation type has been saved.', array('%relation_type' => $relation_type)));
+}
+
+/**
+ * Menu callback; deletes a single relation type.
+ */
+function relation_ui_type_delete_confirm($form, &$form_state, $relation_type) {
+  $form['relation_type'] = array('#type' => 'value', '#value' => $relation_type->relation_type);
+  $form['label'] = array('#type' => 'value', '#value' => $relation_type->label);
+
+  $message = t('Are you sure you want to delete the %label relation type?', array('%label' => $relation_type->label));
+  $caption = '';
+
+  $num_relations = relation_query()
+    ->propertyCondition('relation_type', $relation_type->relation_type)
+    ->count()
+    ->execute();
+  if ($num_relations) {
+    $caption .= '<p>' . format_plural($num_relations,
+      'The %label relation type is used by 1 relation on your site. If you remove this relation type, you will not be able to edit  %label relations and they may not display correctly.',
+      'The %label relation type is used by @count relations on your site. If you remove %label, you will not be able to edit %label relations and they may not display correctly.',
+      array('%label' => $relation_type->label, '@count' => $num_relations)) . '</p>';
+  }
+
+  $caption .= '<p>' . t('This action cannot be undone.') . '</p>';
+
+  return confirm_form($form, $message, 'admin/structure/relation', $caption, t('Delete'));
+}
+
+/**
+ * Process relation type delete confirm submissions.
+ */
+function relation_ui_type_delete_confirm_submit($form, &$form_state) {
+  relation_type_delete($form_state['values']['relation_type']);
+
+  $t_args = array('%label' => $form_state['values']['label']);
+  drupal_set_message(t('The %label relation type has been deleted.', $t_args));
+  watchdog('relation', 'Deleted the %label relation type.', $t_args, WATCHDOG_NOTICE);
+
+  // @TODO: relation_types_rebuild() ?;
+  menu_rebuild();
+
+  $form_state['redirect'] = 'admin/structure/relation';
+  return;
+}
+
+/**
+ * Generate relations
+ */
+function relation_ui_generate_form($form, &$form_state) {
+  $types = relation_get_types();
+
+  if (empty($types)) {
+    $form['explanation']['#markup'] = t("Before you can generate relations, you need to define one or more !link.", array("!link" => l(t('relation types'), 'admin/structure/relation')));
+    return $form;
+  }
+  foreach ($types as $id => $type) {
+    $types[$id] = $type->label;
+  }
+
+  $form['relation_types'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Relation types'),
+    '#description' => t('Select relation types to create relations from. If no types are selected, relations will be generated for all types.'),
+    '#options' => $types,
+  );
+  $form['relation_number'] = array(
+    '#type' => 'textfield',
+    '#title' => t('How many relations would you like to generate of each type?'),
+    '#default_value' => 10,
+    '#size' => 10,
+  );
+  $form['relation_kill'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Kill all existing relations first.'),
+  );
+
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Generate'),
+  );
+  return $form;
+}
+
+function relation_ui_generate_form_submit($form, &$form_state) {
+  $number = $form_state['values']['relation_number'];
+  $types = $form_state['values']['relation_types'];
+  $kill = $form_state['values']['relation_kill'];
+  if (is_numeric($number) && $number > 0) {
+    include_once drupal_get_path('module', 'relation') . '/relation.drush.inc';
+    $types = array_keys(array_filter($types));
+    $rids = relation_generate_relations($number, $types, $kill);
+  }
+}
+
+/**
+ * Filter form for relation administration list.
+ */
+function relation_ui_filter_form($form, $form_state) {
+  if (isset($_SESSION['relation_filters'])) {
+    foreach($_SESSION['relation_filters'] as $filter => $values) {
+      $$filter = $values;
+    }
+  }
+  $types = relation_get_types();
+  foreach ($types as $name => $relation) {
+    $bundles[$name] = $relation->label;
+  }
+  $form['filters'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Show only items where'),
+    '#theme' => 'exposed_filters__relation',
+  );
+  $form['filters']['bundle'] = array(
+    '#title' => t('relation type'),
+    '#type' => 'select',
+    '#default_value' => isset($bundle) ? array_keys($bundle) : NULL,
+    '#multiple' => TRUE,
+    '#options' => $bundles,
+    '#size' => (count($bundles) < 10) ? count($bundles) : 10,
+  );
+  $form['filters']['endpoints_entity_type'] = array(
+    '#title' => t('endpoint type'),
+    '#type' => 'textfield',
+    '#default_value' => isset($endpoints_entity_type) ? $endpoints_entity_type : NULL,
+    '#autocomplete_path' => 'relation/endpoints_type/autocomplete'
+  );
+  $form['filters']['endpoints_entity_id'] = array(
+    '#title' => t('endpoint ID'),
+    '#type' => 'textfield',
+    '#default_value' => isset($endpoints_entity_id) ? $endpoints_entity_id : NULL,
+  );
+  $form['filters']['actions'] = array(
+    '#type' => 'actions',
+    '#attributes' => array('class' => array('container-inline')),
+  );
+  $form['filters']['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Filter'),
+  );
+  $form['filters']['actions']['reset'] = array(
+    '#type' => 'submit',
+    '#value' => t('Reset'),
+  );
+  $form['#submit'] = array('relation_ui_filter_form_submit');
+  return $form;
+}
+
+/**
+ * Submit handler for filter form
+ */
+function relation_ui_filter_form_submit($form, $form_state) {
+  form_state_values_clean($form_state);
+  if ($form_state['triggering_element']['#value'] == t('Reset')) {
+    unset($_SESSION['relation_filters']);
+  }
+  else {
+    $_SESSION['relation_filters'] = $form_state['values'];
+  }
+}
+
+/**
+ * Apply filters for relation administration filters based on session.
+ *
+ * @param $query
+ *   A SelectQuery to which the filters should be applied.
+ */
+function relation_ui_build_filter_query(SelectQueryInterface $query) {
+  if (!empty($_SESSION['relation_filters'])) {
+    $query->join('field_data_endpoints', 'e', 'e.entity_id = r.rid');
+    $query->distinct();
+    foreach ($_SESSION['relation_filters'] as $filter => $values) {
+      if (empty($values)) {
+        continue;
+      }
+      switch ($filter) {
+        case 'bundle':
+          $query->condition('r.relation_type', array_keys($values), 'IN');
+          break;
+        case 'endpoints_entity_type':
+          $query->condition('e.endpoints_entity_type', $values);
+          break;
+        case 'endpoints_entity_id':
+          $query->condition('e.endpoints_entity_id', $values);
+          break;
+      }
+    }
+  }
+}
+
+/**
+ * Menu callback for admin/content/relation. Displays all relations on the site.
+ */
+function relation_ui_admin_content() {
+  // Set up header row.
+  $header = array(
+    'label' => array('data' => t('Title'), 'field' => 'r.rid', 'sort' => 'asc'),
+    'type' => array('data' => t('Type'), 'field' => 'r.relation_type'),
+    t('Relation'),
+    'operations' => array('data' => t('Operations'), 'colspan' => '2'),
+  );
+
+  // Grab all relations.
+  $query = db_select('relation', 'r')->extend('PagerDefault')->extend('TableSort');
+  $query->fields('r', array('rid', 'relation_type'));
+  relation_ui_build_filter_query($query);
+  $query->limit(50)
+  ->orderByHeader($header);
+  $relations = $query->execute();
+
+  $form = drupal_get_form('relation_ui_filter_form');
+  $filter_form = drupal_render($form);
+
+  return $filter_form . theme('relation_ui_admin_content', array('relations' => $relations, 'header' => $header));
+}
+
+/**
+ * Generate a table of all relations on this site.
+ */
+function theme_relation_ui_admin_content($variables) {
+  $relations = $variables['relations'];
+  $header = $variables['header'];
+  $types = relation_get_types();
+
+  $rows = array();
+  if (empty($relations)) {
+    // Give a message if there are no relations returned.
+    $message = t('There are currently no relations on your site.');
+
+    $rows[] = array(
+      array('data' => $message, 'colspan' => 5),
+    );
+  }
+  else {
+    foreach ($relations as $relation) {
+      // Load the relation.
+      $r = relation_load($relation->rid);
+      // Get the endpoints for this relation.
+      $endpoints = field_get_items('relation', $r, 'endpoints');
+
+      $relation_entities = array();
+      if (!empty($endpoints)) {
+        foreach ($endpoints as $endpoint) {
+          $entities = entity_load($endpoint['entity_type'], array($endpoint['entity_id']));
+          $entity = reset($entities);
+          $title = entity_label($endpoint['entity_type'], $entity);
+          $path = entity_uri($endpoint['entity_type'], $entity);
+
+          // Logic to process how the different entities return a uri.
+          // see this issue: http://drupal.org/node/1057242
+          if ($endpoint['entity_type'] == 'file') {
+            $path = array('path' => file_create_url($path));
+          }
+          if ($endpoint['entity_type'] == 'taxonomy_vocabulary') {
+            $path = array('path' => 'admin/structure/taxonomy/' . $entity->machine_name);
+          }
+          $relation_entities[] = array('title' => $title, 'path' => $path['path']);
+        }
+      }
+
+      // Build the column for the relation entities.
+      $relation_column = array();
+      foreach ($relation_entities as $entity) {
+        $relation_column[] = l($entity['title'], $entity['path']);
+      }
+
+      // Build the rows to pass to the table theme function.
+      // Directional is implemented, not sure how well it works.
+
+      $destination = drupal_get_destination();
+      $options = array(
+       'attributes' => array(),
+       'query' => array(
+          'destination' => $destination['destination'],
+        ),
+      );
+
+      $endpoint_separator = ', ';
+      $type_label = '';
+      // Get the type for this relation
+      if (isset($types[$r->relation_type])) {
+        $type = $types[$r->relation_type];
+        $endpoint_separator = $type->directional ? " → " : " ↔ ";
+        $type_label = $relation->relation_type;
+      }
+      $rows[] = array(
+        l(t('Relation') . ' ' . $relation->rid, 'relation/' . $relation->rid),
+        $type_label,
+        implode($endpoint_separator, $relation_column),
+        user_access('edit relations') ? l(t('Edit'), 'relation/' . $relation->rid . '/edit', $options) : '',
+        user_access('delete relations') ? l(t('Delete'), 'relation/' . $relation->rid . '/delete', $options) : '',
+      );
+    }
+  }
+
+  return theme('table', array('header' => $header, 'rows' => $rows)) . theme('pager');
+}
+
+/**
+ * Page callback to import a relation.
+ */
+function relation_ui_type_import($form) {
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Relation type name'),
+    '#description' => t('Enter the machine name to use for this relation type if it is different from the relation type to be imported. Leave blank to use the name of the relation type below.'),
+  );
+  $form['relation_type'] = array(
+    '#type' => 'textarea',
+    '#rows' => 10,
+  );
+  $form['import'] = array(
+    '#type' => 'submit',
+    '#value' => t('Import'),
+  );
+  return $form;
+}
+
+function relation_ui_type_import_validate($form, &$form_state) {
+  if (drupal_substr($form_state['values']['relation_type'], 0, 5) == '<?php') {
+    $form_state['values']['relation_type'] = drupal_substr($form_state['values']['relation_type'], 5);
+  }
+  ob_start();
+  eval($form_state['values']['relation_type']);
+  ob_end_clean();
+  if (!is_object($relation_type)) {
+    return form_error($form['relation_type'], t('Unable to interpret relation type code.'));
+  }
+  // relation_type name must be alphanumeric or underscores, no other punctuation.
+  if (!empty($form_state['values']['name']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['name'])) {
+    form_error($form['name'], t('Relation type name must be alphanumeric or underscores only.'));
+  }
+
+  if ($form_state['values']['name']) {
+    $relation_type->relation_type = $form_state['values']['name'];
+  }
+
+  if (relation_type_load($relation_type->relation_type)) {
+    form_set_error('name', t('A relation type by that name already exists; please choose a different name'));
+  }
+  $form_state['relation_type'] = $relation_type;
+}
+
+function relation_ui_type_import_submit($form, &$form_state) {
+  relation_type_save($form_state['relation_type']);
+  $relation_type = $form_state['relation_type']->relation_type;
+  drupal_set_message(t('Successfully imported @relation_type', array('@relation_type' => $relation_type)));
+  $form_state['redirect'] = 'admin/structure/relation/manage/' . $relation_type;
+}
+
+/**
+ * Relation display page title callback.
+ */
+function relation_ui_page_title($relation) {
+  return 'Relation ' . $relation->rid;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function relation_ui_theme() {
+  $theme = array(
+    'relation_ui_admin_content' => array(
+      'variables' => array('relations' => NULL)
+    ),
+  );
+  return $theme;
+}
+
+/**
+ * Autocomplete function for endpoint type filter.
+ */
+function relation_ui_endpoints_type_autocomplete($string = '') {
+  $result = db_query("SELECT distinct endpoints_entity_type FROM {field_data_endpoints} WHERE endpoints_entity_type LIKE :string", array(":string" => db_like($string) . '%'));
+  $matches = array();
+  while ($res = $result->fetchObject()) {
+    $matches[$res->endpoints_entity_type] = $res->endpoints_entity_type;
+  }
+  drupal_json_output($matches);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/tests/relation.rules.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,138 @@
+<?php
+/**
+ * @file
+ * Tests for Rules support.
+ */
+
+/**
+ * Functional test of Relation's integration with Rules.
+ */
+class RelationRulesTestCase extends RelationTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Relation Rules integration test',
+      'description' => 'Test the Rules integration.',
+      'group' => 'Relation',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('relation');
+    // While setUp fails for non-existing modules, module_enable() doesn't.
+    module_enable(array('rules'));
+  }
+
+  /**
+   * Test to create a relation in different ways by executing a rule.
+   */
+  function testRelationCreateRelation() {
+    // We don't want test failures if the Rules module isn't used.
+    if (module_exists('rules')) {
+      $node = $this->drupalCreateNode(array('type' => 'article'));
+      $user = $this->drupalCreateUser();
+      $endpoints = array(
+        entity_metadata_wrapper('node', $node),
+        entity_metadata_wrapper('user', $user),
+      );
+
+      // Test to create a relation by setting two endpoints and saving it. This
+      // primarily tests the endpoint property set callback.
+      $rule = rule();
+      $rule->action('entity_create', array(
+        'type' => 'relation',
+        'param_relation_type' => $this->relation_types['symmetric']['relation_type'],
+        'param_author:select' => 'site:current-user',
+        'param_endpoints' => $endpoints,
+        'entity_created:var' => 'relation',
+      ));
+      $rule->execute();
+
+      // There is no way for the rule to return the created relation. So get the
+      // last inserted id, which should be the relation we are looking for.
+      $rid = db_query('SELECT MAX(rid) FROM {relation}')->fetchField();
+      // If all went well, we should now have a relation with correct endpoints.
+      $relation = relation_load($rid);
+      $correct = ($relation->endpoints[LANGUAGE_NONE][0]['entity_id'] == $node->nid) && ($relation->endpoints[LANGUAGE_NONE][1]['entity_id'] == $user->uid);
+      $this->assertTrue($correct, 'Relation was created by setting two endpoints from rule context and saving it.');
+
+      // Test to create a relation by first fetching the endpoints from the
+      // last relation and then settings them in a new one. This primarily tests
+      // the endpoint property get callback.
+      $rule = rule();
+      // This will load a relation into the context of the rule.
+      $rule->action('entity_fetch', array('type' => 'relation', 'id' => $rid));
+      $rule->action('entity_create', array(
+        'type' => 'relation',
+        'param_relation_type' => $this->relation_types['symmetric']['relation_type'],
+        'param_author:select' => 'site:current-user',
+        // Now, load the endpoints from the fetched relation, into a new relation.
+        'param_endpoints:select' => 'entity-fetched:endpoints',
+        'entity_created:var' => 'relation',
+      ));
+      $rule->execute();
+
+      // There is no way for the rule to return the created relation. So get the
+      // last inserted id, which should be the relation we are looking for.
+      $rid = db_query('SELECT MAX(rid) FROM {relation}')->fetchField();
+      $relation = relation_load($rid);
+      // The $node and the $user should be the the same as in the last test, since
+      // we fetched the endpoits from that relation.
+      $correct = ($relation->endpoints[LANGUAGE_NONE][0]['entity_id'] == $node->nid) && ($relation->endpoints[LANGUAGE_NONE][1]['entity_id'] == $user->uid);
+      $this->assertTrue($correct, 'Relation was created by fetching endpoints from another relation and saving it.');
+
+
+      // Tests that relation properties are available in rules. So create a new
+      // rule with relation action, and check that the text is available among the
+      // "Data selectors" list.
+
+      // Enables UI module for rules.
+      module_enable(array('rules_admin'));
+      // Resets permissions, because module_enable() doesn't clear static cache.
+      $this->checkPermissions(array(), TRUE);
+      // Creates new user.
+      $user = $this->drupalCreateUser(array('administer rules'));
+      $this->drupalLogin($user);
+
+      // Cleares the cache, becaues UI module's menu items don't exists.
+      drupal_flush_all_caches();
+
+      // Creates rule.
+      $this->drupalGet('admin/config/workflow/rules/reaction/add');
+      $post = array(
+        'settings[label]' => 'Similar',
+        'settings[name]' => 'similar',
+        'event' => 'node_view',
+      );
+      $this->drupalPost(NULL, $post, t('Save'));
+
+      // Adds action.
+      $this->clickLink(t('Add action'));
+      $post = array(
+        'element_name' => 'relation_rules_load_related',
+      );
+      $this->drupalPost(NULL, $post, t('Continue'));
+      $this->assertText('node:relation-directional-node-reverse:0', t('The created relation porperties\' are found.'));
+    }
+  }
+
+  function testRelationLoadRelatedRules() {
+    if (module_exists('rules')) {
+      $nid = $this->node1->nid;
+      variable_set('relation_rules_test_nid', $nid);
+      module_enable(array('relation_rules_test'));
+      $this->node6 = $this->drupalCreateNode(array('type' => 'article'));
+      for ($i = 1; $i <= 6; $i++) {
+        $property = "node$i";
+        $node = $this->$property;
+        if ($node->nid == $nid) {
+          $this->assertFalse((bool) db_query_range('SELECT * FROM {node} WHERE nid = :nid', 0, 1, array(':nid' => $nid))->fetchField(), t('The correct node was deleted'));
+        }
+        else {
+          $nids[] = $node->nid;
+        }
+      }
+      $count = count($nids);
+      $this->assertEqual($count, db_query('SELECT COUNT(*) FROM {node} WHERE nid IN (:nids)', array(':nids' => $nids))->fetchField(), t('@count other nodes were found', array('@count' => $count)));
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/tests/relation.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,415 @@
+<?php
+
+/**
+ * @file
+ * Tests for Relation module.
+ */
+
+/**
+ * Relation helper class.
+ */
+class RelationTestCase extends DrupalWebTestCase {
+  protected $sleep = FALSE;
+
+  function setUp() {
+    // Other modules will reuse this class, make sure to pass the arguments up.
+    if (func_num_args()) {
+      parent::setUp(func_get_args());
+    }
+    else {
+      parent::setUp('relation');
+    }
+
+    // Defines users and permissions.
+    $permissions = array(
+      'create article content',
+      'create page content',
+      'administer relation types',
+      'administer relations',
+      'access relations',
+      'create relations',
+      'edit relations',
+      'delete relations',
+    );
+    $this->web_user = $this->drupalCreateUser($permissions);
+    $this->drupalLogin($this->web_user);
+
+    // Defines entities.
+    $this->createRelationNodes();
+    $this->createRelationUsers();
+
+    // Defines relation types.
+    $this->createRelationTypes();
+
+    // Defines end points.
+    $this->createRelationEndPoints();
+
+    // Defines relations.
+    $this->createRelationSymmetric();
+    $this->createRelationDirectional();
+    $this->createRelationOctopus();
+  }
+
+  /**
+   * Creates nodes.
+   */
+  function createRelationNodes() {
+    $this->node1 = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'title' => 'Grandparent'));
+    $this->node2 = $this->drupalCreateNode(array('type' => 'article', 'promote' => 0));
+    $this->node3 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1, 'title' => 'Parent'));
+    $this->node4 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 0, 'title' => 'Child'));
+    $this->node5 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 0));
+    $this->node6 = $this->drupalCreateNode(array('type' => 'page', 'promote' => 0, 'title' => 'Unrelated'));
+  }
+
+  function createRelationUsers() {
+    $this->user1 = $this->drupalCreateUser();
+  }
+
+  /**
+   * Creates end points.
+   */
+  function createRelationEndPoints() {
+    $this->endpoints = array(
+      array('entity_type' => 'node', 'entity_id' => $this->node1->nid),
+      array('entity_type' => 'node', 'entity_id' => $this->node4->nid),
+    );
+    $this->endpoints_4 = array(
+      array('entity_type' => 'node', 'entity_id' => $this->node1->nid),
+      array('entity_type' => 'node', 'entity_id' => $this->node2->nid),
+      array('entity_type' => 'node', 'entity_id' => $this->node3->nid),
+      array('entity_type' => 'node', 'entity_id' => $this->node4->nid),
+    );
+    $this->endpoints_entitysame = array(
+      array('entity_type' => 'node', 'entity_id' => $this->node3->nid),
+      array('entity_type' => 'node', 'entity_id' => $this->node4->nid),
+    );
+    $this->endpoints_entitydifferent = array(
+      array('entity_type' => 'user', 'entity_id' => $this->user1->uid),
+      array('entity_type' => 'node', 'entity_id' => $this->node3->nid),
+    );
+  }
+
+  /**
+   * Creates a set of standard relation types.
+   */
+  function createRelationTypes() {
+    $this->relation_types['symmetric'] = array(
+      'relation_type' => 'symmetric',
+      'label' => 'symmetric',
+      'source_bundles' => array('node:article', 'node:page', 'taxonomy_term:*', 'user:*'),
+    );
+    $this->relation_types['directional'] = array(
+      'relation_type' => 'directional',
+      'label' => 'directional',
+      'directional' => TRUE,
+      'source_bundles' => array('node:*'),
+      'target_bundles' => array('node:page'),
+    );
+    $this->relation_types['directional_entitysame'] = array(
+      'relation_type' => 'directional_entitysame',
+      'label' => 'directional_entitysame',
+      'directional' => TRUE,
+      'source_bundles' => array('node:page'),
+      'target_bundles' => array('node:page'),
+    );
+    $this->relation_types['directional_entitydifferent'] = array(
+      'relation_type' => 'directional_entitydifferent',
+      'label' => 'directional_entitydifferent',
+      'directional' => TRUE,
+      'source_bundles' => array('user:*'),
+      'target_bundles' => array('node:page'),
+    );
+    $this->relation_types['octopus'] = array(
+      'relation_type' => 'octopus',
+      'label' => 'octopus',
+      'min_arity' => 3,
+      'max_arity' => 5,
+      'source_bundles' => array('node:article', 'node:page'),
+    );
+    foreach ($this->relation_types as $relation_type) {
+      relation_type_save($relation_type);
+    }
+  }
+
+  /**
+   * Creates a Symmetric relation.
+   */
+  function createRelationSymmetric() {
+    // Article 1 <--> Page 4
+    $this->relation_type_symmetric = $this->relation_types['symmetric']['relation_type'];
+    $this->rid_symmetric = $this->saveRelation($this->relation_type_symmetric, $this->endpoints);
+  }
+
+  /**
+   * Creates a Directional relation.
+   */
+  function createRelationDirectional() {
+    // Article 1 --> Page 3
+    $this->endpoints[1]['entity_id'] = $this->node3->nid;
+    $this->endpoints[1]['r_index'] = 1;
+    $this->relation_type_directional = $this->relation_types['directional']['relation_type'];
+    $this->rid_directional = $this->saveRelation($this->relation_type_directional, $this->endpoints);
+    // Page 3 --> Page 4
+    $this->endpoints[0]['entity_id'] = $this->node3->nid;
+    $this->endpoints[1]['entity_id'] = $this->node4->nid;
+    $this->saveRelation($this->relation_type_directional, $this->endpoints);
+
+    // Page 3 --> Page 4
+    $this->endpoints_entitysame[1]['r_index'] = 1;
+    $this->relation_type_directional_entitysame = $this->relation_types['directional_entitysame']['relation_type'];
+    $this->saveRelation($this->relation_type_directional_entitysame, $this->endpoints_entitysame);
+    // Page 3 --> Page 5
+    $this->endpoints_entitysame[1]['entity_id'] = $this->node5->nid;
+    $this->saveRelation($this->relation_type_directional_entitysame, $this->endpoints_entitysame);
+    // Page 4 --> Page 3
+    $this->endpoints_entitysame[0]['entity_id'] = $this->node4->nid;
+    $this->endpoints_entitysame[1]['entity_id'] = $this->node3->nid;
+    $this->saveRelation($this->relation_type_directional_entitysame, $this->endpoints_entitysame);
+
+    // User 1 --> Page 3
+    $this->endpoints_entitydifferent[1]['r_index'] = 1;
+    $this->relation_type_directional_entitydifferent = $this->relation_types['directional_entitydifferent']['relation_type'];
+    $this->saveRelation($this->relation_type_directional_entitydifferent, $this->endpoints_entitydifferent);
+    // User 1 --> Page 4
+    $this->endpoints_entitydifferent[1]['entity_id'] = $this->node4->nid;
+    $this->saveRelation($this->relation_type_directional_entitydifferent, $this->endpoints_entitydifferent);
+  }
+
+  /**
+   * Creates an Octopus (4-ary) relation.
+   */
+  function createRelationOctopus() {
+    // Nodes 1, 2, 3, 4 are related.
+    $this->relation_type_octopus = $this->relation_types['octopus']['relation_type'];
+    $this->rid_octopus = $this->saveRelation($this->relation_type_octopus, $this->endpoints_4);
+  }
+
+  /**
+   * Saves a relation.
+   */
+  function saveRelation($relation_type, $endpoints) {
+    $relation = relation_create($relation_type, $endpoints);
+    $rid = relation_save($relation);
+    if ($this->sleep) {
+      sleep(1);
+    }
+    return $rid;
+  }
+}
+
+/**
+ * Tests Relation API.
+ *
+ * Create nodes, add relations and verify that they are related.
+ * This test suite also checks all methods available in RelationQuery.
+ */
+class RelationAPITestCase extends RelationTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Relation test',
+      'description' => 'Tests Relation API.',
+      'group' => 'Relation',
+    );
+  }
+
+  function setUp() {
+    // This is necessary for the ->propertyOrderBy('created', 'DESC') test.
+    $this->sleep = TRUE;
+    parent::setUp();
+  }
+
+  /**
+   * Tests all available methods in RelationQuery.
+   * Creates some nodes, add some relations and checks if they are related.
+   */
+  function testRelationQuery() {
+    $relations = entity_load('relation', array_keys(relation_query('node', $this->node1->nid)->execute()));
+
+    // Check that symmetric relation is correctly related to node 4.
+    $this->assertEqual($relations[$this->rid_symmetric]->endpoints[LANGUAGE_NONE][1]['entity_id'], $this->node4->nid, 'Correct entity is related: ' . $relations[$this->rid_symmetric]->endpoints[LANGUAGE_NONE][1]['entity_id'] . '==' . $this->node4->nid);
+
+    // Get relations for node 1, should return 3 relations.
+    $count = count($relations);
+    $this->assertEqual($count, 3);
+
+    // Get number of relations for node 4, should return 6 relations.
+    $count = relation_query('node', $this->node4->nid)
+      ->count()
+      ->execute();
+    $this->assertEqual($count, 6);
+
+    // Get number of relations for node 5, should return 1 relation.
+    $count = relation_query('node', $this->node5->nid)
+      ->count()
+      ->execute();
+    $this->assertEqual($count, 1);
+
+    // Get relations between entities 2 and 5 (none).
+    $count = relation_query('node', $this->node2->nid)
+      ->related('node', $this->node5->nid)
+      ->count()
+      ->execute();
+    $this->assertFalse($count);
+
+    // Get directed relations for node 3 using index, should return 2 relations.
+    // The other node 3 relation has an r_index 0.
+    $relations = relation_query('node', $this->node3->nid, 1)
+      ->execute();
+    $this->assertEqual(count($relations), 3);
+    $this->assertTrue(isset($relations[$this->rid_directional]), 'Got the correct directional relation for nid=3.');
+
+    // Get relations between entities 2 and 3 (octopus).
+    $relations = relation_query('node', $this->node2->nid)
+      ->related('node', $this->node3->nid)
+      ->execute();
+    $count = count($relations);
+    $this->assertEqual($count, 1);
+    // Check that we have the correct relations
+    $this->assertEqual(isset($relations[$this->rid_octopus]), 'Got one correct relation.');
+
+    // Get relations for node 1 (symmetric, directional, octopus), limit to
+    // directional and octopus with relation_type().
+    $relations = relation_query('node', $this->node1->nid)
+      ->propertyCondition('relation_type', array(
+        $this->relation_types['directional']['relation_type'],
+        $this->relation_types['octopus']['relation_type'],
+      ))
+      ->execute();
+    $count = count($relations);
+    $this->assertEqual($count, 2);
+    // Check that we have the correct relations.
+    $this->assertTrue(isset($relations[$this->rid_directional]), 'Got one correct relation.');
+    $this->assertTrue(isset($relations[$this->rid_octopus]), 'Got a second one.');
+
+    // Get last two relations for node 1.
+    $relations = relation_query('node', $this->node1->nid)
+      ->range(1, 2)
+      ->propertyOrderBy('rid', 'ASC')
+      ->execute();
+    $count = count($relations);
+    $this->assertEqual($count, 2);
+    // Check that we have the correct relations.
+    $this->assertTrue(isset($relations[$this->rid_directional]), 'Got one correct relation.');
+    $this->assertTrue(isset($relations[$this->rid_octopus]), 'Got a second one.');
+
+    // Get all relations on node 1 and sort them in reverse created order.
+    $relations = relation_query('node', $this->node1->nid)
+      ->propertyOrderBy('created', 'DESC')
+      ->execute();
+    $this->assertEqual(array_keys($relations), array($this->rid_octopus, $this->rid_directional, $this->rid_symmetric));
+    
+    // Create 10 more symmetric relations and verify that the count works with
+    // double digit counts as well.
+    for($i = 0; $i < 10; $i++) {
+      $this->createRelationSymmetric();
+    }
+    $count = relation_query('node', $this->node4->nid)
+      ->count()
+      ->execute();
+    $this->assertEqual($count, 16);        
+  }
+
+  /**
+   * Tests relation types.
+   */
+  function testRelationTypes() {
+    // Symmetric.
+    $related = relation_get_related_entity('node', $this->node1->nid);
+    $this->assertEqual($this->node4->nid, $related->nid);
+
+    // Confirm this works once the related entity has been cached.
+    $related = relation_get_related_entity('node', $this->node1->nid);
+    $this->assertEqual($this->node4->nid, $related->nid);
+
+    // Directional.
+    // From Parent to Grandparent.
+    $related = relation_get_related_entity('node', $this->node3->nid, $this->relation_types['directional']['relation_type'], 1);
+    $this->assertEqual($this->node1->nid, $related->nid);
+    // From Parent to Child.
+    $related = relation_get_related_entity('node', $this->node3->nid, $this->relation_types['directional']['relation_type'], 0);
+    $this->assertEqual($this->node4->nid, $related->nid);
+
+    // Delete all relations related to node 4, then confirm that these can
+    // no longer be found as related entities.
+    $relations = relation_query('node', $this->node4->nid)->execute();
+    foreach ($relations as $relation) {
+      relation_delete($relation->rid);
+    }
+    $this->assertFalse(relation_get_related_entity('node', $this->node4->nid), 'The entity was not loaded after the relation was deleted.');
+  }
+
+  /**
+   * Tests saving of relations.
+   */
+  function testRelationSave() {
+    foreach ($this->relation_types as $value) {
+      $relation_type = $value['relation_type'];
+      $endpoints = isset($value['min_arity']) ? $this->endpoints_4 : $this->endpoints;
+      if ($relation_type == 'directional_entitydifferent') {
+        $endpoints = $this->endpoints_entitydifferent;
+      }
+      $relation = relation_create($relation_type, $endpoints);
+      $rid = relation_save($relation);
+      $this->assertTrue($rid, 'Relation created.');
+      $count = count($relation->endpoints[LANGUAGE_NONE]);
+      $this->assertEqual($count, count($endpoints));
+      $this->assertEqual($relation->arity, count($endpoints));
+      $this->assertEqual($relation->relation_type, $relation_type);
+      foreach ($relation->endpoints[LANGUAGE_NONE] as $endpoint) {
+        $need_ids[$endpoint['entity_id']] = TRUE;
+      }
+      foreach ($relation->endpoints[LANGUAGE_NONE] as $delta => $endpoint) {
+        $this->assertEqual($endpoint['entity_type'], $endpoints[$delta]['entity_type'], 'The entity type is ' . $endpoints[$delta]['entity_type'] . ': ' . $endpoint['entity_type']);
+        $this->assertTrue(isset($need_ids[$endpoint['entity_id']]), 'The entity ID is correct: ' . $need_ids[$endpoint['entity_id']]);
+        unset($need_ids[$endpoint['entity_id']]);
+      }
+      $this->assertFalse($need_ids, 'All ids found.');
+      // Confirm the rid in revision table.
+      $revision = db_select('relation_revision', 'v')
+          ->fields('v', array('rid'))
+          ->condition('vid', $relation->vid)
+          ->execute()
+          ->fetchAllAssoc('rid');
+      $this->assertTrue(array_key_exists($rid, $revision), 'Relation revision created.');
+    }
+  }
+
+  /**
+   * Tests relation delete.
+   */
+  function testRelationDelete() {
+    // Invalid relations are deleted when any endpoint entity is deleted. 
+    // Octopus relation is valid with 3 endpoints, currently it has 4.
+    node_delete($this->node1->nid);
+    $this->assertTrue(relation_load($this->rid_octopus, NULL, TRUE), 'Relation is not deleted.');
+    node_delete($this->node2->nid);
+    $this->assertFalse(relation_load($this->rid_octopus, NULL, TRUE), 'Relation is deleted.');
+  }
+
+  /**
+   * Tests relation revisions.
+   */
+  function testRelationRevision() {
+    $first_user = $this->drupalCreateUser(array('edit relations'));
+    $second_user = $this->drupalCreateUser(array('edit relations'));
+
+    $this->drupalLogin($first_user);
+    $relation = relation_create($this->relation_type_octopus, $this->endpoints_4, $first_user);
+    $rid = relation_save($relation, $first_user);
+    $this->assertEqual($relation->uid, $first_user->uid);
+    $vid = $relation->vid;
+
+    // Relation should still be owned by the first user
+    $this->drupalLogin($second_user);
+    $relation = relation_load($rid);
+    relation_save($relation, $second_user);
+    $this->assertEqual($relation->uid, $first_user->uid);
+
+    // Relation revision authors should not be identical though.
+    $first_revision = relation_load($rid, $vid);
+    $second_revision = relation_load($rid, $relation->vid);
+    $this->assertNotIdentical($first_revision->revision_uid, $second_revision->revision_uid, 'Each revision has a distinct user.');
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/tests/relation.views.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,497 @@
+<?php
+/**
+ * @file
+ * Tests for Views support in the Relation module.
+ */
+
+/**
+ * Functional test of Relation's integration with Views.
+ */
+class RelationViewsTestCase extends RelationTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Relation Views test',
+      'description' => 'Tests the Relation Views support.',
+      'group' => 'Relation',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('relation', 'relation_entity_collector');
+    // While setUp fails for non-existing modules, module_enable() doesn't.
+    module_enable(array('views'));
+  }
+
+  /**
+   * Tests views with relations as a base table.
+   */
+  function testRelationsAsBaseTable() {
+    if (!module_exists('views')) {
+      return;
+    }
+
+    foreach (array('symmetric', 'directional', 'octopus') as $relation_type) {
+      $view = new view;
+      $view->base_table = 'relation';
+      $handler = $view->new_display('default');
+      $handler->display->display_options['relationships']['uid']['id'] = 'uid';
+      $handler->display->display_options['relationships']['uid']['table'] = 'relation';
+      $handler->display->display_options['relationships']['uid']['field'] = 'uid';
+      $handler->display->display_options['fields']['rid']['id'] = 'rid';
+      $handler->display->display_options['fields']['rid']['table'] = 'relation';
+      $handler->display->display_options['fields']['rid']['field'] = 'rid';
+      $handler->display->display_options['fields']['relation_type']['id'] = 'relation_type';
+      $handler->display->display_options['fields']['relation_type']['table'] = 'relation';
+      $handler->display->display_options['fields']['relation_type']['field'] = 'relation_type';
+      $handler->display->display_options['fields']['arity']['id'] = 'arity';
+      $handler->display->display_options['fields']['arity']['table'] = 'relation';
+      $handler->display->display_options['fields']['arity']['field'] = 'arity';
+      $handler->display->display_options['arguments']['rid']['id'] = 'rid';
+      $handler->display->display_options['arguments']['rid']['table'] = 'relation';
+      $handler->display->display_options['arguments']['rid']['field'] = 'rid';
+      $view->set_arguments(array($this->{'rid_' . $relation_type}));
+      $view->execute();
+
+      $result = array_shift($view->result);
+      $this->assertTrue(empty($view->result));
+      $this->assertEqual($result->relation_relation_type, $relation_type);
+      switch ($relation_type) {
+        case 'symmetric':
+          // Relation #1 is of type symmetric and has 2 endpoints.
+          $this->assertEqual($result->rid, 1);
+          $this->assertEqual($result->relation_arity, 2);
+          break;
+        case 'directional':
+          // Relation #2 is of type directional and has 2 endpoints.
+          $this->assertEqual($result->rid, 2);
+          $this->assertEqual($result->relation_arity, 2);
+          break;
+        case 'directional_entitysame':
+          // Relation #4 is of type directional_entitysame and has 2 endpoints.
+          $this->assertEqual($result->rid, 4);
+          $this->assertEqual($result->relation_arity, 2);
+          break;
+        case 'directional_entitydifferent':
+          // Relation #7 is of type directional_entitydifferent and has 2 endpoints.
+          $this->assertEqual($result->rid, 7);
+          $this->assertEqual($result->relation_arity, 2);
+          break;
+        case 'octopus':
+          // Relation #4 is of type octopus and has 4 endpoints.
+          $this->assertEqual($result->rid, 9);
+          $this->assertEqual($result->relation_arity, 4);
+          break;
+      }
+    }
+  }
+
+  /**
+   * Tests views with symmetric relations.
+   */
+  function testSymmetricRelations() {
+    if (!module_exists('views')) {
+      return;
+    }
+
+    foreach (array(FALSE, TRUE) as $required) {
+      $view = new view;
+      $handler = $view->new_display('default');
+      $handler->display->display_options['relationships']['relation_symmetric_node']['id'] = 'relation_symmetric_node';
+      $handler->display->display_options['relationships']['relation_symmetric_node']['table'] = 'node';
+      $handler->display->display_options['relationships']['relation_symmetric_node']['field'] = 'relation_symmetric_node';
+      $handler->display->display_options['relationships']['relation_symmetric_node']['required'] = $required;
+      $handler->display->display_options['fields']['nid']['id'] = 'nid';
+      $handler->display->display_options['fields']['nid']['table'] = 'node';
+      $handler->display->display_options['fields']['nid']['field'] = 'nid';
+      $handler->display->display_options['fields']['nid']['relationship'] = 'relation_symmetric_node';
+      $handler->display->display_options['fields']['nid2']['id'] = 'nid2';
+      $handler->display->display_options['fields']['nid2']['table'] = 'node';
+      $handler->display->display_options['fields']['nid2']['field'] = 'nid';
+      $handler->display->display_options['arguments']['nid']['id'] = 'nid';
+      $handler->display->display_options['arguments']['nid']['table'] = 'node';
+      $handler->display->display_options['arguments']['nid']['field'] = 'nid';
+
+      // The result should be the same for required and non-required for
+      // argument node 1: Relation from 1 to 4.
+      $view->set_arguments(array($this->node1->nid));
+      $view->execute();
+
+      $this->assertEqual(count($view->result), 1);
+      $result = array_pop($view->result);
+      $this->assertEqual($result->nid, $this->node1->nid);
+      $this->assertEqual($result->node_node_nid, $this->node4->nid);
+
+      $view = $view->clone_view();
+
+      // The result should be different for required and non-required for
+      // argument node 6: for required, there should be no results. For
+      // non-required, node 6 may be returned.
+      $view->set_arguments(array($this->node6->nid));
+      $view->execute();
+
+      if ($required) {
+        $this->assertEqual(count($view->result), 0);
+      }
+      else {
+        $this->assertEqual(count($view->result), 1);
+        $result = array_pop($view->result);
+        $this->assertEqual($result->nid, $this->node6->nid);
+        $this->assertEqual($result->node_node_nid, NULL);
+      }
+    }
+  }
+
+  /**
+   * Tests views with directional relations to source, to target and to both.
+   */
+  function testDirectionalRelations() {
+    if (!module_exists('views')) {
+      return;
+    }
+
+    foreach (array(FALSE, TRUE) as $required) {
+      for ($r_index = -1; $r_index < 2; $r_index++) {
+        $view = new view;
+        $handler = $view->new_display('default');
+        $handler->display->display_options['relationships']['relation_directional_node']['id'] = 'relation_directional_node';
+        $handler->display->display_options['relationships']['relation_directional_node']['table'] = 'node';
+        $handler->display->display_options['relationships']['relation_directional_node']['field'] = 'relation_directional_node';
+        $handler->display->display_options['relationships']['relation_directional_node']['required'] = $required;
+        $handler->display->display_options['relationships']['relation_directional_node']['r_index'] = $r_index;
+        $handler->display->display_options['fields']['nid_source']['id'] = 'nid';
+        $handler->display->display_options['fields']['nid_source']['table'] = 'node';
+        $handler->display->display_options['fields']['nid_source']['field'] = 'nid';
+        $handler->display->display_options['fields']['nid_target']['id'] = 'nid';
+        $handler->display->display_options['fields']['nid_target']['table'] = 'node';
+        $handler->display->display_options['fields']['nid_target']['field'] = 'nid';
+        $handler->display->display_options['fields']['nid_target']['relationship'] = 'relation_directional_node';
+        $handler->display->display_options['arguments']['nid']['id'] = 'nid';
+        $handler->display->display_options['arguments']['nid']['table'] = 'node';
+        $handler->display->display_options['arguments']['nid']['field'] = 'nid';
+
+        // First test: node that has relations. The results should be the same
+        // for required and non-required relations.
+        $view->set_arguments(array($this->node3->nid));
+        $view->execute();
+
+        switch ($r_index) {
+          case -1:
+            // Directional, both ways.
+            $this->assertEqual(count($view->result), 2);
+            $targetmatches = array($this->node1->nid => TRUE, $this->node4->nid => TRUE);
+            foreach ($view->result as $result) {
+              $this->assertEqual($result->nid, $this->node3->nid);
+              unset($targetmatches[$result->node_node_nid]);
+            }
+            $this->assertFalse($targetmatches);
+            break;
+          case 0:
+            // Source. This finds the 3->4 relation.
+            $this->assertEqual(count($view->result), 1);
+            $this->assertEqual($view->result[0]->nid, $this->node3->nid);
+            $this->assertEqual($view->result[0]->node_node_nid, $this->node4->nid);
+            break;
+          case 1:
+            // Target. This finds the 1->3 relation.
+            $this->assertEqual(count($view->result), 1);
+            $this->assertEqual($view->result[0]->nid, $this->node3->nid);
+            $this->assertEqual($view->result[0]->node_node_nid, $this->node1->nid);
+            break;
+        }
+
+        // Second test: node that has no relations. The results should be that
+        // no results are found for the required relation, and 6 / NULL
+        // for the optional relation.
+        $view = $view->clone_view(); 
+        $view->set_arguments(array($this->node6->nid));
+        $view->execute();
+
+        if ($required) {
+          $this->assertEqual(count($view->result), 0);
+        }
+        else {
+          $this->assertEqual(count($view->result), 1);
+          $result = array_pop($view->result);
+          $this->assertEqual($result->nid, $this->node6->nid);
+          $this->assertEqual($result->node_node_nid, NULL);
+        }
+      }
+    }
+  }
+
+  /**
+   * Tests views with forward directional relations to source, to target and to
+   * both with the same entities types.
+   */
+  function testForwardDirectionalSameEntityRelations() {
+    if (!module_exists('views')) {
+      return;
+    }
+
+    for ($r_index = -1; $r_index < 2; $r_index++) {
+      $view = new view;
+      $view->base_table = 'node';
+      $handler = $view->new_display('default');
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['id'] = 'relation_directional_entitysame_node';
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['table'] = 'node';
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['field'] = 'relation_directional_entitysame_node';
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['required'] = 1;
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['r_index'] = $r_index;
+      $handler->display->display_options['fields']['nid']['id'] = 'nid';
+      $handler->display->display_options['fields']['nid']['table'] = 'node';
+      $handler->display->display_options['fields']['nid']['field'] = 'nid';
+      $handler->display->display_options['fields']['nid']['relationship'] = 'relation_directional_entitysame_node';
+      $handler->display->display_options['arguments']['nid']['id'] = 'nid';
+      $handler->display->display_options['arguments']['nid']['table'] = 'node';
+      $handler->display->display_options['arguments']['nid']['field'] = 'nid';
+      $view->set_arguments(array($this->node3->nid));
+      $view->execute();
+
+      switch ($r_index) {
+        case -1:
+          // Directional, both ways.
+          $this->assertEqual(count($view->result), 3);
+          $matches = array($this->node4->nid => TRUE, $this->node4->nid => TRUE, $this->node5->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->node_node_nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+        case 0:
+          // Source. This finds the p3->p4 and p3->p5 relations.
+          $this->assertEqual(count($view->result), 2);
+          $matches = array($this->node4->nid => TRUE, $this->node5->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->node_node_nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+        case 1:
+          // Target. This finds the p4->p3 relation.
+          $this->assertEqual(count($view->result), 1);
+          $matches = array($this->node4->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->node_node_nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+      }
+    }
+  }
+
+  /**
+   * Tests views with reverse directional relations to source, to target and to
+   * both with the same entities types.
+   */
+  function testReverseDirectionalSameEntityRelations() {
+    for ($r_index = -1; $r_index < 2; $r_index++) {
+      $view = new view;
+      $view->base_table = 'node';
+      $handler = $view->new_display('default');
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['id'] = 'relation_directional_entitysame_node';
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['table'] = 'node';
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['field'] = 'relation_directional_entitysame_node';
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['required'] = 1;
+      $handler->display->display_options['relationships']['relation_directional_entitysame_node']['r_index'] = $r_index;
+      $handler->display->display_options['fields']['nid']['id'] = 'nid';
+      $handler->display->display_options['fields']['nid']['table'] = 'node';
+      $handler->display->display_options['fields']['nid']['field'] = 'nid';
+      $handler->display->display_options['arguments']['nid']['id'] = 'nid';
+      $handler->display->display_options['arguments']['nid']['table'] = 'node';
+      $handler->display->display_options['arguments']['nid']['field'] = 'nid';
+      $handler->display->display_options['arguments']['nid']['relationship'] = 'relation_directional_entitysame_node';
+      $view->set_arguments(array($this->node3->nid));
+      $view->execute();
+
+      switch ($r_index) {
+        case -1:
+          // Directional, both ways.
+          $this->assertEqual(count($view->result), 3);
+          $matches = array($this->node4->nid => TRUE, $this->node5->nid => TRUE, $this->node4->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+        case 0:
+          // Reverse source. This finds the p4->p3 relation.
+          $this->assertEqual(count($view->result), 1);
+          $matches = array($this->node4->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+        case 1:
+          // Reverse target. This finds the p3->p4 and p3->p5 relations.
+          $this->assertEqual(count($view->result), 2);
+          $matches = array($this->node4->nid => TRUE, $this->node5->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+      }
+    }
+  }
+
+  /**
+   * Tests views with forward directional relations to source, to target and to
+   * both with different entities types.
+   */
+  function testForwardDirectionalDifferentEntityRelations() {
+    for ($r_index = -1; $r_index < 2; $r_index++) {
+      $view = new view;
+      $view->base_table = 'users';
+      $handler = $view->new_display('default');
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['id'] = 'relation_directional_entitydifferent_node';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['table'] = 'users';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['field'] = 'relation_directional_entitydifferent_node';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['required'] = 1;
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['r_index'] = $r_index;
+      $handler->display->display_options['fields']['nid']['id'] = 'nid';
+      $handler->display->display_options['fields']['nid']['table'] = 'node';
+      $handler->display->display_options['fields']['nid']['field'] = 'nid';
+      $handler->display->display_options['fields']['nid']['relationship'] = 'relation_directional_entitydifferent_node';
+      $handler->display->display_options['arguments']['uid']['id'] = 'uid';
+      $handler->display->display_options['arguments']['uid']['table'] = 'users';
+      $handler->display->display_options['arguments']['uid']['field'] = 'uid';
+      $view->set_arguments(array($this->user1->uid));
+      $view->execute();
+
+      switch ($r_index) {
+        case -1:
+          // Directional, both ways.
+          $this->assertEqual(count($view->result), 2);
+          $matches = array($this->node3->nid => TRUE, $this->node4->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->node_users_nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+        case 0:
+          // Source. This finds the u1->p3 and u1->p4 relation.
+          $this->assertEqual(count($view->result), 2);
+          $matches = array($this->node3->nid => TRUE, $this->node4->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->node_users_nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+        case 1:
+          // Target. This finds no relations.
+          $this->assertEqual(count($view->result), 0);
+          $matches = array();
+          foreach ($view->result as $result) {
+            unset($matches[$result->node_users_nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+      }
+    }
+  }
+
+  /**
+   * Tests views with reverse directional relations to source, to target and to
+   * both with different entities types.
+   */
+  function testReverseDirectionalDifferentEntityRelations() {
+    for ($r_index = -1; $r_index < 2; $r_index++) {
+      $view = new view;
+      $view->base_table = 'node';
+      $handler = $view->new_display('default');
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['id'] = 'relation_directional_entitydifferent_user';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['table'] = 'node';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['field'] = 'relation_directional_entitydifferent_user';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['required'] = 1;
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['r_index'] = $r_index;
+      $handler->display->display_options['fields']['nid']['id'] = 'nid';
+      $handler->display->display_options['fields']['nid']['table'] = 'node';
+      $handler->display->display_options['fields']['nid']['field'] = 'nid';
+      $handler->display->display_options['arguments']['uid']['id'] = 'uid';
+      $handler->display->display_options['arguments']['uid']['table'] = 'users';
+      $handler->display->display_options['arguments']['uid']['field'] = 'uid';
+      $handler->display->display_options['arguments']['uid']['relationship'] = 'relation_directional_entitydifferent_user';
+      $view->set_arguments(array($this->user1->uid));
+      $view->execute();
+
+      switch ($r_index) {
+        case -1:
+          // Directional, both ways.
+          $this->assertEqual(count($view->result), 2);
+          $matches = array($this->node3->nid => TRUE, $this->node4->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+        case 0:
+          // Source. This finds no relations.
+          $this->assertEqual(count($view->result), 0);
+          $matches = array();
+          foreach ($view->result as $result) {
+            unset($matches[$result->nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+        case 1:
+          // Target. This finds the u1->p3 and u1->p4 relation.
+          $this->assertEqual(count($view->result), 2);
+          $matches = array($this->node3->nid => TRUE, $this->node4->nid => TRUE);
+          foreach ($view->result as $result) {
+            unset($matches[$result->nid]);
+          }
+          $this->assertFalse($matches);
+          break;
+      }
+    }
+  }
+
+  /**
+   * Tests views deduplication.
+   */
+  function testDeduplication() {
+    for ($i = 0; $i < 2; $i++) {
+      $view = new view;
+      $view->base_table = 'node';
+      $handler = $view->new_display('default');
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['id'] = 'relation_directional_entitydifferent_user';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['table'] = 'node';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['field'] = 'relation_directional_entitydifferent_user';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_user']['required'] = 1;
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['id'] = 'relation_directional_entitydifferent_node';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['table'] = 'users';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['field'] = 'relation_directional_entitydifferent_node';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['relationship'] = 'relation_directional_entitydifferent_user';
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['required'] = 1;
+      $handler->display->display_options['relationships']['relation_directional_entitydifferent_node']['entity_deduplication_right'] = $i;
+      $handler->display->display_options['fields']['nid']['id'] = 'nid';
+      $handler->display->display_options['fields']['nid']['table'] = 'node';
+      $handler->display->display_options['fields']['nid']['field'] = 'nid';
+      $handler->display->display_options['fields']['nid_1']['id'] = 'nid_1';
+      $handler->display->display_options['fields']['nid_1']['table'] = 'node';
+      $handler->display->display_options['fields']['nid_1']['field'] = 'nid';
+      $handler->display->display_options['fields']['nid_1']['relationship'] = 'relation_directional_entitydifferent_node';
+      $handler->display->display_options['arguments']['uid']['id'] = 'uid';
+      $handler->display->display_options['arguments']['uid']['table'] = 'users';
+      $handler->display->display_options['arguments']['uid']['field'] = 'uid';
+      $handler->display->display_options['arguments']['uid']['relationship'] = 'relation_directional_entitydifferent_user';
+      $view->set_arguments(array($this->user1->uid));
+      $view->execute();
+      $this->assertEqual(count($view->result), 4 - 2 * $i);
+      $possible_nids = array($this->node3->nid => TRUE, $this->node4->nid => TRUE);
+      $fail = FALSE;
+      $all_results = array();
+      foreach ($view->result as $result) {
+        $this->assertTrue(isset($possible_nids[$result->nid]) && isset($possible_nids[$result->node_users_nid]), 'Correct nid found');
+        $this->assertFalse(isset($all_results[$result->nid][$result->node_users_nid]), 'No row duplication');
+        $all_results[$result->nid][$result->node_users_nid] = TRUE;
+        $fail = $fail || ($i && $result->nid == $result->node_users_nid);
+      }
+      if ($i) {
+        $this->assertFalse($fail, 'Deduplication worked');
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/tests/relation_rules_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+name = "Relation Tests"
+description = "Support module for the Relation - Rules integration tests."
+package = Testing
+core = 7.x
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2013-02-07
+version = "7.x-1.0-rc4"
+core = "7.x"
+project = "relation"
+datestamp = "1360240967"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/tests/relation_rules_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * @file
+ * Test for Relation's Rules implementation.
+ */
+
+/**
+ * Implementation of hook_default_rules_configuration().
+ */
+function relation_rules_test_default_rules_configuration() {
+  $nid = variable_get('relation_rules_test_nid', 0);
+  $items = array();
+  $items['rules_test'] = entity_import('rules_config', '{ "rules_test" : {
+    "LABEL" : "test",
+    "PLUGIN" : "reaction rule",
+    "REQUIRES" : [ "rules", "relation" ],
+    "ON" : [ "node_insert" ],
+    "DO" : [
+      { "variable_add" : {
+          "USING" : { "type" : "list\u003centity\u003e", "value" : [ "" ] },
+          "PROVIDE" : { "variable_added" : { "new_relation" : "New relation" } }
+        }
+      },
+      { "list_add" : { "list" : [ "new-relation" ], "item" : [ "node" ] } },
+      { "variable_add" : {
+          "USING" : { "type" : "node", "value" : "' . $nid . '" },
+          "PROVIDE" : { "variable_added" : { "node_1" : "Node 1" } }
+        }
+      },
+      { "list_add" : { "list" : [ "new-relation" ], "item" : [ "node-1" ] } },
+      { "entity_create" : {
+          "USING" : {
+            "type" : "relation",
+            "param_relation_type" : "symmetric",
+            "param_endpoints" : [ "new-relation" ]
+          },
+          "PROVIDE" : { "entity_created" : { "entity_created" : "Created entity" } }
+        }
+      },
+      { "entity_save" : { "data" : [ "entity-created" ], "immediate" : 1 } },
+      { "relation_rules_load_related" : {
+          "USING" : { "left" : [ "node" ], "relation_type" : "symmetric" },
+          "PROVIDE" : { "endpoints" : { "endpoints" : "List of related entities" } }
+        }
+      },
+      { "entity_delete" : { "data" : [ "endpoints:0" ] } }
+    ]
+  }
+}');
+  return $items;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/tests/relation_ui.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,197 @@
+<?php
+
+/**
+ * @file
+ * Tests for Relation UI module.
+ */
+
+/**
+ * Tests Relation UI.
+ *
+ * Check that relation administration interface works.
+ */
+class RelationUITestCase extends RelationTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Relation UI test',
+      'description' => 'Tests Relation UI.',
+      'group' => 'Relation',
+    );
+  }
+
+  function setUp() {
+    // This is necessary for the ->propertyOrderBy('created', 'DESC') test.
+    $this->sleep = TRUE;
+    parent::setUp('relation_ui');
+  }
+
+  /**
+   * Tests deletion of a relation.
+   */
+  function testRelationDelete() {
+    $relations = relation_query('node', $this->node1->nid)
+      ->propertyOrderBy('created', 'DESC')
+      ->execute();
+    $relation = $relations[$this->rid_directional];
+
+    $this->drupalPost("relation/$relation->rid/delete", array(), t('Delete'));
+    $arg = array(':rid' => $relation->rid);
+    $this->assertFalse((bool) db_query_range('SELECT * FROM {relation} WHERE rid = :rid', 0, 1, $arg)->fetchField(), 'Nothing in relation table after delete.');
+    $this->assertFalse((bool) db_query_range('SELECT * FROM {relation_revision} WHERE rid = :rid', 0, 1, $arg)->fetchField(), 'Nothing in relation revision table after delete.');
+    $skeleton_relation = entity_create_stub_entity('relation', array($relation->rid, $relation->vid, $relation->relation_type));
+    field_attach_load('relation', array($relation->rid => $skeleton_relation));
+    $this->assertIdentical($skeleton_relation->endpoints, array(), t('Field data not present after delete'));
+
+    // Try deleting the content types.
+    $this->drupalGet("admin/structure/relation/manage/$this->relation_type_symmetric/delete");
+    $num_relations = 1;
+    // See relation_type_delete_confirm() in relation_ui.module
+    $this->assertRaw(format_plural($num_relations, 'The %label relation type is used by 1 relation on your site. If you remove this relation type, you will not be able to edit  %label relations and they may not display correctly.', 'The %label relation type is used by @count relations on your site. If you remove %label, you will not be able to edit %label relations and they may not display correctly.', array('%label' => $this->relation_types['symmetric']['label'], '@count' => $num_relations)), 'Correct number of relations found (1) for ' . $this->relation_types['symmetric']['label'] . ' relation type.');
+  }
+
+  /**
+   * Tests importing method.
+   */
+  function testRelationImport() {
+    // Tests navigate to import page and all fields are available.
+    $this->drupalGet('admin/structure/relation');
+    $this->clickLink(t('Import relation type'));
+    $this->assertFieldByName('name');
+    $this->assertFieldByName('relation_type');
+    $this->assertFieldByName('op', t('Import'));
+
+    // Tests import a relation. The relation name is coming from source. So
+    // first imports a simple relation without adding a different name, check
+    // status message and return to the relations listing page to check the
+    // imported relation is available.
+    $post = array(
+      'relation_type' => '
+        $relation_type = new stdClass();
+        $relation_type->disabled = FALSE; /* Edit this to true to make a default relation_type disabled initially */
+        $relation_type->api_version = 1;
+        $relation_type->relation_type = \'is_similar_to\';
+        $relation_type->label = \'is similar to\';
+        $relation_type->reverse_label = \'is similar to\';
+        $relation_type->directional = 0;
+        $relation_type->transitive = 1;
+        $relation_type->r_unique = 1;
+        $relation_type->min_arity = 4;
+        $relation_type->max_arity = 5;
+        $relation_type->source_bundles = array(
+          0 => \'node:*\',
+        );
+        $relation_type->target_bundles = array();
+      ',
+    );
+    $this->drupalPost(NULL, $post, t('Import'));
+    $this->assertText(t('Successfully imported is_similar_to'));
+    $this->drupalGet('admin/structure/relation');
+    $this->assertLink('is similar to', 0, t('The imported relation is exist'));
+
+    // Navaigates to edit page, checks machine name and the imported data. The
+    // imported data contains the following field checks:
+    // - the selected bundle
+    // - directional checkbox
+    // - transivite checkbox
+    // - unique checkbox
+    // - minimum and maximum arity select lists
+    $this->clickLink('is similar to');
+    // Checks the corect url.
+    $this->assertUrl('admin/structure/relation/manage/is_similar_to', array(), t('The imported machine name is correct.'));
+    // Checks that only the correct bundle is selected.
+    $bundle_options = $this->xpath('//select[@id=:id]//option', array(':id' => 'edit-source-bundles'));
+    foreach ($bundle_options as $option) {
+      $this->assertIdentical((string) $option['value'] == 'node:*', isset($option['selected']));
+    }
+    // Checks other datas.
+    $this->assertNoFieldChecked('edit-directional', t('Directional data is imported correct.'));
+    $this->assertFieldChecked('edit-advanced-transitive', t('Transitive data is imported correct.'));
+    $this->assertFieldChecked('edit-advanced-r-unique', t('Unique data is imported correct.'));
+    $this->assertOptionSelected('edit-advanced-min-arity', '4', t('Minimum arity data is imported correct.'));
+    $this->assertOptionSelected('edit-advanced-max-arity', '5', t('Maximum arity data is imported correct.'));
+
+    // Tests validation of duplication import.
+    $post = array(
+      'relation_type' => '
+        $relation_type = new stdClass();
+        $relation_type->disabled = FALSE; /* Edit this to true to make a default relation_type disabled initially */
+        $relation_type->api_version = 1;
+        $relation_type->relation_type = \'is_similar_to\';
+        $relation_type->label = \'is similar to\';
+        $relation_type->reverse_label = \'is similar to\';
+        $relation_type->directional = 0;
+        $relation_type->transitive = 1;
+        $relation_type->r_unique = 1;
+        $relation_type->min_arity = 4;
+        $relation_type->max_arity = 5;
+        $relation_type->source_bundles = array(
+          0 => \'node:*\',
+        );
+        $relation_type->target_bundles = array();
+      ',
+    );
+    $this->drupalPost('admin/structure/relation/import', $post, t('Import'));
+    $this->assertNoText(t('Successfully imported is_similar_to'));
+    $this->assertText(t('A relation type by that name already exists; please choose a different name'));
+
+    // Delete unused relation.
+    relation_type_delete('is_similar_to');
+
+    // Tests importing with overridden machine name. So after imporing check
+    // the status message, check that the imported relation is available and
+    // check the modified machine name.
+    $post = array(
+      'name' => 'overridden_import_test',
+      'relation_type' => '
+        $relation_type = new stdClass();
+        $relation_type->disabled = FALSE; /* Edit this to true to make a default relation_type disabled initially */
+        $relation_type->api_version = 1;
+        $relation_type->relation_type = \'is_similar_to\';
+        $relation_type->label = \'is similar to\';
+        $relation_type->reverse_label = \'is similar to\';
+        $relation_type->directional = 0;
+        $relation_type->transitive = 1;
+        $relation_type->r_unique = 1;
+        $relation_type->min_arity = 4;
+        $relation_type->max_arity = 5;
+        $relation_type->source_bundles = array(
+          0 => \'node:*\',
+        );
+        $relation_type->target_bundles = array();
+      ',
+    );
+    $this->drupalPost('admin/structure/relation/import', $post, t('Import'));
+    $this->assertText(t('Successfully imported overridden_import_test'));
+    $this->drupalGet('admin/structure/relation');
+    $this->assertLink('is similar to', 0, t('The imported relation is exist'));
+    $this->clickLink('is similar to');
+    $this->assertUrl('admin/structure/relation/manage/overridden_import_test', array(), t('The imported machine name is correct.'));
+
+    // Test that relations of imported relation type are accessible from
+    // admin/content
+    $endpoint = array('entity_type' => 'node', 'entity_id' => $this->node1->nid);
+    $relation = relation_create('overridden_import_test', array_fill(0, 5, $endpoint));
+    $rid = relation_save($relation);
+    $this->drupalGet('admin/content/relation');
+    $this->assertLink(t('Relation') . ' ' . $rid, 0, t('Relation of imported type is listed in admin/content'));
+
+    // Delete unused relation.
+    relation_type_delete('overridden_import_test');
+  }
+
+  /**
+   * Tests endpoint field settings.
+   */
+  function testRelationEndpointsField() {
+    $field_label = $this->randomName();
+    $edit = array(
+      'instance[label]' => $field_label,
+    );
+    $this->drupalPost('admin/structure/relation/manage/symmetric/fields/endpoints', $edit, t('Save settings'));
+    $this->assertText(t('Saved @label configuration.', array('@label' => $field_label)));
+
+    $this->drupalGet('admin/structure/relation/manage/symmetric/fields');
+    $this->assertFieldByXPath('//table[@id="field-overview"]//td[1]', $field_label, t('Endpoints field label appears to be changed in the overview table.'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/views/relation.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,376 @@
+<?php
+
+/**
+ * @file
+ * Views support.
+ */
+
+/**
+ * Implements hook_views_data().
+ */
+function relation_views_data() {
+  // Define the base group of this table.
+  $data['relation']['table']['group']  = t('Relation');
+
+  // Advertise this table as a possible base table
+  $data['relation']['table']['base'] = array(
+    'field' => 'rid',
+    'title' => t('Relation'),
+    'weight' => -10,
+  );
+  $data['relation']['table']['entity type'] = 'relation';
+  $data['relation']['rid'] = array(
+    'title' => t('Rid'),
+    'help' => t('The relation ID.'),
+    'field' => array(
+      'handler' => 'views_handler_field_numeric',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+  $data['relation']['relation_type'] = array(
+    'title' => t('Relation type'),
+    'help' => t('The relation type.'),
+    'field' => array(
+      'handler' => 'views_handler_field',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_string',
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_in_operator',
+      'options callback' => 'relation_get_types_options',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+
+  $data['relation']['vid'] = array(
+    'title' => t('Vid'),
+    'help' => t('The relation revision ID.'),
+    'field' => array(
+      'handler' => 'views_handler_field_numeric',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+  $data['relation']['uid'] = array(
+    'title' => t('Uid'),
+    'help' => t('The relation uid.'),
+    'field' => array(
+      'handler' => 'views_handler_field_numeric',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+    'relationship' => array(
+      'label' => 'relation author',
+      'title' => t('Relation Author'),
+      'base' => 'users',
+      'base field' => 'uid',
+    ),
+  );
+
+  $data['relation']['created'] = array(
+    'title' => t('Create Date'),
+    'help' => t('The date when the relation was created.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_date',
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+  $data['relation']['changed'] = array(
+    'title' => t('Change Date'),
+    'help' => t('The date when the relation was last changed.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_date',
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+  $data['relation']['arity'] = array(
+    'title' => t('Number of rows'),
+    'help' => t('The number of rows in this relation.'),
+    'field' => array(
+      'handler' => 'views_handler_field_numeric',
+      'click sortable' => TRUE,
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+      'numeric' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+    ),
+  );
+
+  // View link.
+  $data['relation']['link'] = array(
+    'title' => t('Link'),
+    'help' => t('Provide a simple link to the relation entity.'),
+    'field' => array(
+      'handler' => 'views_handler_field_relation_link',
+      'click sortable' => TRUE,
+      'real field' => 'rid',
+      'additional fields' => array(
+        'rid',
+      ),
+    ),
+  );
+
+  // Edit link.
+  $data['relation']['edit'] = array(
+    'title' => t('Edit link'),
+    'help' => t('Provide a simple link to edit the relation entity.'),
+    'field' => array(
+      'handler' => 'views_handler_field_relation_link_edit',
+      'click sortable' => TRUE,
+      'real field' => 'rid',
+      'additional fields' => array(
+        'rid',
+      ),
+    ),
+  );
+
+  // Delete link.
+  $data['relation']['delete'] = array(
+    'title' => t('Delete link'),
+    'help' => t('Provide a simple link to delete the relation entity.'),
+    'field' => array(
+      'handler' => 'views_handler_field_relation_link_delete',
+      'click sortable' => TRUE,
+      'real field' => 'rid',
+      'additional fields' => array(
+        'rid',
+      ),
+    ),
+  );
+
+  return $data;
+}
+
+
+/**
+ * Implements hook_views_data_alter().
+ */
+function relation_views_data_alter(&$data) {
+  // Find out which entity type has which base table.
+  $entity_infos = entity_get_info();
+  $entity_tables = array();
+  foreach ($entity_infos as $entity_type => $entity_info) {
+    if (isset($entity_info['base table'])) {
+      $entity_tables[$entity_type] = $entity_info['base table'];
+    }
+  }
+  $field = field_info_field('endpoints');
+  $relation_data_table_name = _field_sql_storage_tablename($field);
+  $entity_id_field_name = _field_sql_storage_columnname('endpoints', 'entity_id');
+  $entity_type_field_name = _field_sql_storage_columnname('endpoints', 'entity_type');
+  // Build the relations between the different tables.
+  $types = relation_get_types();
+  foreach ($types as $type => $relation_type) {
+    $target_index = $relation_type->directional ? 'target_bundles' : 'source_bundles';
+    foreach ($relation_type->source_bundles as $source_bundle) {
+      $source_bundle = explode(':', $source_bundle, 2);
+      $entity_type_left = $source_bundle[0];
+      $base_table_left = $entity_tables[$entity_type_left];
+      $t_arguments = array(
+        '@left' => $entity_type_left,
+        '@relation_type_label' => $relation_type->label,
+        '@relation_type_reverse_label' => $relation_type->reverse_label,
+        '@arrow' => $relation_type->directional ? '→' : '↔',
+      );
+      $data[$base_table_left]['relation_base_left_' . $type] = array(
+        'title' => t('Relation: @relation_type_label (@left → relation)', $t_arguments),
+        'help' => t('Provides a relationship from @left to the relation table via the relation @relation_type_label', $t_arguments),
+        'relationship' => array(
+          // relation_handler_relationship::options_form() relies on this check_plain().
+          'label' => check_plain($relation_type->label),
+          'base' => 'relation',
+          'base field' => 'rid',
+          'relationship field' => $entity_infos[$entity_type_left]['entity keys']['id'],
+          'handler' => 'relation_handler_relationship',
+          'relation_type' => $type,
+          'entity_type_left' => $entity_type_left,
+          'directional' => $relation_type->directional,
+        ),
+      );
+      foreach ($relation_type->$target_index as $target_bundle) {
+        $target_bundle = explode(':', $target_bundle, 2);
+        $entity_type_right = $target_bundle[0];
+        $base_table_right = $entity_tables[$entity_type_right];
+        $t_arguments['@right'] = $entity_type_right;
+        // Provide forward relationships
+        $data[$base_table_left]['relation_' . $type . '_' . $entity_type_right] = array(
+          'title' => t('Relation: @relation_type_label (@left @arrow @right)', $t_arguments),
+          'help' => t('Provides a relationship from @left to @right via the relation @relation_type_label', $t_arguments),
+          'relationship' => array(
+            // relation_handler_relationship::options_form() relies on this check_plain().
+            'label' => check_plain($relation_type->label),
+            'base' => $base_table_right,
+            'base field' => $entity_infos[$entity_type_right]['entity keys']['id'],
+            'relationship field' => $entity_infos[$entity_type_left]['entity keys']['id'],
+            'handler' => 'relation_handler_relationship',
+            'relation_type' => $type,
+            'entity_type_left' => $entity_type_left,
+            'entity_type_right' => $entity_type_right,
+            'directional' => $relation_type->directional,
+          ),
+        );
+        $data['relation']['relation_base_' . $type . '_' . $entity_type_right] = array(
+          'title' => t('Relation: @relation_type_label (relation → @right)', $t_arguments),
+          'help' => t('Provides a relationship from the relation table to @right via the relation @relation_type_label', $t_arguments),
+          'relationship' => array(
+            // relation_handler_relationship::options_form() relies on this check_plain().
+            'label' => check_plain($relation_type->label),
+            'base' => $base_table_right,
+            'base field' => $entity_infos[$entity_type_right]['entity keys']['id'],
+            'relationship field' => 'rid',
+            'handler' => 'relation_handler_relationship',
+            'relation_type' => $type,
+            'entity_type_right' => $entity_type_right,
+            'directional' => $relation_type->directional,
+          ),
+        );
+        // Provide reverse relationships
+        if ($entity_type_right != $entity_type_left) {
+          $data[$base_table_right]['relation_' . $type . '_' . $entity_type_left] = array(
+            'title' => t('Relation: @relation_type_reverse_label (@right @arrow @left)', $t_arguments),
+            'help' => t('Provides a relationship from @right to @left via the relation @relation_type_reverse_label', $t_arguments),
+            'relationship' => array(
+              // relation_handler_relationship::options_form() relies on this check_plain().
+              'label' => check_plain($relation_type->reverse_label),
+              'base' => $base_table_left,
+              'base field' => $entity_infos[$entity_type_left]['entity keys']['id'],
+              'relationship field' => $entity_infos[$entity_type_right]['entity keys']['id'],
+              'handler' => 'relation_handler_relationship',
+              'relation_type' => $type,
+              'entity_type_left' => $entity_type_right,
+              'entity_type_right' => $entity_type_left,
+              'directional' => $relation_type->directional,
+            ),
+          );
+          $data[$base_table_right]['relation_base_right_' . $type] = array(
+            'title' => t('Relation: @relation_type_reverse_label (@right → relation)', $t_arguments),
+            'help' => t('Provides a relationship from @right to the relation table via the relation @relation_type_reverse_label. Usually only needed to access the fields of the relation itself.', $t_arguments),
+            'relationship' => array(
+              // relation_handler_relationship::options_form() relies on this check_plain().
+              'label' => check_plain($relation_type->reverse_label),
+              'base' => 'relation',
+              'base field' => 'rid',
+              'relationship field' => $entity_infos[$entity_type_right]['entity keys']['id'],
+              'handler' => 'relation_handler_relationship',
+              'relation_type' => $type,
+              'entity_type_right' => $entity_type_right,
+              'directional' => $relation_type->directional,
+            ),
+          );
+          $data['relation']['relation_base_' . $type . '_' . $entity_type_left] = array(
+            'title' => t('Relation: @relation_type_reverse_label (relation → @left)', $t_arguments),
+            'help' => t('Provides a relationship from the relation table to @left via the relation @relation_type_reverse_label', $t_arguments),
+            'relationship' => array(
+              // relation_handler_relationship::options_form() relies on this check_plain().
+              'label' => check_plain($relation_type->reverse_label),
+              'base' => $base_table_left,
+              'base field' => $entity_infos[$entity_type_left]['entity keys']['id'],
+              'relationship field' => 'rid',
+              'handler' => 'relation_handler_relationship',
+              'relation_type' => $type,
+              'entity_type_left' => $entity_type_left,
+              'directional' => $relation_type->directional,
+            ),
+          );
+
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_form_views_ui_add_item_form_alter().
+ */
+function relation_form_views_ui_add_item_form_alter(&$form, $form_state) {
+  if ($form_state['type'] == 'relationship' && $form_state['view']->base_table != 'relation') {
+    foreach (relation_get_types() as $relation_type) {
+      foreach (array('source_bundles', 'target_bundles') as $endpoint_bundles) {
+        foreach ($relation_type->$endpoint_bundles as $relation_bundle) {
+          if (substr($relation_bundle, 0, 9) == 'relation:') {
+            return;
+          }
+        }
+      }
+    }
+    // Collect the relation types already added as a relationship.
+    $preg_pieces = array();
+    foreach ($form_state['view']->display_handler->get_handlers('relationship') as $relationship) {
+      if (get_class($relationship) == 'relation_handler_relationship') {
+        $preg_pieces[] = '^relation\.relation_base_' . $relationship->definition['relation_type'];
+      }
+    }
+    if ($preg_pieces) {
+      // Filter out impossible Views relationships.
+      $relation_type_preg = '/' . implode('|', array_unique($preg_pieces)) .'/';
+      foreach (element_children($form['options']['name']) as $name) {
+        if (substr($name, 0, 9) == 'relation.' && !preg_match($relation_type_preg, $name)) {
+          $form['options']['name'][$name]['#access'] = FALSE;
+        }
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/views/relation.views_default.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Relation default views.
+ */
+
+/**
+ * Relation's default views.
+ */
+function relation_views_default_views() {
+  $views = array();
+
+  $view = new view;
+  $view->name = 'relations';
+  $view->description = 'Lists relations of a certain type';
+  $view->tag = 'default';
+  $view->base_table = 'relation';
+  $view->human_name = 'Relations';
+  $view->core = 7;
+  $view->api_version = '3.0';
+  $view->disabled = TRUE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Master */
+  $handler = $view->new_display('default', 'Master', 'default');
+  $handler->display->display_options['title'] = 'Relations';
+  $handler->display->display_options['access']['type'] = 'none';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['query']['options']['query_comment'] = FALSE;
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '10';
+  $handler->display->display_options['style_plugin'] = 'default';
+  $handler->display->display_options['style_options']['group_rendered'] = 1;
+  $handler->display->display_options['row_plugin'] = 'fields';
+  /* Field: Relation: endpoints */
+  $handler->display->display_options['fields']['endpoints']['id'] = 'endpoints';
+  $handler->display->display_options['fields']['endpoints']['table'] = 'field_data_endpoints';
+  $handler->display->display_options['fields']['endpoints']['field'] = 'endpoints';
+  $handler->display->display_options['fields']['endpoints']['label'] = '';
+  $handler->display->display_options['fields']['endpoints']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['external'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['replace_spaces'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['trim_whitespace'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['nl2br'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['endpoints']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['endpoints']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['endpoints']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['endpoints']['element_label_colon'] = FALSE;
+  $handler->display->display_options['fields']['endpoints']['element_default_classes'] = 1;
+  $handler->display->display_options['fields']['endpoints']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['endpoints']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['endpoints']['hide_alter_empty'] = 0;
+  $handler->display->display_options['fields']['endpoints']['click_sort_column'] = 'entity_type';
+  $handler->display->display_options['fields']['endpoints']['group_rows'] = 1;
+  $handler->display->display_options['fields']['endpoints']['delta_offset'] = '0';
+  $handler->display->display_options['fields']['endpoints']['delta_reversed'] = 0;
+  $handler->display->display_options['fields']['endpoints']['delta_first_last'] = 0;
+  $handler->display->display_options['fields']['endpoints']['field_api_classes'] = 0;
+  /* Contextual filter: Relation: Relation type */
+  $handler->display->display_options['arguments']['relation_type']['id'] = 'relation_type';
+  $handler->display->display_options['arguments']['relation_type']['table'] = 'relation';
+  $handler->display->display_options['arguments']['relation_type']['field'] = 'relation_type';
+  $handler->display->display_options['arguments']['relation_type']['default_action'] = 'summary';
+  $handler->display->display_options['arguments']['relation_type']['default_argument_type'] = 'fixed';
+  $handler->display->display_options['arguments']['relation_type']['default_argument_skip_url'] = 0;
+  $handler->display->display_options['arguments']['relation_type']['summary']['number_of_records'] = '0';
+  $handler->display->display_options['arguments']['relation_type']['summary']['format'] = 'default_summary';
+  $handler->display->display_options['arguments']['relation_type']['summary_options']['items_per_page'] = '25';
+  $handler->display->display_options['arguments']['relation_type']['glossary'] = 0;
+  $handler->display->display_options['arguments']['relation_type']['limit'] = '0';
+  $handler->display->display_options['arguments']['relation_type']['transform_dash'] = 0;
+  $handler->display->display_options['arguments']['relation_type']['break_phrase'] = 0;
+
+  /* Display: Page */
+  $handler = $view->new_display('page', 'Page', 'page');
+  $handler->display->display_options['path'] = 'relations';
+  $views['relations'] = $view;
+
+  return $views;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/views/relation_handler_relationship.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * @file
+ * Views relationship support.
+ */
+
+class relation_handler_relationship extends views_handler_relationship {
+  /**
+   * Define r_index option.
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['r_index'] = array('default' => -1);
+    $options['entity_deduplication_left'] = array('default' => FALSE);
+    $options['entity_deduplication_right'] = array('default' => FALSE);
+    return $options;
+  }
+
+  /**
+   * Let the user choose r_index.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Check if this relation is entity-to-entity or entity-to-relation / relation-to-entity.
+    $endpoints_twice = isset($this->definition['entity_type_left']) && isset($this->definition['entity_type_right']);
+
+    if ($this->definition['directional']) {
+      $form['r_index'] = array(
+        '#type' => 'select',
+        '#options' => array(
+          -1 => t('Any'),
+          0 => t('Source'),
+          1 => t('Target'),
+        ),
+        '#title' => t('Position of the relationship base'),
+        '#default_value' => $this->options['r_index'],
+        // check_plain()'d in the definition.
+        '#description' => t('Select whether the entity you are adding the relationship to is source or target of !relation_type_label relation.', array('!relation_type_label' => $this->definition['label'])),
+      );
+    }
+    foreach (array('left', 'right') as $key) {
+      if (isset($this->definition['entity_type_' . $key])) {
+        $form['entity_deduplication_' . $key] = array(
+          '#type' => 'checkbox',
+          '#title' => $endpoints_twice ?
+            t('Avoid @direction @type duplication', array('@direction' => t($key), '@type' => $this->definition['entity_type_' . $key])) :
+            t('Avoid @type duplication', array('@type' => $this->definition['entity_type_' . $key])),
+          '#default_value' => $this->options['entity_deduplication_' . $key],
+          '#description' => t('When creating a chain of Views relationships for example from node to relation and then from relation to node (both via the same relation type) then each node will display on both ends. Check this option to avoid this kind of duplication.'),
+        );
+      }
+    }
+  }
+
+  function query() {
+    $field = field_info_field('endpoints');
+    $relation_data_table_name = _field_sql_storage_tablename($field);
+    $entity_id_field_name = _field_sql_storage_columnname('endpoints', 'entity_id');
+    $entity_type_field_name = _field_sql_storage_columnname('endpoints', 'entity_type');
+    $r_index_field_name = _field_sql_storage_columnname('endpoints', 'r_index');
+    $join_type = empty($this->options['required']) ? 'LEFT' : 'INNER';
+    $endpoints_twice = isset($this->definition['entity_type_left']) && isset($this->definition['entity_type_right']);
+
+    $this->ensure_my_table();
+    // Join the left table with the entity type to the endpoints field data table.
+    $join = new views_join();
+    $join->definition = array(
+      'left_table' => $this->table_alias,
+      'left_field' => $this->real_field,
+      'table'      => $relation_data_table_name,
+      'type'       => $join_type,
+      'extra'      => array(
+        array(
+          'field' => 'bundle',
+          'value' => $this->definition['relation_type'],
+        ),
+      ),
+    );
+    if (isset($this->definition['entity_type_left'])) {
+      // The left table is an entity, not a relation.
+      $join->definition['field'] = $entity_id_field_name;
+      $this->ensure_no_duplicate_entities($join->definition['extra'], $this->options['entity_deduplication_left'], $this->definition['relation_type'], $this->definition['entity_type_left'], $this->table_alias, $this->real_field);
+      $join->definition['extra'][] = array(
+        'field' => $entity_type_field_name,
+        'value' => $this->definition['entity_type_left'],
+      );
+    }
+    else {
+      // The left table is relation.
+      $join->definition['field'] = 'entity_id';
+    }
+    if ($this->definition['directional'] && $this->options['r_index'] > -1) {
+      $join->definition['extra'][] = array(
+        'field' => $r_index_field_name,
+        'value' => $this->options['r_index'],
+      );
+    }
+    $join->construct();
+    $join->adjusted = TRUE;
+    $l = $this->query->add_table($relation_data_table_name, $this->relationship, $join);
+
+    if ($endpoints_twice) {
+      // Execute a self-join.
+      $join = new views_join();
+      $join->definition = array(
+        'left_table' => $l,
+        'left_field' => 'entity_id',
+        'table'      => $relation_data_table_name,
+        'field'      => 'entity_id',
+        'type'       => $join_type,
+        'extra'      => array(
+          array(
+            'field' => $entity_type_field_name,
+            'value' => $this->definition['entity_type_right'],
+          ),
+        ),
+      );
+
+      if ($this->definition['entity_type_left'] == $this->definition['entity_type_right']) {
+        $join->definition['extra'][] = array(
+          // This definition is a bit funny but there's no other way to tell
+          // Views to use an expression in join extra as it is.
+          'field' => $r_index_field_name . ' !=  ' . $l . '.' . $r_index_field_name . ' AND 1',
+          'value' => 1,
+        );
+      }
+
+      $join->construct();
+      $join->adjusted = TRUE;
+      $r = $this->query->add_table($relation_data_table_name, $this->relationship, $join);
+    }
+    else {
+      $r = $l;
+    }
+    $join = new views_join();
+    $join->definition = array(
+      'left_table' => $r,
+      'table'      => $this->definition['base'],
+      'field'      => $this->definition['base field'],
+      'type'       => $join_type,
+    );
+    if (isset($this->definition['entity_type_right'])) {
+      // We are finishing on an entity table.
+      $join->definition['left_field'] = $entity_id_field_name;
+      $this->ensure_no_duplicate_entities($join->definition['extra'], $this->options['entity_deduplication_right'], $this->definition['relation_type'], $this->definition['entity_type_right'], $r, $entity_id_field_name);
+      $join->definition['extra'][] = array(
+        'table' => $r,
+        'field' => $entity_type_field_name,
+        'value' => $this->definition['entity_type_right'],
+      );
+    }
+    else {
+      // We are finishing on relation.
+      $join->definition['left_field'] = 'entity_id';
+    }
+
+    $join->construct();
+    $join->adjusted = TRUE;
+    // use a short alias for this:
+    $alias = $this->definition['base'] . '_' . $this->table;
+    $this->alias = $this->query->add_relationship($alias, $join, $this->definition['base'], $this->relationship);
+  }
+
+  protected function ensure_no_duplicate_entities(&$extra, $check, $relation_type, $entity_type, $table, $field) {
+    if ($check && isset($this->view->relation_entity_tables[$entity_type][$relation_type])) {
+      foreach ($this->view->relation_entity_tables[$entity_type][$relation_type] as $expression) {
+        $extra[] = array(
+          'table' => NULL,
+          'field' => "$expression != $table.$field AND 1",
+          'value' => 1,
+        );
+      }
+    }
+    $this->view->relation_entity_tables[$entity_type][$relation_type][] = "$table.$field";
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/views/views_handler_field_relation_link.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * @file
+ * Definition of views_handler_field_relation_link.
+ */
+
+/**
+ * Field handler to present a link to the relation.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_relation_link extends views_handler_field_entity {
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['text'] = array('default' => '', 'translatable' => TRUE);
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    $form['text'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Text to display'),
+      '#default_value' => $this->options['text'],
+    );
+    parent::options_form($form, $form_state);
+
+    // The path is set by render_link function so don't allow to set it.
+    $form['alter']['path'] = array('#access' => FALSE);
+    $form['alter']['external'] = array('#access' => FALSE);
+  }
+
+  function render($values) {
+    if ($entity = $this->get_value($values)) {
+      return $this->render_link($entity, $values);
+    }
+  }
+
+  function render_link($relation, $values) {
+    if (user_access('view relations')) {
+      $this->options['alter']['make_link'] = TRUE;
+      $this->options['alter']['path'] = "relation/$relation->rid";
+      $text = !empty($this->options['text']) ? $this->options['text'] : t('View');
+      return $text;
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/views/views_handler_field_relation_link_delete.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Definition of views_handler_field_relation_link_delete.
+ */
+
+/**
+ * Field handler to present a link to delete a relation.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_relation_link_delete extends views_handler_field_relation_link {
+
+  /**
+   * Renders the link.
+   */
+  function render_link($relation, $values) {
+    // Ensure user has access to delete this relation.
+    if (!user_access('delete relations')) {
+      return;
+    }
+
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = "relation/$relation->rid/delete";
+    $this->options['alter']['query'] = drupal_get_destination();
+
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('Delete');
+    return $text;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/relation/views/views_handler_field_relation_link_edit.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * @file
+ * Definition of views_handler_field_relation_link_edit.
+ */
+
+/**
+ * Field handler to present a link relation edit.
+ *
+ * @ingroup views_field_handlers
+ */
+class views_handler_field_relation_link_edit extends views_handler_field_relation_link {
+
+  /**
+   * Renders the link.
+   */
+  function render_link($relation, $values) {
+    // Ensure user has access to edit this relation.
+    if (!user_access('edit relations')) {
+      return;
+    }
+
+    $this->options['alter']['make_link'] = TRUE;
+    $this->options['alter']['path'] = "relation/$relation->rid/edit";
+    $this->options['alter']['query'] = drupal_get_destination();
+
+    $text = !empty($this->options['text']) ? $this->options['text'] : t('Edit');
+    return $text;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,169 @@
+
+--------------------------------------------------------------------------------
+                 RESTful Web Services for Drupal (restws)
+--------------------------------------------------------------------------------
+
+Maintainers:
+ * Wolfgang Ziegler (fago), wolfgang.ziegler@epiqo.com
+ * Klaus Purer (klausi), klaus.purer@epiqo.com
+
+Exposes Drupal resources (e.g. entities) as RESTful web services. The module
+makes use of the Entity API and the information about entity properties
+(provided via hook_entity_property_info()) to provide resource representations.
+It aims to be fully compliant to the REST principles.
+
+Installation
+------------
+
+ * Copy the whole restws directory to your modules directory
+   (e.g. DRUPAL_ROOT/sites/all/modules) and activate the RESTful Web Services
+   module.
+ * There is no user interface or such needed.
+
+Usage / Testing
+---------------
+
+ * To obtain the JSON representation of an entity use your browser to visit
+
+   http://example.com/node/1.json or
+   http://example.com/user/1.json or
+   http://example.com/<entity type name>/<entity id>.json
+
+   for an example.
+   
+ * In order to access entities via this interface, permissions must be granted
+   for the desired operation (e.g. "access content" or "create content" for
+   nodes). Additionally each resource is protected with a RESTWS permission
+   that can be configured at "admin/people/permissions#module-restws".
+
+ * Some example outputs are given in the example_exports folder.
+
+
+Design goals and concept
+------------------------
+
+ * Create a module that simply exposes Drupal's data (e.g. entities) as web
+   resources, thus creating a simple RESTful web service. It aims to be fully
+   compliant to the REST principles.
+
+ * The module is strictly resource-oriented. No support for message-oriented or
+   RPC-style web services.
+
+ * Plain and simple. No need for endpoint configuration, all resources are
+   available on the same path pattern. Access via HTTP only.
+
+ * When the module is enabled all entities should be available at the URL path
+   /<entity type name>/<entity id>, e.g. /node/123, /user/1 or /profile/789.
+
+ * Resources are represented and exchanged in different formats, e.g. JSON or
+   XML. The format has to be specified in every request.
+   
+ * The module defines resource for all entity types supported by the entity API
+   as well as a JSON format. Modules may provide further resources and formats
+   via hooks.
+
+ * The module supports full CRUD (Create, Read, Update, Delete) for resources:
+ 
+     * Create: HTTP POST /<entity type name> (requires HTTP Content-Type header
+       set to the MIME type of <format>)
+
+     * Read: HTTP GET /<entity type name>/<entity id>.<format>
+
+     * Update: HTTP PUT /<entity type name>/<entity id>.<format>
+       or      HTTP PUT /<entity type name>/<entity id> (requires HTTP
+       Content-Type header set to the MIME type of the posted format)
+
+     * Delete: HTTP DELETE /<entity type name>/<entity id>
+
+      Note: if you use cookie-based authentication then you also need to set the
+      HTTP X-CSRF-Token header on all writing requests (POST, PUT and DELETE).
+      You can retrieve the token from /restws/session/token with a standard HTTP
+      GET request.
+
+ * The representation <format> can be json, xml etc.
+
+ * The usual Drupal permission system is respected, thus permissions are checked
+   for the logged in user account of the received requests. 
+
+ * Authentication can be achieved via separate modules, maybe making use of the
+   standard Drupal cookie and session handling. The module comes with an
+   optional HTTP Basic Authentication module (restws_auth_basic) that performs
+   a user login with the credentials provided via the usual HTTP headers.
+
+Querying
+--------
+The module also supports querying for resources:
+
+  Query: HTTP GET /<entity type name>.<format>?<filter>=<value1>&
+  <meta_control>=<value2>
+
+By default RestWS simply outputs all resources available for the given type:
+
+/user.json
+
+The example above will output a JSON object containing up to 100 users
+available in an sub object called list. The XML output will simply create
+tags with the given type in parent type, which also is called list. The hard
+limit of 100 resources per request ensures that the database and webserver
+won't overload. The hard limit is defined by the system variable
+restws_query_max_limit, which can be overridden if necessary.
+
+You can filter for certain resources by passing parameters in the URL. These
+parameters consist of properties of the resource and a value for that property.
+The value of a property is always the schema field of it. So if you want to
+filter for an author, the value of the filter has to be the uid. If you want to
+filter for nodes with a certain term, then you have to use the tid of that term.
+You can only specify one value, so filtering for more than one tag, is currently
+not supported.
+
+/node.json?type=article&field_tags=17&author=1
+
+By default the first field column will be used for the query. If you want
+another column, you can specify it in square brackets.
+
+/node.json?body[format]=filtered_html
+
+If a certain property isn't valid an HTTP status code 412 will be returned
+containing an error message.
+
+Meta Controls
+-------------
+
+Additionally to the filters RestWS also supports meta controls, which allow you
+to control your output. Currently only sort and direction are supported.
+This two meta controls allow you to sort your output by a specific property of
+your resource for a certain direction. By default the direction will be
+ascending but if want to sort your output descending you have to use the keyword
+DESC for the meta control direction.
+
+/taxonomy_term.json?sort=tid&direction=DESC
+
+You can limit the results with the meta control limit which is by default 100.
+To navigate through the generated pages, you have to use meta control page.
+
+/node.json?limit=10&page=3
+
+The output always has a self, a first and a last element, which contain a link
+to the current, first and last page. If your current page isn't the last or the
+first one, RestWS will also generate prev and next links. For xml they can be
+found in the tags <link /> in the first hierarchy.
+
+Sometimes it might be helpful to retrieve only the references to resources of a
+query. You can tell RestWS to output them by setting the meta control full to 0,
+by default it will be 1 and output the whole resources.
+
+/node.json?full=0
+
+If one of your resource properties collides with one of RestWS meta control
+keywords, you have prefix it with property_, when specifying it as filter.
+
+Debugging
+---------
+
+You can enable a debug logging facility by setting a variable in settings.php
+(e.g. in DRUPAL_ROOT/sites/default/settings.php):
+
+$conf['restws_debug_log'] = DRUPAL_ROOT . '/restws_debug.log';
+
+It will write the details of every web service request to the file you have
+specified, e.g. to DRUPAL_ROOT/restws_debug.log.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/example_exports/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,38 @@
+
+--------------------------------------------------------------------------------
+                 RESTful Web Services for Drupal (restws)
+--------------------------------------------------------------------------------
+
+Example Exports
+---------------
+This folder contains some example outputs of RestWS. Note that the output
+depends on the permissions and the field access of the viewing user. Nodes and
+users are used as examples here, but the structure is the same for all entity
+types.
+
+Here is a list of the outputs with the URL paths:
+
+- Retrieve a node
+
+  /node/1.json
+  node.1.json
+
+  /node/1.xml
+  node.1.xml
+
+- Get a list of nodes with a limit of 3 nodes per page and display the second
+  page (the first is page=0).
+
+  /node.json?limit=3&page=1
+  node.json
+
+  /node.xml?limit=3&page=1
+  node.xml
+
+- Retrieve a user
+
+  /user.json
+  user.1.json
+
+  /user.xml
+  user.1.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/example_exports/node.1.json	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,45 @@
+{
+  "body":{
+    "value":"Aptent bene capto euismod facilisi olim praemitto. Adipiscing esca paulatim tamen tincidunt utrum. Abbas consectetuer eu ibidem imputo luctus ludus nisl. Ad huic oppeto saepius singularis turpis valde. Fere ille magna nostrud premo. Caecus dolore te ulciscor. Ex iustum ludus meus. Dolore hos importunus paratus praemitto venio.\n\nAcsi obruo occuro quia. Erat genitus ibidem ideo pertineo zelus. Cogo dolor ille probo suscipere typicus usitas vel velit. Appellatio commodo nunc.\n\n",
+    "summary":"",
+    "format":"php_code"
+  },
+  "field_tags":[
+    {
+      "uri":"http:\/\/drupal-7dev.localhost\/taxonomy_term\/18",
+      "id":"18",
+      "resource":"taxonomy_term"
+    }
+  ],
+  "field_image":{
+    "file":{
+      "uri":"http:\/\/drupal-7dev.localhost\/file\/23",
+      "id":"23",
+      "resource":"file"
+    },
+    "alt":"Huic similis tego ullamcorper wisi."
+  },
+  "nid":"1",
+  "vid":"1",
+  "is_new":false,
+  "type":"article",
+  "title":"Autem Commoveo Ludus Quadrum",
+  "language":"und",
+  "url":"http:\/\/drupal-7dev.localhost\/node\/89",
+  "edit_url":"http:\/\/drupal-7dev.localhost\/node\/89\/edit",
+  "status":"1",
+  "promote":"1",
+  "sticky":"0",
+  "created":"1342808903",
+  "changed":"1343130463",
+  "author":{
+    "uri":"http:\/\/drupal-7dev.localhost\/user\/1",
+    "id":"1",
+    "resource":"user"
+  },
+  "log":"",
+  "revision":null,
+  "comment":"2",
+  "comment_count":"0",
+  "comment_count_new":"0"
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/example_exports/node.1.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<node>
+    <body>
+        <value>Aptent bene capto euismod facilisi olim praemitto. Adipiscing esca paulatim tamen tincidunt utrum. Abbas consectetuer eu ibidem imputo luctus ludus nisl. Ad huic oppeto saepius singularis turpis valde. Fere ille magna nostrud premo. Caecus dolore te ulciscor. Ex iustum ludus meus. Dolore hos importunus paratus praemitto venio.
+
+            Acsi obruo occuro quia. Erat genitus ibidem ideo pertineo zelus. Cogo dolor ille probo suscipere typicus usitas vel velit. Appellatio commodo nunc.
+
+        </value>
+        <summary></summary>
+        <format>php_code</format>
+    </body>
+    <field_tags>
+        <item resource="taxonomy_term" id="18">http://drupal-7dev.localhost/taxonomy_term/18</item>
+    </field_tags>
+    <field_image>
+        <file resource="file" id="23">http://drupal-7dev.localhost/file/23</file>
+        <alt>Huic similis tego ullamcorper wisi.</alt>
+    </field_image>
+    <nid>1</nid>
+    <vid>1</vid>
+    <is_new></is_new>
+    <type>article</type>
+    <title>Autem Commoveo Ludus Quadrum</title>
+    <language>und</language>
+    <url>http://drupal-7dev.localhost/node/89</url>
+    <edit_url>http://drupal-7dev.localhost/node/89/edit</edit_url>
+    <status>1</status>
+    <promote>1</promote>
+    <sticky>0</sticky>
+    <created>1342808903</created>
+    <changed>1343130463</changed>
+    <author resource="user" id="1">http://drupal-7dev.localhost/user/1</author>
+    <log></log>
+    <comment>2</comment>
+    <comment_count>0</comment_count>
+    <comment_count_new>0</comment_count_new>
+</node>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/example_exports/node.json	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,150 @@
+{
+  "self":"http://drupal-7dev.localhost/node?limit=3&page=1",
+  "first":"http://drupal-7dev.localhost/node?limit=3&page=0",
+  "last":"http://drupal-7dev.localhost/node?limit=3&page=2",
+  "prev":"http://drupal-7dev.localhost/node?limit=3&page=0",
+  "next":"http://drupal-7dev.localhost/node?limit=3&page=2",
+  "list":[
+    {
+      "body":{
+        "value":"<p>Euismod incassum mauris praesent refoveo tincidunt torqueo turpis uxor. Causa diam dolor elit iriure turpis vereor. Distineo melior vero. Accumsan gemino ille immitto persto usitas. Ad blandit olim probo vicis. Caecus exerci lucidus persto quae si. Causa eu exputo iaceo iustum jus tamen ut. Augue eum ibidem lenis natu olim si tum vero.</p>\n<p>At elit eum facilisis in. Et eu paulatim scisco secundum. Accumsan eros nobis quidem.</p>\n<p>Nutus quadrum rusticus sudo velit. Esca si turpis. Eros ex fere gravis ideo metuo nostrud. At ulciscor voco. Brevitas letalis ludus meus nobis paratus singularis utinam verto.</p>\n<p>Haero macto saluto. Eros facilisis macto neque. Abluo haero si. Abluo enim gilvus humo ideo in quia refoveo. Gilvus hendrerit imputo jumentum loquor occuro pala. Abdo minim paratus saluto. Esca hos incassum iustum similis validus. Abbas camur feugiat obruo valde vero. Inhibeo nulla vero ymo. Abbas autem caecus dolore hendrerit iriure premo si tation volutpat. Conventio cui dolore erat paulatim premo typicus venio vindico.</p>\n<p>Consectetuer facilisis feugiat iriure jumentum jus paratus quis. Abbas gemino hendrerit nutus oppeto zelus. Abluo bene capto commodo duis jumentum quia secundum singularis vereor. Consectetuer imputo neque pertineo premo virtus vulpes. Cogo comis consequat defui fere occuro persto. Brevitas dolore euismod interdico macto neque patria saepius tamen.</p>\n<p>Appellatio augue causa pala premo quidne refoveo sino utrum venio. Amet consectetuer damnum eu ex ibidem quadrum. Appellatio letalis patria qui voco. Exerci meus modo sino. Abbas elit hendrerit loquor nostrud occuro populus qui torqueo.</p>\n<p>Consequat ea iaceo ille pneum saepius tamen. Capto dolore gilvus jumentum molior paulatim probo quidem sudo. Meus minim mos pagus sed zelus. Abigo autem brevitas commoveo conventio erat hendrerit iustum mos neque.</p>\n",
+        "summary":"",
+        "format":"filtered_html"
+      },
+      "field_tags":[
+        {
+          "uri":"http://drupal-7dev.localhost/taxonomy_term/1",
+          "id":"1",
+          "resource":"taxonomy_term"
+        }
+      ],
+      "field_image":{
+        "file":{
+          "uri":"http://drupal-7dev.localhost/file/25",
+          "id":"25",
+          "resource":"file"
+        },
+        "alt":"Abdo camur gilvus macto praesent probo turpis."
+      },
+      "nid":"91",
+      "vid":"92",
+      "is_new":false,
+      "type":"article",
+      "title":"Abbas Dolor",
+      "language":"und",
+      "url":"http://drupal-7dev.localhost/node/91",
+      "edit_url":"http://drupal-7dev.localhost/node/91/edit",
+      "status":"1",
+      "promote":"1",
+      "sticky":"0",
+      "created":"1342746489",
+      "changed":"1343130431",
+      "author":{
+        "uri":"http://drupal-7dev.localhost/user/5",
+        "id":"5",
+        "resource":"user"
+      },
+      "log":"",
+      "revision":null,
+      "comment":"2",
+      "comment_count":"0",
+      "comment_count_new":"0"
+    },
+    {
+      "body":{
+        "value":"Capto damnum diam eros eum ludus quidne roto vero. Ad augue bene decet importunus quae qui vereor.\n\nAdipiscing brevitas consectetuer exerci gemino refero vereor. Caecus ideo nutus sed. Abluo amet autem elit humo jumentum premo quis sit virtus. Melior obruo roto saepius sed vicis vulputate. Commodo eu lobortis lucidus paratus praesent proprius quis secundum tincidunt. Brevitas caecus erat euismod hendrerit incassum nostrud persto sit vereor.\n\nElit meus neque pala. Accumsan brevitas damnum diam enim gravis praemitto secundum similis uxor. Mauris os usitas ymo. Facilisi iriure nibh nobis veniam. Augue erat exputo praesent quidne sed velit vulpes.\n\nConsequat euismod molior os pagus probo roto sit. Jugis lenis letalis quia. Amet camur huic laoreet nunc os persto proprius vero vulputate. Consequat oppeto paratus tamen vindico. Enim facilisis ille luptatum mauris nulla occuro saepius scisco ymo. Accumsan conventio dolus enim eu melior neque. Blandit gemino incassum iriure nulla pala pertineo quia utinam vulpes. Ad adipiscing magna odio persto quae refero ut voco.\n\nAutem damnum hendrerit lucidus pertineo voco. At commodo eligo gilvus in incassum quis validus. Caecus cui jus laoreet minim tation vero ymo. In luptatum zelus. Caecus duis haero meus paulatim sed typicus velit.\n\nAbluo eros et eu letalis natu quae vero. Exputo haero iusto lenis mos vereor wisi. Ille incassum jus probo ullamcorper validus veniam. Capto illum imputo lucidus occuro olim qui quidem utinam. Abbas facilisi imputo incassum nulla sudo utinam valde vereor. Bene facilisi ille. Humo importunus meus obruo. Abdo amet eum ex haero melior nutus persto qui tego.\n\nAbico acsi defui eligo eros iriure nimis praesent probo. Decet gemino magna nisl patria persto sino tamen verto zelus. Aliquam distineo ex hendrerit loquor. Autem ea exputo importunus persto pneum vulpes. Appellatio blandit hendrerit incassum nisl quia refoveo torqueo. Acsi elit metuo occuro praesent scisco ulciscor ut velit.\n\nAbluo blandit macto magna mauris metuo pecus plaga ullamcorper vindico. Loquor minim sudo. Humo jus modo nutus veniam. Dignissim enim euismod quibus. Adipiscing ea luctus quidem uxor. Blandit ex exputo haero iusto praesent sagaciter scisco veniam. Blandit brevitas duis elit hendrerit importunus ratis torqueo vero vindico.\n\nAppellatio decet facilisi magna oppeto praemitto ullamcorper virtus. Caecus ibidem nisl nobis obruo velit volutpat ymo. Eros facilisis gemino jus nunc praemitto verto virtus voco zelus. Abigo pala velit. Augue cui diam exerci praesent singularis. Abluo aliquam enim inhibeo iriure meus qui veniam.\n\nExputo oppeto pecus pneum. Et gemino jumentum lucidus nutus persto secundum tincidunt torqueo valetudo. Bene dolor erat ex quidem virtus vulputate ymo. Aptent capto macto ratis roto utrum. Causa dolor eu ex paulatim quia usitas.\n\nAbdo adipiscing gilvus ibidem turpis vulputate. Ad cui incassum sed singularis. Cui damnum eum luctus oppeto persto ullamcorper velit vero virtus. Caecus duis ibidem minim tincidunt. Aliquam augue bene cogo defui jumentum proprius qui ut utinam. Abdo amet esca jugis molior nobis. Abbas abico consectetuer genitus iustum lobortis praemitto quibus ratis saluto. Autem laoreet metuo nimis oppeto similis tego.\n\nAdipiscing dolore eros gravis lenis. Acsi autem gemino immitto nunc. Commoveo exputo fere huic iustum lenis loquor magna minim sagaciter. Dolore hendrerit incassum refoveo sit tego tincidunt venio vero vulputate. Abluo acsi at eu magna quadrum sino sudo utrum. Abdo antehabeo conventio jus neo sino. Abluo aliquam amet ibidem valde zelus. Commoveo exerci facilisis olim proprius sino ymo. Adipiscing blandit capto defui diam euismod huic neo tincidunt.\n\n",
+        "summary":"",
+        "format":"php_code"
+      },
+      "field_tags":[
+        {
+          "uri":"http://drupal-7dev.localhost/taxonomy_term/17",
+          "id":"17",
+          "resource":"taxonomy_term"
+        },
+        {
+          "uri":"http://drupal-7dev.localhost/taxonomy_term/17",
+          "id":"17",
+          "resource":"taxonomy_term"
+        },
+        {
+          "uri":"http://drupal-7dev.localhost/taxonomy_term/17",
+          "id":"17",
+          "resource":"taxonomy_term"
+        }
+      ],
+      "field_image":{
+        "file":{
+          "uri":"http://drupal-7dev.localhost/file/26",
+          "id":"26",
+          "resource":"file"
+        },
+        "alt":"Abbas haero ille iustum ludus sit sudo ut."
+      },
+      "nid":"92",
+      "vid":"93",
+      "is_new":false,
+      "type":"article",
+      "title":"Pala Sudo",
+      "language":"und",
+      "url":"http://drupal-7dev.localhost/node/92",
+      "edit_url":"http://drupal-7dev.localhost/node/92/edit",
+      "status":"1",
+      "promote":"1",
+      "sticky":"0",
+      "created":"1342559584",
+      "changed":"1343130401",
+      "author":{
+        "uri":"http://drupal-7dev.localhost/user/5",
+        "id":"5",
+        "resource":"user"
+      },
+      "log":"",
+      "revision":null,
+      "comment":"2",
+      "comment_count":"0",
+      "comment_count_new":"0"
+    },
+    {
+      "body":{
+        "value":"<p>teasd</p>\n",
+        "summary":"",
+        "format":"filtered_html"
+      },
+      "field_tags":[
+
+      ],
+      "field_image":{
+        "file":{
+          "uri":"http://drupal-7dev.localhost/file/27",
+          "id":"27",
+          "resource":"file"
+        },
+        "alt":"foo"
+      },
+      "nid":"93",
+      "vid":"94",
+      "is_new":false,
+      "type":"article",
+      "title":"test",
+      "language":"und",
+      "url":"http://drupal-7dev.localhost/node/93",
+      "edit_url":"http://drupal-7dev.localhost/node/93/edit",
+      "status":"1",
+      "promote":"1",
+      "sticky":"0",
+      "created":"1343823327",
+      "changed":"1343823327",
+      "author":{
+        "uri":"http://drupal-7dev.localhost/user/1",
+        "id":"1",
+        "resource":"user"
+      },
+      "log":"",
+      "revision":null,
+      "comment":"2",
+      "comment_count":"0",
+      "comment_count_new":"0"
+    }
+  ]
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/example_exports/node.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<list>
+    <link rel="self" href="http://drupal-7dev.localhost/node?limit=3&amp;page=1"/>
+    <link rel="first" href="http://drupal-7dev.localhost/node?limit=3&amp;page=0"/>
+    <link rel="last" href="http://drupal-7dev.localhost/node?limit=3&amp;page=2"/>
+    <link rel="prev" href="http://drupal-7dev.localhost/node?limit=3&amp;page=0"/>
+    <link rel="next" href="http://drupal-7dev.localhost/node?limit=3&amp;page=2"/>
+    <node>
+        <body>
+            <value>&lt;p&gt;Euismod incassum mauris praesent refoveo tincidunt torqueo turpis uxor. Causa diam dolor elit iriure turpis vereor. Distineo melior vero. Accumsan gemino ille immitto persto usitas. Ad blandit olim probo vicis. Caecus exerci lucidus persto quae si. Causa eu exputo iaceo iustum jus tamen ut. Augue eum ibidem lenis natu olim si tum vero.&lt;/p&gt;
+                &lt;p&gt;At elit eum facilisis in. Et eu paulatim scisco secundum. Accumsan eros nobis quidem.&lt;/p&gt;
+                &lt;p&gt;Nutus quadrum rusticus sudo velit. Esca si turpis. Eros ex fere gravis ideo metuo nostrud. At ulciscor voco. Brevitas letalis ludus meus nobis paratus singularis utinam verto.&lt;/p&gt;
+                &lt;p&gt;Haero macto saluto. Eros facilisis macto neque. Abluo haero si. Abluo enim gilvus humo ideo in quia refoveo. Gilvus hendrerit imputo jumentum loquor occuro pala. Abdo minim paratus saluto. Esca hos incassum iustum similis validus. Abbas camur feugiat obruo valde vero. Inhibeo nulla vero ymo. Abbas autem caecus dolore hendrerit iriure premo si tation volutpat. Conventio cui dolore erat paulatim premo typicus venio vindico.&lt;/p&gt;
+                &lt;p&gt;Consectetuer facilisis feugiat iriure jumentum jus paratus quis. Abbas gemino hendrerit nutus oppeto zelus. Abluo bene capto commodo duis jumentum quia secundum singularis vereor. Consectetuer imputo neque pertineo premo virtus vulpes. Cogo comis consequat defui fere occuro persto. Brevitas dolore euismod interdico macto neque patria saepius tamen.&lt;/p&gt;
+                &lt;p&gt;Appellatio augue causa pala premo quidne refoveo sino utrum venio. Amet consectetuer damnum eu ex ibidem quadrum. Appellatio letalis patria qui voco. Exerci meus modo sino. Abbas elit hendrerit loquor nostrud occuro populus qui torqueo.&lt;/p&gt;
+                &lt;p&gt;Consequat ea iaceo ille pneum saepius tamen. Capto dolore gilvus jumentum molior paulatim probo quidem sudo. Meus minim mos pagus sed zelus. Abigo autem brevitas commoveo conventio erat hendrerit iustum mos neque.&lt;/p&gt;
+            </value>
+            <summary></summary>
+            <format>filtered_html</format>
+        </body>
+        <field_tags>
+            <item resource="taxonomy_term" id="1">http://drupal-7dev.localhost/taxonomy_term/1</item>
+        </field_tags>
+        <field_image>
+            <file resource="file" id="25">http://drupal-7dev.localhost/file/25</file>
+            <alt>Abdo camur gilvus macto praesent probo turpis.</alt>
+        </field_image>
+        <nid>91</nid>
+        <vid>92</vid>
+        <is_new></is_new>
+        <type>article</type>
+        <title>Abbas Dolor</title>
+        <language>und</language>
+        <url>http://drupal-7dev.localhost/node/91</url>
+        <edit_url>http://drupal-7dev.localhost/node/91/edit</edit_url>
+        <status>1</status>
+        <promote>1</promote>
+        <sticky>0</sticky>
+        <created>1342746489</created>
+        <changed>1343130431</changed>
+        <author resource="user" id="5">http://drupal-7dev.localhost/user/5</author>
+        <log></log>
+        <comment>2</comment>
+        <comment_count>0</comment_count>
+        <comment_count_new>0</comment_count_new>
+    </node>
+    <node>
+        <body>
+            <value>Capto damnum diam eros eum ludus quidne roto vero. Ad augue bene decet importunus quae qui vereor.
+
+                Adipiscing brevitas consectetuer exerci gemino refero vereor. Caecus ideo nutus sed. Abluo amet autem elit humo jumentum premo quis sit virtus. Melior obruo roto saepius sed vicis vulputate. Commodo eu lobortis lucidus paratus praesent proprius quis secundum tincidunt. Brevitas caecus erat euismod hendrerit incassum nostrud persto sit vereor.
+
+                Elit meus neque pala. Accumsan brevitas damnum diam enim gravis praemitto secundum similis uxor. Mauris os usitas ymo. Facilisi iriure nibh nobis veniam. Augue erat exputo praesent quidne sed velit vulpes.
+
+                Consequat euismod molior os pagus probo roto sit. Jugis lenis letalis quia. Amet camur huic laoreet nunc os persto proprius vero vulputate. Consequat oppeto paratus tamen vindico. Enim facilisis ille luptatum mauris nulla occuro saepius scisco ymo. Accumsan conventio dolus enim eu melior neque. Blandit gemino incassum iriure nulla pala pertineo quia utinam vulpes. Ad adipiscing magna odio persto quae refero ut voco.
+
+                Autem damnum hendrerit lucidus pertineo voco. At commodo eligo gilvus in incassum quis validus. Caecus cui jus laoreet minim tation vero ymo. In luptatum zelus. Caecus duis haero meus paulatim sed typicus velit.
+
+                Abluo eros et eu letalis natu quae vero. Exputo haero iusto lenis mos vereor wisi. Ille incassum jus probo ullamcorper validus veniam. Capto illum imputo lucidus occuro olim qui quidem utinam. Abbas facilisi imputo incassum nulla sudo utinam valde vereor. Bene facilisi ille. Humo importunus meus obruo. Abdo amet eum ex haero melior nutus persto qui tego.
+
+                Abico acsi defui eligo eros iriure nimis praesent probo. Decet gemino magna nisl patria persto sino tamen verto zelus. Aliquam distineo ex hendrerit loquor. Autem ea exputo importunus persto pneum vulpes. Appellatio blandit hendrerit incassum nisl quia refoveo torqueo. Acsi elit metuo occuro praesent scisco ulciscor ut velit.
+
+                Abluo blandit macto magna mauris metuo pecus plaga ullamcorper vindico. Loquor minim sudo. Humo jus modo nutus veniam. Dignissim enim euismod quibus. Adipiscing ea luctus quidem uxor. Blandit ex exputo haero iusto praesent sagaciter scisco veniam. Blandit brevitas duis elit hendrerit importunus ratis torqueo vero vindico.
+
+                Appellatio decet facilisi magna oppeto praemitto ullamcorper virtus. Caecus ibidem nisl nobis obruo velit volutpat ymo. Eros facilisis gemino jus nunc praemitto verto virtus voco zelus. Abigo pala velit. Augue cui diam exerci praesent singularis. Abluo aliquam enim inhibeo iriure meus qui veniam.
+
+                Exputo oppeto pecus pneum. Et gemino jumentum lucidus nutus persto secundum tincidunt torqueo valetudo. Bene dolor erat ex quidem virtus vulputate ymo. Aptent capto macto ratis roto utrum. Causa dolor eu ex paulatim quia usitas.
+
+                Abdo adipiscing gilvus ibidem turpis vulputate. Ad cui incassum sed singularis. Cui damnum eum luctus oppeto persto ullamcorper velit vero virtus. Caecus duis ibidem minim tincidunt. Aliquam augue bene cogo defui jumentum proprius qui ut utinam. Abdo amet esca jugis molior nobis. Abbas abico consectetuer genitus iustum lobortis praemitto quibus ratis saluto. Autem laoreet metuo nimis oppeto similis tego.
+
+                Adipiscing dolore eros gravis lenis. Acsi autem gemino immitto nunc. Commoveo exputo fere huic iustum lenis loquor magna minim sagaciter. Dolore hendrerit incassum refoveo sit tego tincidunt venio vero vulputate. Abluo acsi at eu magna quadrum sino sudo utrum. Abdo antehabeo conventio jus neo sino. Abluo aliquam amet ibidem valde zelus. Commoveo exerci facilisis olim proprius sino ymo. Adipiscing blandit capto defui diam euismod huic neo tincidunt.
+
+            </value>
+            <summary></summary>
+            <format>php_code</format>
+        </body>
+        <field_tags>
+            <item resource="taxonomy_term" id="17">http://drupal-7dev.localhost/taxonomy_term/17</item>
+            <item resource="taxonomy_term" id="17">http://drupal-7dev.localhost/taxonomy_term/17</item>
+            <item resource="taxonomy_term" id="17">http://drupal-7dev.localhost/taxonomy_term/17</item>
+        </field_tags>
+        <field_image>
+            <file resource="file" id="26">http://drupal-7dev.localhost/file/26</file>
+            <alt>Abbas haero ille iustum ludus sit sudo ut.</alt>
+        </field_image>
+        <nid>92</nid>
+        <vid>93</vid>
+        <is_new></is_new>
+        <type>article</type>
+        <title>Pala Sudo</title>
+        <language>und</language>
+        <url>http://drupal-7dev.localhost/node/92</url>
+        <edit_url>http://drupal-7dev.localhost/node/92/edit</edit_url>
+        <status>1</status>
+        <promote>1</promote>
+        <sticky>0</sticky>
+        <created>1342559584</created>
+        <changed>1343130401</changed>
+        <author resource="user" id="5">http://drupal-7dev.localhost/user/5</author>
+        <log></log>
+        <comment>2</comment>
+        <comment_count>0</comment_count>
+        <comment_count_new>0</comment_count_new>
+    </node>
+    <node>
+        <body>
+            <value>&lt;p&gt;teasd&lt;/p&gt;
+            </value>
+            <summary></summary>
+            <format>filtered_html</format>
+        </body>
+        <field_tags/>
+        <field_image>
+            <file resource="file" id="27">http://drupal-7dev.localhost/file/27</file>
+            <alt>foo</alt>
+        </field_image>
+        <nid>93</nid>
+        <vid>94</vid>
+        <is_new></is_new>
+        <type>article</type>
+        <title>test</title>
+        <language>und</language>
+        <url>http://drupal-7dev.localhost/node/93</url>
+        <edit_url>http://drupal-7dev.localhost/node/93/edit</edit_url>
+        <status>1</status>
+        <promote>1</promote>
+        <sticky>0</sticky>
+        <created>1343823327</created>
+        <changed>1343823327</changed>
+        <author resource="user" id="1">http://drupal-7dev.localhost/user/1</author>
+        <log></log>
+        <comment>2</comment>
+        <comment_count>0</comment_count>
+        <comment_count_new>0</comment_count_new>
+    </node>
+</list>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/example_exports/user.1.json	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+{
+
+  "uid": "1",
+  "name": "foo",
+  "mail": "foo.bar@domain.com",
+  "url": "http://drupal-7dev.localhost/user/1",
+  "edit_url": "http://drupal-7dev.localhost/user/1/edit",
+  "last_access": "1344245660",
+  "last_login": "1343821898",
+  "created": "1339609269",
+  "roles": [
+    2,
+    3
+  ],
+  "status": "1",
+  "theme": "bartik"
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/example_exports/user.1.xml	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<user>
+    <uid>1</uid>
+    <name>foo</name>
+    <mail>foo.bar@domain.com</mail>
+    <url>http://drupal-7dev.localhost/user/1</url>
+    <edit_url>http://drupal-7dev.localhost/user/1/edit</edit_url>
+    <last_access>1344245660</last_access>
+    <last_login>1343821898</last_login>
+    <created>1339609269</created>
+    <roles>
+        <item>2</item>
+        <item>3</item>
+    </roles>
+    <status>1</status>
+    <theme>bartik</theme>
+</user>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws.api.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,251 @@
+<?php
+
+/**
+ * @file
+ * This file contains no working PHP code; it exists to provide additional
+ * documentation for doxygen as well as to document hooks in the standard
+ * Drupal manner.
+ */
+
+
+/**
+ * @defgroup restws RestWS module integrations.
+ *
+ * Module integrations with the restws module.
+ */
+
+/**
+ * @defgroup restws_hooks RestWS' hooks
+ * @{
+ * Hooks that can be implemented by other modules in order to extend restws.
+ */
+
+/**
+ * Define restws compatible resources.
+ *
+ * This hook is required in order to add new restws resources.
+ *
+ * @return array
+ *   An array of information about the module's provided resources.
+ *   The array contains a sub-array for each resource, with the resource name as
+ *   the key. Resource names may only contain lowercase alpha-numeric characters
+ *   and underscores and should be prefixed with the providing module name.
+ *   Possible attributes for each sub-array are:
+ *   - label: The label of the resource. Start capitalized.
+ *   - class: The name of the controller class for the resource. The class has
+ *     to implement the RestWSResourceControllerInterface. Required.
+ *   - menu_path: A relative path were the resource callback should lie. By
+ *     default the resource name will be used as menu path. Optional.
+ *
+ * @see MyModuleBookResourceController
+ */
+function hook_restws_resource_info() {
+  return array(
+    'mymodule_book' => array(
+      'label' => t('Book'),
+      'class' => 'MyModuleBookResourceController',
+      'menu_path' => 'api/mybook',
+    ),
+    'mymodule_status' => array(
+      'label' => t('Status'),
+      'class' => 'MyModuleStatusResourceController',
+    ),
+  );
+}
+
+/**
+ * Alter available resource information.
+ *
+ * @param array $resource_info
+ *   Resource information as defined in hook_restws_resource_info(). You can
+ *   move the path of a resouce by setting menu_info. In this example you'll
+ *   have to retrieve nodes from /mypath.json or /mypath/1.json.
+ *
+ * @see hook_restws_resource_info()
+ */
+function hook_restws_resource_info_alter(&$resource_info) {
+  $resource_info['node']['class'] = 'MySpecialNodeResourceController';
+  $resource_info['node']['menu_path'] = 'mypath';
+}
+
+/**
+ * Define restws compatible formats.
+ *
+ * This hook is required in order to add new restws formats.
+ *
+ * @return array
+ *   An array of information about the module's provided formats.
+ *   The array contains a sub-array for each format, with the format name as
+ *   the key. Format names may only contain lowercase alpha-numeric characters
+ *   and underscores.
+ *   Possible attributes for each sub-array are:
+ *   - label: The label of the format. Start capitalized.
+ *   - class: The name of the class for the format. The class has to implement
+ *     the RestWSFormatInterface. Required.
+ *   - mime type: The official internet media type (MIME type) of the format.
+ *     Required.
+ */
+function hook_restws_format_info() {
+  return array(
+    'json' => array(
+      'label' => t('JSON'),
+      'class' => 'RestWSFormatJSON',
+      'mime type' => 'application/json',
+    ),
+    'xml' => array(
+      'label' => t('XML'),
+      'class' => 'RestWSFormatXML',
+      'mime type' => 'application/xml',
+    ),
+  );
+}
+
+/**
+ * Alter available format information.
+ *
+ * @param array $format_info
+ *   Format information as defined in hook_restws_format_info()
+ *
+ * @see hook_restws_format_info()
+ */
+function hook_restws_format_info_alter(&$format_info) {
+  $format_info['json']['class'] = 'MyJsonFormatHandler';
+}
+
+/**
+ * Alter the incoming request array.
+ *
+ * @param array $request
+ *   A request array that contains the following items:
+ *   - op: operation string, one of create, read, update or delete.
+ *   - format: object implementing RestWSFormatInterface.
+ *   - resource: object implementing RestWSResourceControllerInterface.
+ *   - id: resource identifier or NULL for the create operation.
+ *   - payload: array containing data attached to this request, if any.
+ */
+function hook_restws_request_alter(array &$request) {
+  if ($request['resource']->resource() == 'node') {
+    $request['format'] = restws_format('json');
+  }
+}
+
+/**
+ * Alter the outgoing response.
+ *
+ * @param mixed $response
+ *   The response data being returned by the REST service (not yet serialized).
+ *
+ * @param string $function
+ *   The function being called on the REST service.
+ *
+ * @param string $format
+ *   The name of the format serializing the response.
+ */
+function hook_restws_response_alter(&$response, $function, $formatName) {
+  if ($function == 'viewResource' && $formatName == 'json') {
+    $response['site_name'] = variable_get('site_name', '');
+  }
+}
+
+/**
+ * @}
+ */
+
+/**
+ * Example controller class for the mymodule_book resource.
+ */
+class MyModuleBookResourceController implements RestWSResourceControllerInterface {
+
+  /**
+   * @see hook_entity_property_info()
+   * @see RestWSResourceControllerInterface::propertyInfo()
+   */
+  public function propertyInfo() {
+    return array(
+      'properties' => array(
+        'title' => array(
+          'type' => 'text',
+          'label' => t('Book title'),
+          'setter callback' => 'entity_property_verbatim_set',
+        ),
+        'author' => array(
+          'type' => 'text',
+          'label' => t('Author'),
+          'setter callback' => 'entity_property_verbatim_set',
+        ),
+        'pages' => array(
+          'type' => 'integer',
+          'label' => t('Number of pages'),
+          'setter callback' => 'entity_property_verbatim_set',
+        ),
+        'price' => array(
+          'type' => 'decimal',
+          'label' => t('Price'),
+          'setter callback' => 'entity_property_verbatim_set',
+        ),
+      ),
+    );
+  }
+
+  /**
+   * @see RestWSResourceControllerInterface::wrapper()
+   */
+  public function wrapper($id) {
+    $book = mymodule_book_load($id);
+    $info = $this->propertyInfo();
+    return entity_metadata_wrapper('mymodule_book', $book, array('property info' => $info['properties']));
+  }
+
+  /**
+   * @see RestWSResourceControllerInterface::create()
+   */
+  public function create(array $values) {
+    try {
+      $book = mymodule_book_save($values);
+      return $book->id;
+    }
+    catch (Exception $e) {
+      throw new RestWSException('Creation error', 406);
+    }
+  }
+
+  /**
+   * @see RestWSResourceControllerInterface::read()
+   */
+  public function read($id) {
+    return mymodule_book_load($id);
+  }
+
+  /**
+   * @see RestWSResourceControllerInterface::update()
+   */
+  public function update($id, array $values) {
+    throw new RestWSException('Not implemented', 501);
+  }
+
+  /**
+   * @see RestWSResourceControllerInterface::delete()
+   */
+  public function delete($id) {
+    try {
+      mymodule_book_delete($id);
+    }
+    catch (Exception $e) {
+      throw new RestWSException('Book not found', 404);
+    }
+  }
+
+  /**
+   * @see RestWSResourceControllerInterface::access()
+   */
+  public function access($op, $id) {
+    return mymodule_book_access($op, $id);
+  }
+
+  /**
+   * @see RestWSResourceControllerInterface::resource()
+   */
+  public function resource() {
+    return 'mymodule_book';
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws.entity.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,420 @@
+<?php
+
+/**
+ * @file
+ * RESTful web services module integration for entities.
+ */
+
+/**
+ * Specifies CRUD and access methods for resources.
+ */
+interface RestWSResourceControllerInterface {
+
+  /**
+   * Returns the property info for the given resource.
+   *
+   * @return array
+   *   An array structured as hook_entity_property_info() is structured for an
+   *   entity type.
+   */
+  public function propertyInfo();
+
+  /**
+   * Returns a metadata wrapper for the resource with the given id.
+   *
+   * @return EntityStructureWrapper
+   *   Metadata wrapper of the resource.
+   */
+  public function wrapper($id);
+
+  /**
+   * Create a new resource.
+   *
+   * @param array $values
+   *   Array of values for properties of the resource, keyed by property
+   *   name. At least for all required properties values have to be given.
+   *
+   * @return int|string
+   *   The id of the newly created resource.
+   */
+  public function create(array $values);
+
+  /**
+   * Returns an existing resource.
+   *
+   * @param int|string $id
+   *   The id of the resource that should be returned.
+   *
+   * @return
+   *   The internal representation of the resource.
+   */
+  public function read($id);
+
+  /**
+   * Update an existing resource.
+   *
+   * @param int|string $id
+   *   The id of the resource that should be updated.
+   * @param array $values
+   *   An array of values for the properties to be updated, keyed by property
+   *   name.
+   */
+  public function update($id, array $values);
+
+  /**
+   * Delete an existing resource.
+   *
+   * @param int|string $id
+   *   The id of the resource that should be deleted.
+   */
+  public function delete($id);
+
+  /**
+   * Determines access for a given operation and resource.
+   *
+   * @param string $op
+   *   Either 'create', 'view' (= read), 'update' or 'delete'.
+   * @param int|string $id
+   *   The id of the resource.
+   *
+   * @see entity_access()
+   */
+  public function access($op, $id);
+
+  /**
+   * Returns the name of the resource.
+   */
+  public function resource();
+}
+
+/**
+ * Specifies query methods for resources.
+ */
+interface RestWSQueryResourceControllerInterface extends RestWSResourceControllerInterface {
+  /**
+   * Query for a list of resources.
+   *
+   * @param array $filters
+   *   A list of properties to query for, or an empty array if all resources
+   *   should be counted.
+   * @param array $meta_controls
+   *   @see restws_meta_controls()
+   *
+   * @return array
+   *   An array containing the ids of the matching resources.
+   */
+  public function query($filters = array(), $meta_controls = array());
+
+  /**
+   * Returns the number of resources available with the given filters.
+   *
+   * @param array $filters
+   *   A list of properties to query for, or an empty array if all resources
+   *   should be returned.
+   *
+   * @return int
+   *   The number of resources available.
+   */
+  public function count($filters = array());
+
+  /**
+   * Returns the limit for the current query.
+   *
+   * @param int $client_limit
+   *   The limit specified in the meta controls or NULL if not set.
+   *
+   * @return int
+   *   The limit of the current limit.
+   */
+  public function limit($client_limit = NULL);
+}
+
+/**
+ * Controller for entity-bases resources.
+ */
+class RestWSEntityResourceController implements RestWSQueryResourceControllerInterface {
+
+  protected $entityType, $entityInfo;
+
+  public function __construct($name, $info) {
+    $this->entityType = $name;
+    $this->entityInfo = entity_get_info($name);
+  }
+
+  public function propertyInfo() {
+    return entity_get_all_property_info($this->entityType);
+  }
+
+  public function wrapper($id) {
+    return entity_metadata_wrapper($this->entityType, $id);
+  }
+
+  public function read($id) {
+    return $this->wrapper($id)->value();
+  }
+
+  public function create(array $values) {
+    // Make sure that bundle information is present on entities that have
+    // bundles.
+    $entity_info = entity_get_info($this->entityType);
+    if (isset($entity_info['bundle keys'])) {
+      foreach ($entity_info['bundle keys'] as $bundle_key) {
+        if (!array_key_exists($bundle_key, $values)) {
+          throw new RestWSException('Missing bundle: ' . $bundle_key, 406);
+        }
+      }
+    }
+
+    try {
+      $wrapper = entity_property_values_create_entity($this->entityType, $values);
+      // Get the ID and bundle property names.
+      $entity_keys = array_intersect_key($entity_info['entity keys'], array('id' => 1, 'bundle' => 1));
+
+      foreach (array_keys($values) as $name) {
+        // Don't check access on entity keys for new entities. Otherwise,
+        // property access checks will fail for, e.g., node type, which
+        // requires the 'administer nodes' permission to set.
+        // @see entity_metadata_node_entity_property_info().
+        if (!in_array($name, $entity_keys)) {
+          if (!$this->checkPropertyAccess($wrapper, $name, $wrapper->{$name})) {
+            throw new RestWSException(t('Not authorized to set property @p', array('@p' => $name)), 403);
+          }
+        }
+      }
+    }
+    catch (EntityMetadataWrapperException $e) {
+      throw new RestWSException($e->getMessage(), 406);
+    }
+
+    $properties = $wrapper->getPropertyInfo();
+    $diff = array_diff_key($values, $properties);
+    if (!empty($diff)) {
+      throw new RestWSException('Unknown data properties: ' . implode(' ', array_keys($diff)) . '.', 406);
+    }
+    $wrapper->save();
+    return $wrapper->getIdentifier();
+  }
+
+  public function update($id, array $values) {
+    $wrapper = $this->wrapper($id);
+    $entity_info = $wrapper->entityInfo();
+    // Get the ID and bundle property names.
+    $entity_keys = array_intersect_key($entity_info['entity keys'], array('id' => 1, 'bundle' => 1));
+    try {
+      foreach ($values as $name => $value) {
+        if (in_array($name, $entity_keys)) {
+          // We don't allow changing the entity ID or bundle.
+          if ($wrapper->{$name}->value() != $value) {
+            throw new RestWSException('Unable to change ' . $name, 422);
+          }
+        }
+        else {
+          $wrapper->{$name}->set($value);
+          if (!$this->checkPropertyAccess($wrapper, $name, $wrapper->{$name})) {
+            throw new RestWSException(t('Not authorized to set property @p', array('@p' => $name)), 403);
+          }
+        }
+      }
+    }
+    catch (EntityMetadataWrapperException $e) {
+      throw new RestWSException($e->getMessage(), 406);
+    }
+    $wrapper->save();
+  }
+
+  public function delete($id) {
+    entity_delete($this->entityType, $id);
+  }
+
+  /**
+   * Implements RestWSQueryResourceControllerInterface::query().
+   */
+  public function query($filters = array(), $meta_controls = array()) {
+    $limit = variable_get('restws_query_max_limit', 100);
+    $offset = 0;
+
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $this->resource());
+
+    foreach ($filters as $filter => $value) {
+      $this->propertyQueryOperation($query, 'Condition', $filter, $value);
+    }
+
+    $rest_controls = restws_meta_controls();
+    foreach ($meta_controls as $control_name => $value) {
+      switch ($control_name) {
+        case $rest_controls['sort']:
+          if (isset($meta_controls[$rest_controls['direction']]) && strtolower($meta_controls[$rest_controls['direction']]) == 'desc') {
+            $direction = 'DESC';
+          }
+          else {
+            $direction = 'ASC';
+          }
+          $this->propertyQueryOperation($query, 'OrderBy', $value, $direction);
+          break;
+
+        case $rest_controls['limit']:
+          $limit = $this->limit($value);
+          break;
+
+        case $rest_controls['page']:
+          $offset = $value > 0 ? $value : $offset;
+          break;
+      }
+    }
+
+    // Calculate the offset.
+    $offset *= $limit;
+    $query->range($offset, $limit);
+
+    $this->nodeAccess($query);
+
+    // Catch any errors, like wrong keywords or properties.
+    try {
+      $query_result = $query->execute();
+    }
+    catch (PDOException $exception) {
+      throw new RestWSException('Query failed.', 400);
+    }
+    $query_result = isset($query_result[$this->resource()]) ? $query_result[$this->resource()] : array();
+
+    $result = array_keys($query_result);
+
+    return $result;
+  }
+
+
+  /**
+   * Implements RestWSQueryResourceControllerInterface::count().
+   */
+  public function count($filters = array()) {
+    $query = new EntityFieldQuery();
+    $query->entityCondition('entity_type', $this->resource());
+
+    foreach ($filters as $filter => $value) {
+      $this->propertyQueryOperation($query, 'Condition', $filter, $value);
+    }
+    $query->count();
+    $this->nodeAccess($query);
+
+    return $query->execute();
+  }
+
+  /**
+   * Helper function to respect node permissions while querying.
+   *
+   * @param EntityFieldQuery $query
+   *   The query object.
+   */
+  protected function nodeAccess(EntityFieldQuery $query) {
+    // Respect node access and filter out unpublished nodes if user lacks
+    // the right permission.
+    if ($this->resource() == 'node') {
+      $query->addTag('node_access');
+      if (!user_access('bypass node access')) {
+        $this->propertyQueryOperation($query, 'Condition', 'status', 1);
+      }
+    }
+  }
+
+  /**
+   * Implements RestWSQueryResourceControllerInterface::limit().
+   */
+  public function limit($client_limit = NULL) {
+    $limit = variable_get('restws_query_max_limit', 100);
+    // Only allow user provided limits smaller than the system hard limit.
+    if (!empty($client_limit) && $client_limit < $limit) {
+      return $client_limit;
+    }
+    else {
+      return $limit;
+    }
+  }
+
+  public function access($op, $id) {
+    return entity_access($op, $this->entityType, isset($id) ? $this->wrapper($id)->value() : NULL);
+  }
+
+  public function resource() {
+    return $this->entityType;
+  }
+
+  /**
+   * Helper function which takes care of distinguishing between fields and
+   * entity properties and executes the right EntityFieldQuery function for it.
+   *
+   * @param EntityFieldQuery $query
+   *   The EntityFieldQuery pointer which should be used.
+   *
+   * @param string $operation
+   *   The general function name, without the words 'property' or 'field'.
+   *
+   * @param string $property
+   *   The property or field which should be used.
+   *
+   * @param string|array $value
+   *   The value for the function.
+   */
+  protected function propertyQueryOperation(EntityFieldQuery $query, $operation, $property, $value) {
+    $properties = $this->propertyInfo();
+
+    // If field is not set, then the filter is a property and we can extract
+    // the schema field from the property array.
+    if (empty($properties[$property]['field'])) {
+      $column = $properties[$property]['schema field'];
+      $operation = 'property' . $operation;
+      $query->$operation($column, $value);
+    }
+    else {
+      // For fields we need the field info to get the right column for the
+      // query.
+      $field_info = field_info_field($property);
+      $operation = 'field' . $operation;
+      if (is_array($value)) {
+        // Specific column filters are given, so add a query condition for each
+        // one of them.
+        foreach ($value as $column => $val) {
+          $query->$operation($field_info, $column, $val);
+        }
+      }
+      else {
+        // Just pick the first field column for the operation.
+        $columns = array_keys($field_info['columns']);
+        $column = $columns[0];
+        $query->$operation($field_info, $column, $value);
+      }
+    }
+  }
+
+  /**
+   * Helper method to check access on a property.
+   *
+   * @todo Remove this once Entity API properly handles text format access.
+   *
+   * @param EntityMetadataWrapper $entity
+   *   The parent entity.
+   * @param string $property_name
+   *   The property name on the entity.
+   * @param EntityMetadataWrapper $property
+   *   The property whose access is to be checked.
+   *
+   * @return bool
+   *   TRUE if the current user has access to set the property, FALSE otherwise.
+   */
+  protected function checkPropertyAccess($entity, $property_name, $property) {
+    global $user;
+    // Special case node author: we allow access if set to the current user.
+    if ($entity->type() == 'node' && $property_name == 'author' && $property->raw() == $GLOBALS['user']->uid) {
+      return TRUE;
+    }
+    // @todo Hack to check format access for text fields. Should be removed once
+    // this is handled properly on the Entity API level.
+    elseif ($property->type() == 'text_formatted' && $property->format->value()) {
+      $format = (object) array('format' => $property->format->value());
+      if (!filter_access($format)) {
+        return FALSE;
+      }
+    }
+    return $property->access('edit');
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws.formats.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,788 @@
+<?php
+
+/**
+ * @file
+ * RESTful web services module formats.
+ */
+
+/**
+ * Interface implemented by formatter implementations for the http client.
+ */
+interface RestWSFormatInterface {
+
+  /**
+   * Gets the representation of a resource.
+   *
+   * @param RestWSResourceControllerInterface $resourceController
+   *   The controller used to retrieve the resource.
+   * @param int|string $id
+   *   The id of the resource that should be returned.
+   *
+   * @return string
+   *   The representation of the resource.
+   */
+  public function viewResource($resourceController, $id);
+
+  /**
+   * Create a resource.
+   *
+   * @param RestWSResourceControllerInterface $resourceController
+   *   The controller used to create the resource.
+   * @param string $data
+   *   The representation of the resource.
+   *
+   * @return int|string
+   *   The id of the newly created resource.
+   */
+  public function createResource($resourceController, $data);
+
+  /**
+   * Update a resource.
+   *
+   * @param RestWSResourceControllerInterface $resourceController
+   *   The controller used to update the resource.
+   * @param int|string $id
+   *   The id of the resource that should be updated.
+   * @param string $data
+   *   The representation of the resource.
+   */
+  public function updateResource($resourceController, $id, $data);
+
+  /**
+   * Delete a resource.
+   *
+   * @param RestWSResourceControllerInterface $resourceController
+   *   The controller used to update the resource.
+   * @param int|string $id
+   *   The id of the resource that should be deleted.
+   */
+  public function deleteResource($resourceController, $id);
+
+  /**
+   * Query for a resource.
+   *
+   * If a format doesn't want to implement querying, then it should throw an
+   * RestWSException with the 501 HTTP status code.
+   *
+   * @param RestWSResourceControllerInterface $resourceController
+   *   The controller used to query the resource.
+   * @param array $payload
+   *   An optional way to pass the query parameters.
+   *
+   * @return string
+   *   The serialized representation of a list of resources.
+   */
+  public function queryResource($resourceController, $payload);
+
+
+  /**
+   * Returns the mime type of this format, e.g. 'application/json' or
+   * 'application/xml'.
+   */
+  public function mimeType();
+
+  /**
+   * Returns the short name of this format.
+   *
+   * @return string
+   *   The format name, example: "json".
+   */
+  public function getName();
+}
+
+/**
+ * A base for all simple formats that are just serializing/unserializing an
+ * array of property values.
+ */
+abstract class RestWSBaseFormat implements RestWSFormatInterface {
+
+  protected $formatName;
+  protected $formatInfo;
+
+  public function __construct($name, $info) {
+    $this->formatName = $name;
+    $this->formatInfo = $info;
+  }
+
+  /**
+   * Gets the representation of a resource.
+   */
+  public function viewResource($resourceController, $id) {
+    $values = self::getData($resourceController->wrapper($id));
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $values, $function, $this->formatName);
+
+    return $this->serialize($values);
+  }
+
+  /**
+   * Creates a new resource.
+   */
+  public function createResource($resourceController, $data) {
+    $values = $this->unserialize($resourceController->propertyInfo(), $data);
+    $id = $resourceController->create($values);
+    $ref = self::getResourceReference($resourceController->resource(), $id);
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $ref, $function, $this->formatName);
+
+    return $this->serialize($ref);
+  }
+
+  /**
+   * Updates a resource.
+   */
+  public function updateResource($resourceController, $id, $data) {
+    $values = $this->unserialize($resourceController->propertyInfo(), $data);
+    $resourceController->update($id, $values);
+    // Return an empty representation by default.
+    $value = array();
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $value, $function, $this->formatName);
+
+    return $this->serialize($value);
+  }
+
+  /**
+   * Deletes a resource.
+   */
+  public function deleteResource($resourceController, $id) {
+    $resourceController->delete($id);
+    // Return an empty representation by default.
+    $value = array();
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $value, $function, $this->formatName);
+
+    return $this->serialize($value);
+  }
+
+  /**
+   * Implements RestWSFormatInterface::queryResource().
+   */
+  public function queryResource($resourceController, $payload) {
+    // Get the parameter from the URL.
+    $parameters = drupal_get_query_parameters();
+
+    $rest_controls = restws_meta_controls();
+    $properties = $resourceController->propertyInfo();
+    $split_parameters = $this->splitParameters($properties, $parameters);
+
+    $values = $this->generateQueryURIs($resourceController, $parameters, $split_parameters['filters']);
+
+    $full = (isset($split_parameters['meta_controls'][$rest_controls['full']])) ? $split_parameters['meta_controls'][$rest_controls['full']] : 1;
+
+    $result = $resourceController->query($split_parameters['filters'], $split_parameters['meta_controls']);
+    if ($full === '0') {
+      foreach ($result as $id) {
+        $values['list'][] = $this->getResourceReference($resourceController->resource(), $id);
+      }
+    }
+    else {
+      foreach ($result as $id) {
+        $values['list'][] = self::getData($resourceController->wrapper($id));
+      }
+    }
+
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $values, $function, $this->formatName);
+
+    return $this->serialize($values);
+  }
+
+  public function mimeType() {
+    return $this->formatInfo['mime type'];
+  }
+
+  public function getName() {
+    return $this->formatName;
+  }
+
+  /**
+   * Gets a simple PHP array using URI references for some wrapped data.
+   *
+   * This is the counter-part of self::getPropertyValues().
+   */
+  public static function getData($wrapper) {
+    $data = array();
+    $filtered = restws_property_access_filter($wrapper);
+    foreach ($filtered as $name => $property) {
+      try {
+        if ($property instanceof EntityDrupalWrapper) {
+          // For referenced entities only return the URI.
+          if ($id = $property->getIdentifier()) {
+            $data[$name] = self::getResourceReference($property->type(), $id);
+          }
+        }
+        elseif ($property instanceof EntityValueWrapper) {
+          $data[$name] = $property->value();
+        }
+        elseif ($property instanceof EntityListWrapper || $property instanceof EntityStructureWrapper) {
+          $data[$name] = self::getData($property);
+        }
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // A property causes problems - ignore that.
+      }
+    }
+    return $data;
+  }
+
+  public static function getResourceReference($resource, $id) {
+    $return = array(
+      'uri' => restws_resource_uri($resource, $id),
+      'id' => $id,
+      'resource' => $resource,
+    );
+    if (module_exists('uuid') && entity_get_info($resource)) {
+      $ids = entity_get_uuid_by_id($resource, array($id));
+      if ($id = reset($ids)) {
+        $return['uuid'] = $id;
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Transforms simple-array data values to valid entity property values.
+   *
+   * This is the counter-part of self::getData(), thus it converts resource
+   * references to the required value(s).
+   *
+   * @param array $values
+   *   The array representation of the data values.
+   * @param $property_info
+   *   The property info array of the entity type for which we are transforming
+   *   the values.
+   */
+  protected function getPropertyValues(array &$values, $property_info) {
+    foreach ($values as $name => &$property_value) {
+      if (isset($property_info[$name]) && $info = $property_info[$name]) {
+
+        // Check if there is a resource array and if the property has a type.
+        if (is_array($property_value) && isset($info['type'])) {
+
+          // Check if the field is a list or a single value field.
+          if (entity_property_list_extract_type($info['type'])) {
+            // Check if the list values consist of structure wrappers.
+            if (array_key_exists('property info', $info)) {
+              foreach ($property_value as &$list_values) {
+                $this->getPropertyValues($list_values, $info['property info']);
+              }
+            }
+            else {
+              $list_type = entity_property_list_extract_type($info['type']);
+              foreach ($property_value as &$list_value) {
+                $list_value = $this->getResourceReferenceValue($list_type, $list_value);
+              }
+            }
+          }
+          else {
+            // Check if the property is a structure wrapper.
+            if (array_key_exists('property info', $info)) {
+              $this->getPropertyValues($property_value, $info['property info']);
+            }
+            else {
+              $property_value = $this->getResourceReferenceValue($info['type'], $property_value);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Gets the resource reference value.
+   *
+   * @param $type
+   *   The data type of the reference property.
+   * @param array $reference
+   *   The input data specifying the resource reference in one supported way.
+   *
+   * @return mixed
+   *   The value to be set for the reference. Usually this is an entity or
+   *   resource id, but for generic entity references it's an
+   *   EntityDrupalWrapper.
+   *
+   * @see RestWSBaseFormat::getResourceReference()
+   */
+  protected function getResourceReferenceValue($type, array $reference) {
+
+    if (isset($reference['id']) && $type != 'entity') {
+      return $reference['id'];
+    }
+    // Handle setting generic entity references, i.e. of type entity.
+    elseif ($type == 'entity' && isset($reference['id']) && isset($reference['resource'])) {
+      if (!entity_get_info($reference['resource'])) {
+        throw new RestWSException('Invalid resource for entity reference given.', 406);
+      }
+      return entity_metadata_wrapper($reference['resource'], $reference['id']);
+    }
+    elseif (isset($reference['uri'])) {
+      // @todo: Implement setting references by URI by parsing resource/id from
+      // the URI.
+    }
+    elseif (isset($reference['uuid']) && module_exists('uuid') && $type != 'entity') {
+      $ids = entity_get_id_by_uuid($type, array($reference['uuid']));
+      if (!$ids) {
+        throw new RestWSException('Invalid UUID for resource reference given.', 406);
+      }
+      return reset($ids);
+    }
+
+    throw new RestWSException('Invalid value for resource reference given.', 406);
+  }
+
+  /**
+   * Splits a query parameter into two sub arrays containing the filters and
+   * meta controls.
+   *
+   * @param array $properties
+   *   An array containing the properties of the resource.
+   *
+   * @param array $parameters
+   *   An array which contains filters and meta controls.
+   *
+   * @return array
+   *   An array containing two sub arrays, one for filters and one for meta
+   *   controls with corresponding keys.
+   *
+   * @throws RestWSException
+   *   If a filter isn't valid, the function will throw a RestWSException with
+   *   the 412 HTTP status code.
+   */
+  protected function splitParameters($properties, array $parameters) {
+    $meta_controls = array();
+    $rest_controls = restws_meta_controls();
+    foreach ($parameters as $control_name => $property) {
+      if (isset($rest_controls[$control_name])) {
+        $meta_controls[$control_name] = $property;
+        unset($parameters[$control_name]);
+      }
+    }
+
+    $filters = array();
+    foreach ($parameters as $parameter => $value) {
+      // Check if the property is prefixed.
+      if (substr($parameter, 0, 9) == 'property_') {
+        $parameter = substr($parameter, 9, strlen($parameter) - 9);
+      }
+
+      // If the parameter doesn't exist, we can not filter for and need to
+      // notify the client about it.
+      if (!isset($properties[$parameter])) {
+        throw new RestWSException('Not a valid filter: ' . $parameter, 412);
+      }
+      $filters[$parameter] = $value;
+    }
+    return array('meta_controls' => $meta_controls, 'filters' => $filters);
+  }
+
+  /**
+   * Generates all navigation links for querying.
+   *
+   * @param RestWSResourceControllerInterface $resourceController
+   *   The controller used to query the resource.
+   *
+   * @param array $parameters
+   *   The HTTP GET parameters for the query.
+   *
+   * @param array $filters
+   *   The filters for the query.
+   *
+   * @return array
+   *   An array containing all navigation links.
+   *
+   * @throws RestWSException
+   *   If the page is out of range the function will throw a new RestWSException
+   *   with HTTP status code 404.
+   */
+  protected function generateQueryURIs(RestWSResourceControllerInterface $resourceController, array $parameters, array $filters) {
+    $rest_controls = restws_meta_controls();
+
+    $count = $resourceController->count($filters);
+    $limit = isset($parameters[$rest_controls['limit']]) ? $parameters[$rest_controls['limit']] : NULL;
+    $limit = $resourceController->limit($limit);
+    $page = isset($parameters[$rest_controls['page']]) ? $parameters[$rest_controls['page']] : 0;
+
+    $last = ceil($count / $limit) - 1;
+
+    if ($page > $last || $page < 0) {
+      throw new RestWSException('Page doesn\'t exist.', 404);
+    }
+
+    $uris = array();
+    $options = array(
+      'query' => &$parameters,
+    );
+
+    $uris['self'] = restws_resource_uri($resourceController->resource(), null, $options);
+    $parameters['page'] = 0;
+    $uris['first'] = restws_resource_uri($resourceController->resource(), null, $options);
+    $parameters['page'] = $last;
+    $uris['last'] = restws_resource_uri($resourceController->resource(), null, $options);
+
+
+    if ($page != 0) {
+      $parameters['page'] = $page - 1;
+      $uris['prev'] = restws_resource_uri($resourceController->resource(), null, $options);
+    }
+
+    if ($page != $last) {
+      $parameters['page'] = $page + 1;
+      $uris['next'] = restws_resource_uri($resourceController->resource(), null, $options);
+    }
+
+    return $uris;
+  }
+}
+
+/**
+ * Filters out properties where view access is not allowed for the current user.
+ *
+ * @param EntityMetadataWrapper $wrapper
+ *   EntityMetadataWrapper that should be checked.
+ *
+ * @return
+ *   An array of properties where access is allowed, keyed by their property
+ *   name.
+ */
+function restws_property_access_filter($wrapper) {
+  $filtered = array();
+  foreach ($wrapper as $name => $property) {
+    if ($property->access('view')) {
+      $filtered[$name] = $property;
+    }
+  }
+  return $filtered;
+}
+
+/**
+ * A formatter to format json.
+ */
+class RestWSFormatJSON extends RestWSBaseFormat {
+
+  public function serialize($values) {
+    return drupal_json_encode($values);
+  }
+
+  public function unserialize($properties, $data) {
+    $values = drupal_json_decode($data);
+    $this->getPropertyValues($values, $properties);
+    return $values;
+  }
+}
+
+/**
+ * A formatter for XML.
+ */
+class RestWSFormatXML extends RestWSBaseFormat {
+
+  /**
+   * Gets the representation of a resource.
+   */
+  public function viewResource($resourceController, $id) {
+    $xml = new DOMDocument('1.0', 'utf-8');
+    $element = $xml->createElement($resourceController->resource());
+    self::addToXML($xml, $element, $resourceController->wrapper($id));
+    $xml->appendChild($element);
+
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $xml, $function, $this->formatName);
+
+    return $xml->saveXML();
+  }
+
+  /**
+   * Creates a new resource.
+   */
+  public function createResource($resourceController, $data) {
+    $values = $this->unserialize($resourceController->propertyInfo(), $data);
+    $id = $resourceController->create($values);
+
+    $xml = new DOMDocument('1.0', 'utf-8');
+    $element = $xml->createElement('uri');
+    self::setXMLReference($element, $resourceController->resource(), $id);
+    $xml->appendChild($element);
+
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $xml, $function, $this->formatName);
+
+    return $xml->saveXML();
+  }
+
+  /**
+   * Overrides RestWSBaseFormat::queryResource().
+   */
+  public function queryResource($resourceController, $payload) {
+    $xml = new DOMDocument('1.0', 'utf-8');
+    $element = $xml->createElement('list');
+
+    $rest_controls = restws_meta_controls();
+    $parameters = drupal_get_query_parameters();
+    $properties = $resourceController->propertyInfo();
+    $split_parameters = $this->splitParameters($properties, $parameters);
+
+    $links = $this->generateQueryURIs($resourceController, $parameters, $split_parameters['filters']);
+
+    foreach ($links as $rel => $link) {
+      $item = $xml->createElement('link');
+      $item->setAttribute('rel', $rel);
+      $item->setAttribute('href', $link);
+      $element->appendChild($item);
+    }
+
+    $full = (isset($split_parameters['meta_controls'][$rest_controls['full']])) ? $split_parameters['meta_controls'][$rest_controls['full']] : 1;
+
+    $result = $resourceController->query($split_parameters['filters'], $split_parameters['meta_controls']);
+
+    if ($full === '0') {
+      foreach ($result as $id) {
+        $item = $xml->createElement($resourceController->resource());
+        self::setXMLReference($item, $resourceController->resource(), $id);
+        $element->appendChild($item);
+      }
+    }
+    else {
+      foreach ($result as $id) {
+        $item = $xml->createElement($resourceController->resource());
+        self::addToXML($xml, $item, $resourceController->wrapper($id));
+        $element->appendChild($item);
+      }
+    }
+
+    $xml->appendChild($element);
+
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $xml, $function, $this->formatName);
+
+    return $xml->saveXML();
+  }
+
+  public function serialize($data) {
+    // Return an empty XML document.
+    $xml = new DOMDocument('1.0', 'utf-8');
+    return $xml->saveXML();
+  }
+
+  public function unserialize($properties, $data) {
+    $xml = simplexml_load_string($data);
+    return $this->xmlToArray($properties, $xml);
+  }
+
+  /**
+   * Turns the xml structure into an array of values.
+   */
+  public function xmlToArray($properties, SimpleXMLElement $xml, $listItemType = NULL) {
+    foreach ($xml->children() as $name => $element) {
+      // Check if we are processing an entity, an item from a list or a list.
+      if ((isset($properties[$name]['type']) && (entity_property_list_extract_type($properties[$name]['type']) || entity_get_info($properties[$name]['type'])))  || isset($listItemType)) {
+        // If we are processing a list, then set the type of the list and save
+        // the results into a a numeric array.
+        if (isset($listItemType)) {
+          $type = $listItemType;
+          $result_pointer = &$result[];
+        }
+        else {
+          $type = $properties[$name]['type'];
+          $result_pointer = &$result[$name];
+        }
+
+        // Check if the type is a list.
+        if (entity_property_list_extract_type($type)) {
+          $result_pointer = $this->xmlToArray($properties, $element, entity_property_list_extract_type($type));
+        }
+        else {
+          $attributes = $element->attributes();
+          $values['id'] = (string)$attributes['id'];
+          $values['resource'] = (string)$attributes['resource'];
+          $values['uri'] = $this->xmlToArray($properties, $element);
+          $id = $this->getResourceReferenceValue($type, $values);
+          // If an id could be extracted, then a resource array was send.
+          if ($id !== FALSE) {
+            $result_pointer = $id;
+          }
+          else {
+            // If no ID could be extracted, then save the inner text content of
+            // the node, which is saved in the $values['uri'].
+            $result_pointer = $values['uri'];
+          }
+        }
+      }
+      else {
+        $result[$name] = $this->xmlToArray($properties, $element);
+      }
+      foreach ($xml->attributes() as $attribute_name => $attribute_value) {
+        $result[$attribute_name] = $attribute_value;
+      }
+    }
+    if (!isset($result)) {
+      $result = ($string = (string) $xml) ? $string : NULL;
+    }
+    return $result;
+  }
+
+  /**
+   * Adds the data of the given wrapper to the given XML element.
+   */
+  public static function addToXML(DOMDocument $doc, DOMNode $parent, $wrapper) {
+    $filtered = restws_property_access_filter($wrapper);
+    foreach ($filtered as $name => $property) {
+      try {
+        if ($property instanceof EntityDrupalWrapper) {
+          // For referenced entities only return the URI.
+          if ($id = $property->getIdentifier()) {
+            $element = $doc->createElement(is_numeric($name) ? 'item' : $name);
+            $parent->appendChild($element);
+            self::setXMLReference($element, $property->type(), $id);
+          }
+        }
+        elseif ($property instanceof EntityValueWrapper) {
+          // Only primitive data types are allowed here. There might be complex
+          // arrays/objects in EntityValueWrapper if no property information is
+          // provided (example: the "data" property of commerce_price fields.
+          if (is_scalar($property->value())) {
+            $escaped = $doc->createTextNode($property->value());
+            $element = $doc->createElement(is_numeric($name) ? 'item' : $name);
+            $element->appendChild($escaped);
+            $parent->appendChild($element);
+          }
+        }
+        elseif ($property instanceof EntityListWrapper || $property instanceof EntityStructureWrapper) {
+          $element = $doc->createElement(is_numeric($name) ? 'item' : $name);
+          $parent->appendChild($element);
+          self::addToXML($doc, $element, $property);
+        }
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // A property causes problems - ignore that.
+      }
+    }
+  }
+
+  public static function setXMLReference(DOMElement $node, $resource, $id) {
+    $node->nodeValue = restws_resource_uri($resource, $id);
+    $node->setAttribute('resource', $resource);
+    $node->setAttribute('id', $id);
+  }
+}
+
+/**
+ * A simple formatter for RDF. Requires the RDF module for the mapping.
+ */
+class RestWSFormatRDF extends RestWSBaseFormat {
+
+  protected $namespaces;
+
+  public function __construct($name, $info) {
+    parent::__construct($name, $info);
+    $this->namespaces = rdf_get_namespaces();
+    $this->namespaces['rdf'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+  }
+
+  /**
+   * Gets the representation of a resource.
+   */
+  public function viewResource($resourceController, $id) {
+    $xml = new DOMDocument('1.0', 'utf-8');
+    $rdf_element = $xml->createElementNS($this->namespaces['rdf'], 'rdf:RDF');
+    $xml->appendChild($rdf_element);
+
+    $element = $xml->createElementNS($this->namespaces['rdf'], 'rdf:Description');
+    $element->setAttributeNS($this->namespaces['rdf'], 'rdf:about', restws_resource_uri($resourceController->resource(), $id));
+
+    // Add the RDF type of the resource if there is a mapping.
+    $entity = $resourceController->read($id);
+    if (!empty($entity->rdf_mapping['rdftype'])) {
+      foreach ($entity->rdf_mapping['rdftype'] as $rdf_type) {
+        $type_element = $xml->createElementNS($this->namespaces['rdf'], 'rdf:type');
+        list($ns, $name) = explode(':', $rdf_type);
+        $type_element->setAttributeNS($this->namespaces['rdf'], 'rdf:resource', $this->namespaces[$ns] . $name);
+        $element->appendChild($type_element);
+      }
+    }
+
+    $this->addToXML($xml, $element, $resourceController->wrapper($id));
+    $rdf_element->appendChild($element);
+
+    $function = __FUNCTION__;
+    drupal_alter('restws_response', $xml, $function, $this->formatName);
+
+    return $xml->saveXML();
+  }
+
+  public function createResource($resourceController, $data) {
+    throw new RestWSException('Not implemented', 501);
+  }
+
+  public function updateResource($resourceController, $id, $data) {
+    throw new RestWSException('Not implemented', 501);
+  }
+
+  public function queryResource($resourceController, $parameters) {
+    throw new RestWSException('Not implemented', 501);
+  }
+
+  /**
+   * Adds the data of the given wrapper to the given XML element.
+   */
+  public function addToXML(DOMDocument $doc, DOMNode $parent, $wrapper) {
+    $filtered = restws_property_access_filter($wrapper);
+    foreach ($filtered as $name => $property) {
+      try {
+        if ($property instanceof EntityDrupalWrapper) {
+          // For referenced entities only return the URI.
+          if ($id = $property->getIdentifier()) {
+            $element = $this->addRdfElement($doc, $wrapper, $name);
+            $parent->appendChild($element);
+            $this->addReference($doc, $element, $property->type(), $id);
+          }
+        }
+        elseif ($property instanceof EntityValueWrapper) {
+          $element = $this->addRdfElement($doc, $wrapper, $name);
+          $parent->appendChild($element);
+          $element->nodeValue = $property->value();
+        }
+        elseif ($property instanceof EntityListWrapper || $property instanceof EntityStructureWrapper) {
+          $element = $this->addRdfElement($doc, $wrapper, $name);
+          $parent->appendChild($element);
+          $node = $doc->createElementNS($this->namespaces['rdf'], 'rdf:Description');
+          $element->appendChild($node);
+          $this->addToXML($doc, $node, $property);
+        }
+      }
+      catch (EntityMetadataWrapperException $e) {
+        // A property causes problems - ignore that.
+      }
+    }
+  }
+
+  public function addReference(DomDocument $doc, DOMElement $node, $resource, $id) {
+    $element = $doc->createElementNS($this->namespaces['rdf'], 'rdf:Description');
+    $element->setAttributeNS($this->namespaces['rdf'], 'rdf:about', restws_resource_uri($resource, $id));
+    $node->appendChild($element);
+  }
+
+  /**
+   * Adds an RDF element for the given property of the wrapper using the RDF
+   * mapping.
+   */
+  public function addRdfElement(DOMDOcument $doc, EntityMetadataWrapper $wrapper, $name) {
+    if ($wrapper instanceof EntityDrupalWrapper) {
+      $entity = $wrapper->value();
+      if (!empty($entity->rdf_mapping[$name])) {
+        // Just make use of the first predicate for now.
+        $predicate = reset($entity->rdf_mapping[$name]['predicates']);
+        list($ns, $qname) = explode(':', $predicate);
+        $element = $doc->createElementNS($this->namespaces[$ns], $predicate);
+
+        if (!empty($entity->rdf_mapping[$name]['datatype'])) {
+          $element->setAttributeNS($this->namespaces['rdf'], 'rdf:datatype', $entity->rdf_mapping[$name]['datatype']);
+        }
+      }
+    }
+    if (!isset($element)) {
+      // For other elements just use the site URL as namespace.
+      $element = $doc->createElementNS(url('', array('absolute' => TRUE)), 'site:' . (is_numeric($name) ? 'item' : $name));
+    }
+    return $element;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = RESTful web services
+description = Provides RESTful web services.
+core = 7.x
+files[] = restws.entity.inc
+files[] = restws.formats.inc
+files[] = restws.test
+dependencies[] = entity
+
+; Information added by drupal.org packaging script on 2013-08-07
+version = "7.x-2.1"
+core = "7.x"
+project = "restws"
+datestamp = "1375888987"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Install, update, and uninstall functions for the RESTWS module.
+ */
+
+/**
+ * Clear the page cache to throw out any RESTWS responses that could be
+ * delivered on HTML requests.
+ */
+function restws_update_7001() {
+  cache_clear_all(NULL, 'cache_page');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,557 @@
+<?php
+
+/**
+ * @file
+ * RESTful web services module.
+ */
+
+/**
+ * Returns info about all defined resources.
+ *
+ * @param string $resource
+ *   By default null, else the info for the given resource will be returned.
+ */
+function restws_get_resource_info($resource = NULL) {
+  $info = &drupal_static(__FUNCTION__);
+  if (!isset($info)) {
+    $info = module_invoke_all('restws_resource_info');
+    drupal_alter('restws_resource_info', $info);
+  }
+  if (!empty($resource)) {
+    return $info[$resource];
+  }
+  return $info;
+}
+
+/**
+ * Returns info about all defined formats.
+ */
+function restws_get_format_info() {
+  $info = &drupal_static(__FUNCTION__);
+  if (!isset($info)) {
+    $info = module_invoke_all('restws_format_info');
+    drupal_alter('restws_format_info', $info);
+  }
+  return $info;
+}
+
+/**
+ * Implements hook_restws_resource_info().
+ *
+ * Provides resources for all entity types.
+ */
+function restws_restws_resource_info() {
+  foreach (entity_get_info() as $entity_type => $info) {
+    $result[$entity_type] = array(
+      'label' => $info['label'],
+      'class' => 'RestWSEntityResourceController',
+    );
+  }
+  return $result;
+}
+
+/**
+ * Returns a instance of a resource controller.
+ *
+ * @return RestWSResourceControllerInterface
+ *   A resource controller object.
+ */
+function restws_resource_controller($name) {
+  $static = &drupal_static(__FUNCTION__);
+  if (!isset($static[$name])) {
+    $info = restws_get_resource_info();
+    $static[$name] = isset($info[$name]) ? new $info[$name]['class']($name, $info[$name]) : FALSE;
+  }
+  return $static[$name];
+}
+
+/**
+ * Implements hook_restws_format_info().
+ *
+ * Provides basic formats.
+ */
+function restws_restws_format_info() {
+  $result = array(
+    'json' => array(
+      'label' => t('JSON'),
+      'class' => 'RestWSFormatJSON',
+      'mime type' => 'application/json',
+    ),
+    'xml' => array(
+      'label' => t('XML'),
+      'class' => 'RestWSFormatXML',
+      'mime type' => 'application/xml',
+    ),
+  );
+  if (module_exists('rdf')) {
+    $result['rdf'] = array(
+      'label' => t('RDF'),
+      'class' => 'RestWSFormatRDF',
+      'mime type' => 'application/rdf+xml',
+    );
+  }
+  return $result;
+}
+
+/**
+ * Returns an instance of a format.
+ *
+ * @return RestWSFormatInterface
+ *   A resource format object.
+ */
+function restws_format($name) {
+  $static = &drupal_static(__FUNCTION__);
+  if (!isset($static[$name])) {
+    $info = restws_get_format_info();
+    $static[$name] = isset($info[$name]) ? new $info[$name]['class']($name, $info[$name]) : FALSE;
+  }
+  return $static[$name];
+}
+
+/**
+ * Handles a request.
+ *
+ * @param string $op
+ *   One of 'create', 'update', 'delete' or 'view'.
+ */
+function restws_handle_request($op, $format, $resource_name, $id = NULL, $payload = NULL) {
+  if ($resource = restws_resource_controller($resource_name)) {
+    // Allow other modules to change the web service request or react upon it.
+    $request = array(
+      'op' => &$op,
+      'format' => &$format,
+      'resource' => &$resource,
+      'id' => &$id,
+      'payload' => &$payload,
+    );
+    drupal_alter('restws_request', $request);
+
+    // Since there is no access callback for query we need to use view.
+    $access_op = $op == 'query' ? 'view' : $op;
+
+    if (user_access('access resource ' . $resource_name) && $resource->access($access_op, $id)) {
+      try {
+        $method = $op . 'Resource';
+        if ($op == 'create') {
+          print $format->$method($resource, $payload);
+          drupal_add_http_header('Status', '201 Created');
+        }
+        elseif ($op == 'query') {
+          if (!$resource instanceof RestWSQueryResourceControllerInterface) {
+            throw new RestWSException('Quering not available for this resources', 501);
+          }
+          print $format->$method($resource, $payload);
+        }
+        else {
+          print $format->$method($resource, $id, $payload);
+        }
+        drupal_add_http_header('Content-Type', $format->mimeType());
+      }
+      catch (RestWSException $e) {
+        echo check_plain($e->getHTTPError()) . ': ' . check_plain($e->getMessage());
+        drupal_add_http_header('Status', $e->getHTTPError());
+      }
+    }
+    else {
+      echo '403 Forbidden';
+      drupal_add_http_header('Status', '403 Forbidden');
+      watchdog('access denied', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
+    }
+  }
+  else {
+    echo '404 Not Found';
+    drupal_add_http_header('Status', '404 Not Found');
+  }
+  drupal_page_footer();
+  exit;
+}
+
+/**
+ * An exception defining the HTTP error code and message.
+ */
+class RestWSException extends Exception {
+
+  public function getHTTPError() {
+    $code = $this->getCode();
+    switch ($code) {
+      case 403:
+        return '403 Forbidden';
+      case 404:
+        return '404 Not Found';
+      case 406:
+        return '406 Not Acceptable';
+      case 412:
+        return '412 Precondition Failed';
+      case 422:
+        return '422 Unprocessable Entity';
+      default:
+        return '500 Internal Server Error';
+    }
+  }
+}
+
+/**
+ * Implements hook_menu_alter().
+ */
+function restws_menu_alter(&$items) {
+  foreach (restws_get_resource_info() as $resource => $info) {
+    // Resource full path (e.g. /node/% or /user/%) for accessing specific
+    // resources.
+    $menu_path = isset($info['menu_path']) ? $info['menu_path'] . '/%' : $resource . '/%';
+    // Replace existing page callbacks with our own (e.g. node/%)
+    if (isset($items[$menu_path])) {
+      // Prepend the page callback and the resource to the page arguments.
+      // So we can re-use it on standard HTML page requests.
+      array_unshift($items[$menu_path]['page arguments'], $resource, $items[$menu_path]['page callback']);
+      $items[$menu_path]['page callback'] = 'restws_page_callback';
+    }
+    // Also replace wildcard loaders (e.g. node/%node)
+    elseif (isset($items[$menu_path . $resource])) {
+      $menu_path = $menu_path . $resource;
+      array_unshift($items[$menu_path]['page arguments'], $resource, $items[$menu_path]['page callback']);
+      $items[$menu_path]['page callback'] = 'restws_page_callback';
+    }
+    else {
+      $items[$menu_path] = array(
+        'page callback' => 'restws_page_callback',
+        'page arguments' => array($resource),
+        'access callback' => TRUE,
+        'type' => MENU_CALLBACK,
+      );
+    }
+    // Resource base path (e.g. /node or /user) for creating resources.
+    $menu_path = isset($info['menu_path']) ? substr($menu_path, 0, strlen($menu_path) - 2) : $resource;
+
+    if (isset($items[$menu_path])) {
+      // Prepend the page callback and the resource to the page arguments.
+      if (!isset($items[$menu_path]['page arguments'])) {
+        $items[$menu_path]['page arguments'] = array();
+      }
+      array_unshift($items[$menu_path]['page arguments'], $resource, $items[$menu_path]['page callback']);
+      $items[$menu_path]['page callback'] = 'restws_page_callback';
+    }
+    else {
+      $items[$menu_path] = array(
+        'page callback' => 'restws_page_callback',
+        'page arguments' => array($resource),
+        'access callback' => TRUE,
+        'type' => MENU_CALLBACK,
+      );
+    }
+    // Querying menu paths.
+    foreach (array_keys(restws_get_format_info()) as $format) {
+      // Resource base path URLs with the suffixes (e.g. node.json or user.xml)
+      // for querying.
+      if (isset($items["$menu_path.$format"])) {
+        // Prepend the page callback and the resource to the page arguments.
+        if (!isset($items["$menu_path.$format"]['page arguments'])) {
+          $items["$menu_path.$format"]['page arguments'] = array();
+        }
+        array_unshift($items["$menu_path.$format"]['page arguments'], $resource, $items["$menu_path.$format"]['page callback']);
+        $items["$menu_path.$format"]['page callback'] = 'restws_page_callback';
+
+      }
+      else {
+        $items["$menu_path.$format"] = array(
+          'page callback' => 'restws_page_callback',
+          'page arguments' => array($resource),
+          'access callback' => TRUE,
+          'type' => MENU_CALLBACK,
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Menu page callback.
+ */
+function restws_page_callback($resource, $page_callback = NULL) {
+  $id_arg = arg(1);
+  $resource_arg = arg(0);
+  $format = FALSE;
+  $id = NULL;
+  // Check for an appended .format string on GET requests only to avoid CSRF
+  // attacks on POST requests.
+  if ($_SERVER['REQUEST_METHOD'] == 'GET' && ($pos = strpos($id_arg, '.')) && $format_name = substr($id_arg, $pos + 1)) {
+    $id = substr($id_arg, 0, $pos);
+    $format = restws_format($format_name);
+  }
+  elseif ($_SERVER['REQUEST_METHOD'] == 'GET' && ($pos = strpos($resource_arg, '.')) && $format_name = substr($resource_arg, $pos + 1)) {
+    $format = restws_format($format_name);
+  }
+  else {
+    $id = $id_arg;
+    switch ($_SERVER['REQUEST_METHOD']) {
+      case 'POST':
+      case 'PUT':
+        // Get format MIME type form HTTP Content type header.
+        $parts = explode(';', $_SERVER['CONTENT_TYPE'], 2);
+        $format = restws_format_mimetype($parts[0]);
+        break;
+
+      case 'DELETE':
+        if (isset($_SERVER['HTTP_ACCEPT'])) {
+          $parts = explode(',', $_SERVER['HTTP_ACCEPT'], 2);
+          $format = restws_format_mimetype($parts[0]);
+        }
+        if (!$format) {
+          // We don't care about the format, just pick JSON.
+          $format = restws_format('json');
+        }
+        break;
+
+      default:
+        // Get the format MIME type form the HTTP Accept header.
+        // Ignore requests from web browsers that accept HTML.
+        if (isset($_SERVER['HTTP_ACCEPT']) && strpos($_SERVER['HTTP_ACCEPT'], 'html') === FALSE) {
+          // Use the first MIME type.
+          $parts = explode(',', $_SERVER['HTTP_ACCEPT'], 2);
+          $format = restws_format_mimetype($parts[0]);
+        }
+        // Consumers should not use this URL if page caching is enabled.
+        // Drupal's page cache IDs are only determined by URL path, so this
+        // could poison the HTML page cache. A browser request to /node/1 could
+        // suddenly return JSON if the cache was primed with this RESTWS
+        // response.
+        if ($format && !isset($_COOKIE[session_name()]) && variable_get('cache')) {
+          // Redirect to the URL path containing the format name instead.
+          drupal_goto($_GET['q'] . '.' . $format->getName(), array(), 301);
+        }
+    }
+  }
+  if ($format) {
+    switch ($_SERVER['REQUEST_METHOD']) {
+      case 'POST':
+        $op = 'create';
+        break;
+
+      case 'PUT':
+        $op = 'update';
+        break;
+
+      case 'DELETE':
+        $op = 'delete';
+        break;
+
+      default:
+        if (!empty($id)) {
+          $op = 'view';
+        }
+        else {
+          $op  = 'query';
+        }
+    }
+
+    // CSRF protection on write operations.
+    if (!in_array($_SERVER['REQUEST_METHOD'], array('GET', 'HEAD', 'OPTIONS', 'TRACE')) && !restws_csrf_validation()) {
+      echo '403 Access Denied: CSRF validation failed';
+      drupal_add_http_header('Status', '403 Forbidden');
+      drupal_page_footer();
+      exit;
+    }
+
+    $payload = file_get_contents('php://input');
+    if ($file = variable_get('restws_debug_log')) {
+      $log = date(DATE_ISO8601) . "\n";
+      $log .= 'Resource: ' . $resource . "\n";
+      $log .= 'Operation: ' . $op . "\n";
+      $log .= 'Format: ' . $format->mimeType() . "\n";
+      $log .= 'Id: ' . $id . "\n";
+      $log .= 'Payload: ' . $payload . "\n";
+      $log .= "----------------------------------------------------------------\n";
+      file_put_contents($file, $log, FILE_APPEND);
+    }
+    restws_handle_request($op, $format, $resource, $id, $payload);
+  }
+
+  // @todo: Determine human readable URIs and redirect, if there is no
+  // page callback.
+  if (isset($page_callback)) {
+    // Further page callback arguments have been appended to our arguments.
+    $args = func_get_args();
+    return call_user_func_array($page_callback, array_slice($args, 2));
+  }
+  echo '404 Not Found';
+  drupal_add_http_header('Status', '404 Not Found');
+  drupal_page_footer();
+  exit;
+}
+
+/**
+ * Returns the URI used for the given resource.
+ *
+ * @param string $resource
+ *   The resource for which the URI should be returned.
+ * @param int $id
+ *   The resource ID or NULL if only the base path should be returned.
+ * @param array $options
+ *   Optional array that is passed to url().
+ */
+function restws_resource_uri($resource, $id = NULL, array $options = array()) {
+  $info = restws_get_resource_info($resource);
+  $basepath = isset($info['menu_path']) ? $info['menu_path'] : $resource;
+  $sub_path = isset($id) ? "/$id" : '';
+
+  // Avoid having the URLs aliased.
+  $base_options = array('absolute' => TRUE, 'alias' => TRUE);
+  $options += $base_options;
+
+  return url($basepath . $sub_path, $options);
+}
+
+/**
+ * Returns the format instance for a given MIME type.
+ *
+ * @param string $mime
+ *   The MIME type, e.g. 'application/json' or 'application/xml'.
+ *
+ * @return bool|RestWSFormatInterface
+ *   The format controller or FALSE if the format was not found.
+ */
+function restws_format_mimetype($mime) {
+  foreach (restws_get_format_info() as $format_name => $info) {
+    if ($info['mime type'] == $mime) {
+      return restws_format($format_name);
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function restws_permission() {
+  $permissions = array();
+  // Create service access permissions per resource type.
+  foreach (restws_get_resource_info() as $type => $info) {
+    $permissions['access resource ' . $type] = array(
+      'title' => t('Access the resource %resource', array('%resource' => $type)),
+    );
+  }
+  return $permissions;
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ */
+function restws_module_implements_alter(&$implementations, $hook) {
+  // Make sure that restws runs last.
+  // @todo remove entity_info_alter once https://drupal.org/node/1780646 is fixed.
+  if ($hook == 'menu_alter' || $hook == 'entity_info_alter') {
+    $group = $implementations['restws'];
+    unset($implementations['restws']);
+    $implementations['restws'] = $group;
+  }
+}
+
+/**
+ * Return all available meta controls.
+ */
+function restws_meta_controls() {
+  return array(
+    'sort' => 'sort',
+    'direction' => 'direction',
+    'page' => 'page',
+    'limit' => 'limit',
+    'full' => 'full',
+  );
+}
+
+/**
+ * Ensures that a request with cookies has the required CSRF header set.
+ *
+ * @return bool
+ *   TRUE if the request passed the CSRF protection, FALSE otherwise.
+ */
+function restws_csrf_validation() {
+  // This check only applies if the user was successfully authenticated and the
+  // request comes with a session cookie.
+  if (user_is_logged_in() && !empty($_COOKIE[session_name()])) {
+    return isset($_SERVER['HTTP_X_CSRF_TOKEN']) && drupal_valid_token($_SERVER['HTTP_X_CSRF_TOKEN'], 'restws');
+  }
+  return TRUE;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function restws_menu() {
+  $items['restws/session/token'] = array(
+    'page callback' => 'restws_session_token',
+    // Only authenticated users are allowed to retrieve a session token.
+    'access callback' => 'user_is_logged_in',
+    'type' => MENU_CALLBACK,
+  );
+  return $items;
+}
+
+/**
+ * Page callback: returns a session token for the currently active user.
+ */
+function restws_session_token() {
+  drupal_add_http_header('Content-Type', 'text/plain');
+  print drupal_get_token('restws');
+  drupal_exit();
+}
+
+/**
+ * Access callback for the node entity.
+ *
+ * Replacement for entity_metadata_no_hook_node_access() because it does not
+ * work with the create operation.
+ *
+ * @todo Remove this once https://drupal.org/node/1780646 is fixed.
+ *
+ * @see restws_entity_info_alter()
+ * @see entity_metadata_no_hook_node_access()
+ */
+function restws_entity_node_access($op, $node = NULL, $account = NULL) {
+  // First deal with the case where a $node is provided.
+  if (isset($node)) {
+    // Ugly hack to handle field access, because entity_api does not distinguish
+    // between 'create' and 'update' permissions for fields. This should rather
+    // be fixed in EntityStructureWrapper::propertyAccess() (entity.wrapper.inc).
+    if ($op == 'update' && empty($node->nid)) {
+      $op = 'create';
+    }
+    if ($op == 'create') {
+      if (isset($node->type)) {
+        return node_access($op, $node->type, $account);
+      }
+      else {
+        throw new EntityMalformedException('Permission to create a node was requested but no node type was given.');
+      }
+    }
+    // If a non-default revision is given, incorporate revision access.
+    $default_revision = node_load($node->nid);
+    if ($node->vid !== $default_revision->vid) {
+      return _node_revision_access($node, $op, $account);
+    }
+    else {
+      return node_access($op, $node, $account);
+    }
+  }
+  // No node is provided. Check for access to all nodes.
+  if (user_access('bypass node access', $account)) {
+    return TRUE;
+  }
+  if (!user_access('access content', $account)) {
+    return FALSE;
+  }
+  if ($op == 'view' && node_access_view_all_nodes($account)) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * Implements hook_entity_info_alter().
+ *
+ * @todo Remove this once https://drupal.org/node/1780646 is fixed.
+ */
+function restws_entity_info_alter(&$info) {
+  // In order for this to work we have to make sure we run after entity_api.
+  // @see restws_module_implements_alter().
+  $info['node']['access callback'] = 'restws_entity_node_access';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,634 @@
+<?php
+
+/**
+ * @file
+ * RESTful web services tests.
+ */
+
+class RestWSTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'RESTful web services tests',
+      'description' => 'Tests CRUD operations via the REST web service.',
+      'group' => 'Services',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('restws');
+  }
+
+  /**
+   * CRUD tests for nodes.
+   */
+  public function testCRUD() {
+    // Test Read.
+    $title = $this->randomName(8);
+    $node = $this->drupalCreateNode(array('title' => $title));
+    $account = $this->drupalCreateUser(array('access resource node'));
+    $this->drupalLogin($account);
+    $result = $this->httpRequest('node/' . $node->nid . '.json', 'GET', $account);
+    $node_array = drupal_json_decode($result);
+    $this->assertEqual($node->title, $node_array['title'], 'Node title was received correctly.');
+    $this->assertResponse('200', 'HTTP response code is correct.');
+    $this->assertEqual(curl_getinfo($this->curlHandle, CURLINFO_CONTENT_TYPE), 'application/json', 'HTTP content type is correct.');
+
+    // Test Create.
+    $account = $this->drupalCreateUser(array('access content',
+      'bypass node access', 'access resource node'));
+    $title = $this->randomName(8);
+    $new_node = array(
+      'body'      => array(LANGUAGE_NONE => array(array())),
+      'title'     => $title,
+      'type'      => 'page',
+      'author'    => $account->uid,
+    );
+    $json = drupal_json_encode($new_node);
+    $result = $this->httpRequest('node', 'POST', $account, $json);
+    $result_array = drupal_json_decode($result);
+    $nid = $result_array['id'];
+    $node = node_load($nid);
+    $this->assertEqual($title, $node->title, 'Node title in DB is equal to the new title.');
+    $this->assertResponse('201', 'HTTP response code is correct.');
+    $this->assertEqual(curl_getinfo($this->curlHandle, CURLINFO_CONTENT_TYPE), 'application/json', 'HTTP content type is correct.');
+
+    // Test Update.
+    $new_title = $this->randomName(8);
+    $json = drupal_json_encode(array('title' => $new_title));
+    $this->httpRequest('node/' . $node->nid, 'PUT', $account, $json);
+    // Clear the static cache, otherwise we won't see the update.
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertEqual($new_title, $node->title, 'Node title in DB is equal to the updated title.');
+    $this->assertResponse('200', 'HTTP response code is correct.');
+    $this->assertEqual(curl_getinfo($this->curlHandle, CURLINFO_CONTENT_TYPE), 'application/json', 'HTTP content type is correct.');
+
+    // Test delete.
+    $this->httpRequest('node/' . $node->nid, 'DELETE', $account);
+    // Clear the static cache, otherwise we won't see the update.
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertFalse($node, 'Node is not in the DB anymore.');
+    $this->assertResponse('200', 'HTTP response code is correct.');
+    $this->assertEqual(curl_getinfo($this->curlHandle, CURLINFO_CONTENT_TYPE), 'application/json', 'HTTP content type is correct.');
+  }
+
+  /**
+   * Tests bad requests.
+   */
+  public function testBadRequests() {
+    // Assure that nodes without types won't be created.
+    $account = $this->drupalCreateUser(array('access content', 'bypass node access', 'access resource node', 'administer users'));
+    $title = $this->randomName(8);
+    $new_node = array(
+      'body'  => array(LANGUAGE_NONE => array(array())),
+      'title' => $title,
+    );
+    $json = drupal_json_encode($new_node);
+    $result = $this->httpRequest('node', 'POST', $account, $json);
+    $node = entity_load('node', FALSE, array('title' => $title));
+    $this->assertEqual(count($node), 0, "Node wasn't created");
+
+    $this->assertResponse('406', 'Missing bundle: type');
+  }
+
+  /**
+   * Tests access to restricted input formats.
+   */
+  public function testBadInputFormat() {
+    module_enable(array('php'));
+    // Reset the cache of valid permissions so that the PHP code format
+    // permission exists.
+    $this->checkPermissions(array(), TRUE);
+
+    // Assure that users can't create nodes with unauthorized input formats.
+    $unprivileged_account = $this->drupalCreateUser(array('bypass node access', 'access resource node'));
+    $title = $this->randomName(8);
+    $new_node = array(
+      'body'  => array(
+        'value' => $this->randomName(30),
+        'format' => 'php_code',
+      ),
+      'title' => $title,
+      'type' => 'page',
+    );
+    $json = drupal_json_encode($new_node);
+    $result = $this->httpRequest('node', 'POST', $unprivileged_account, $json);
+    $this->assertResponse('403');
+    $this->assertEqual($result, '403 Forbidden: Not authorized to set property body');
+    $node = entity_load('node', FALSE, array('title' => $title));
+    $this->assertEqual(count($node), 0, "Node with unauthorized input format wasn't created");
+
+    // Check that the format is allowed if the permission is present.
+    $privileged_account = $this->drupalCreateUser(array('bypass node access', 'access resource node', 'use text format php_code'));
+    $this->httpRequest('node', 'POST', $privileged_account, $json);
+    $this->assertResponse('201');
+
+    $node = entity_load('node', FALSE, array('title' => $title));
+    $this->assertEqual(count($node), 1, "Node was created");
+    $node = reset($node);
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $new_node['body']['value'], 'The new node body has the correct value');
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['format'], 'php_code', 'The new node has the correct format');
+
+    // Check that users can't update nodes with unauthorized input formats.
+    $node->body[LANGUAGE_NONE][0]['format'] = 'filtered_html';
+    node_save($node);
+
+    $new_body = $this->randomName(30);
+    $update = array(
+      'body'  => array(
+        'value' => $new_body,
+        'format' => 'php_code',
+      ),
+    );
+    $json = drupal_json_encode($update);
+    $result = $this->httpRequest('node/1', 'PUT', $unprivileged_account, $json);
+    $this->assertResponse('403');
+    $this->assertEqual($result, '403 Forbidden: Not authorized to set property body');
+    $node = node_load(1, NULL, TRUE);
+    $this->assertNotEqual($node->body[LANGUAGE_NONE][0]['value'], $new_body);
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['format'], 'filtered_html');
+
+    // Check that the format is allowed if the permission is present.
+    $this->httpRequest('node/1', 'PUT', $privileged_account, $json);
+    $this->assertResponse('200');
+    $node = node_load(1, NULL, TRUE);
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['value'], $new_body);
+    $this->assertEqual($node->body[LANGUAGE_NONE][0]['format'], 'php_code');
+  }
+
+  /**
+   * Test field level access restrictions.
+   *
+   * @see restws_test_field_access()
+   */
+  public function testFieldAccess() {
+    module_enable(array('restws_test'));
+
+    // Add text field to nodes.
+    $field_info = array(
+      'field_name' => 'field_text',
+      'type' => 'text',
+      'entity_types' => array('node'),
+    );
+    field_create_field($field_info);
+
+    $instance = array(
+      'label' => 'Text Field',
+      'field_name' => 'field_text',
+      'entity_type' => 'node',
+      'bundle' => 'page',
+      'settings' => array(),
+      'required' => FALSE,
+    );
+    field_create_instance($instance);
+
+    // A user without the "administer users" permission should not be able to
+    // create a node with the access protected field.
+    $unprivileged_account = $this->drupalCreateUser(array('bypass node access', 'access resource node'));
+    $title = $this->randomName(8);
+    $new_node = array(
+      'title' => $title,
+      'type' => 'page',
+      'field_text' => 'test',
+    );
+    $json = drupal_json_encode($new_node);
+    $this->httpRequest('node', 'POST', $unprivileged_account, $json);
+    $this->assertResponse('403');
+    $nodes = entity_load('node', FALSE, array('title' => $title));
+    $this->assertEqual(count($nodes), 0, "Node with access protected field wasn't created");
+
+    // Test again with the additional permission, this should work now.
+    $privileged_account = $this->drupalCreateUser(array('bypass node access', 'access resource node', 'administer users'));
+    $this->httpRequest('node', 'POST', $privileged_account, $json);
+    $this->assertResponse('201');
+    $node = node_load(1, NULL, TRUE);
+    $this->assertEqual($node->field_text[LANGUAGE_NONE][0]['value'], 'test');
+
+    // Update test: unpriviledged users should not be able to change the
+    // protected field.
+    $update = array('field_text' => 'newvalue');
+    $json = drupal_json_encode($update);
+    $result = $this->httpRequest('node/1', 'PUT', $unprivileged_account, $json);
+    $this->assertResponse('403');
+    $this->assertEqual($result, '403 Forbidden: Not authorized to set property field_text');
+    $node = node_load(1, NULL, TRUE);
+    $this->assertEqual($node->field_text[LANGUAGE_NONE][0]['value'], 'test');
+
+    // Check that the update is allowed if the permission is present.
+    $this->httpRequest('node/1', 'PUT', $privileged_account, $json);
+    $this->assertResponse('200');
+    $node = node_load(1, NULL, TRUE);
+    $this->assertEqual($node->field_text[LANGUAGE_NONE][0]['value'], 'newvalue');
+  }
+
+  /**
+   * Test entity references with an array which contains id, entity type.
+   */
+  public function testResourceArray() {
+    $account = $this->drupalCreateUser(array(
+      'access content', 'bypass node access', 'access resource node',
+    ));
+    $this->drupalLogin($account);
+    $this->createTerm("foo");
+    $this->createTerm("bar");
+
+    // Test json create.
+    $title = $this->randomName(8);
+    $new_node = array(
+      'body' => array(LANGUAGE_NONE => array(array())),
+      'type' => 'article',
+      'title' => 'foo',
+      'field_tags' => array(
+        array(
+          'id' => '2', 'resource' => 'taxonomy_term',
+        ), array(
+          'id' => '1', 'resource' => 'taxonomy_term',
+        ),
+      ),
+      'author' => array(
+        'id' => $account->uid, 'resource' => 'user',
+      ),
+    );
+    $json = drupal_json_encode($new_node);
+    $result = $this->httpRequest('node', 'POST', $account, $json);
+    $result_array = drupal_json_decode($result);
+    $nid = $result_array['id'];
+    $node = node_load($nid);
+    $this->assertEqual($node->field_tags[LANGUAGE_NONE][0]['tid'], 2, 'Taxonomy term 1 was correctly added.');
+    $this->assertEqual($node->field_tags[LANGUAGE_NONE][1]['tid'], 1, 'Taxonomy term 2 was correctly added.');
+
+    // Test XML update.
+    $xml = '
+      <node>
+        <title>bar</title>
+        <type>article</type>
+        <author resource="user" id="' . $account->uid . '">' . restws_resource_uri('user', $account->uid) . '</author>
+        <field_tags>
+          <item resource="taxonomy_term" id="1">' . restws_resource_uri('taxonomy_term', 1) . '</item>
+          <item resource="taxonomy_term" id="2">' . restws_resource_uri('taxonomy_term', 2) . '</item>
+        </field_tags>
+      </node>';
+    $result = $this->httpRequest('node/' . $nid, 'PUT', $account, $xml, 'xml');
+    $node = node_load($nid, NULL, TRUE);
+    $this->assertEqual($node->field_tags[LANGUAGE_NONE][0]['tid'], 1, 'Taxonomy term 1 was correctly updated.');
+    $this->assertEqual($node->field_tags[LANGUAGE_NONE][1]['tid'], 2, 'Taxonomy term 2 was correctly updated.');
+
+    // Test XML create.
+    $result = $this->httpRequest('node', 'POST', $account, $xml, 'xml');
+    $xml_element = simplexml_load_string($result);
+    $nid = $xml_element->attributes()->id;
+    $node = node_load((int) $nid, NULL, TRUE);
+    $this->assertEqual($node->field_tags[LANGUAGE_NONE][0]['tid'], 1, 'Taxonomy term 1 was correctly added.');
+    $this->assertEqual($node->field_tags[LANGUAGE_NONE][1]['tid'], 2, 'Taxonomy term 2 was correctly added.');
+  }
+
+  /**
+   * Tests using the xml formatter.
+   */
+  public function testXmlFormatter() {
+    // Test Read.
+    $account = $this->drupalCreateUser(array('access content',
+      'bypass node access', 'access resource node')
+    );
+    $this->drupalLogin($account);
+    $title = $this->randomName(8);
+    $node = $this->drupalCreateNode(array('title' => $title));
+
+    $result = $this->drupalGet("node/$node->nid", array(), array('Accept: application/xml'));
+    $this->assertRaw("<title>$title</title>", 'XML has been generated.');
+
+    // Test update.
+    $new_title = 'foo';
+    $result = $this->httpRequest('node/' . $node->nid, 'PUT', $account, "<node><title>$new_title</title></node>", 'xml');
+    // Clear the static cache, otherwise we won't see the update.
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertEqual($new_title, $node->title, 'Node title in DB is equal to the updated title.');
+    $this->assertResponse('200', 'HTTP response code is correct.');
+    $this->assertEqual(curl_getinfo($this->curlHandle, CURLINFO_CONTENT_TYPE), 'application/xml', 'HTTP content type is correct.');
+  }
+
+  /**
+   * Test requests to non-existing resources and other errors.
+   */
+  public function testErrors() {
+    // Read non-existing resource.
+    $random_nid = rand(1, 1000);
+    $result = $this->httpRequest('node/' . $random_nid, 'GET');
+    $this->assertResponse('404', 'HTTP response code is correct.');
+
+    // Update a node with an unknown property.
+    $account = $this->drupalCreateUser(array('access content',
+      'bypass node access', 'access resource node')
+    );
+    $node = $this->drupalCreateNode();
+    $property_name = $this->randomName(8);
+    $json = drupal_json_encode(array($property_name => $property_name));
+    $result = $this->httpRequest('node/' . $node->nid, 'PUT', $account, $json);
+    $this->assertEqual($result, "406 Not Acceptable: Unknown data property $property_name.", 'Response body is correct');
+    $this->assertResponse('406', 'HTTP response code is correct.');
+
+    // Create a node with an unknown property.
+    $title = $this->randomName(8);
+    $new_node = array(
+      'body'      => array(LANGUAGE_NONE => array(array())),
+      'title'     => $this->randomName(8),
+      'type'      => 'page',
+      'author'    => $account->uid,
+      $property_name => $property_name,
+    );
+    $json = drupal_json_encode($new_node);
+    $result = $this->httpRequest('node', 'POST', $account, $json);
+    $this->assertEqual($result, "406 Not Acceptable: Unknown data property $property_name.", 'Response body is correct');
+    $this->assertResponse('406', 'HTTP response code is correct.');
+
+
+    // Simulate a CSRF attack without the required token.
+    $new_title = 'HACKED!';
+    $json = drupal_json_encode(array('title' => $new_title));
+    $this->curlExec(array(
+      CURLOPT_HTTPGET => FALSE,
+      CURLOPT_POST => TRUE,
+      CURLOPT_CUSTOMREQUEST => 'POST',
+      CURLOPT_POSTFIELDS => $json,
+      CURLOPT_URL => url('node/' . $node->nid, array('absolute' => TRUE)),
+      CURLOPT_NOBODY => FALSE,
+      CURLOPT_HTTPHEADER => array('Content-Type: application/json'),
+    ));
+    $this->assertResponse(403);
+    // Clear the static cache, otherwise we won't see the update.
+    $node = node_load($node->nid, NULL, TRUE);
+    $this->assertNotEqual($node->title, $new_title, 'Node title was not updated in the database.');
+
+    // Simulate a cache poisoning attack where JSON could get into the page
+    // cache.
+    // Grant node resource access to anonymous users.
+    user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array('access resource node'));
+    // Enable page caching.
+    variable_set('cache', 1);
+    // Reset cURL here to delete any stored request settings.
+    unset($this->curlHandle);
+    // Request the JSON representation of the node.
+    $this->drupalGet("node/$node->nid", array(), array('Accept: application/json'));
+    $this->assertUrl("node/$node->nid.json", array(), 'Requesting a resource with JSON Accept header redirects to the .json URL.');
+    // Now request the HTML representation.
+    $result = $this->drupalGet("node/$node->nid");
+    $content_type = $this->drupalGetHeader('content-type');
+    $this->assertNotEqual($content_type, 'application/json', 'Content type header is not JSON after requesting HTML.');
+    $this->assertNull(drupal_json_decode($result), 'Response body is not JSON after requesting HTML.');
+  }
+
+  /**
+   * Tests resource querying.
+   */
+  public function testQuerying() {
+    $account = $this->drupalCreateUser(array('access content',
+        'bypass node access', 'access resource node')
+    );
+    $this->drupalLogin($account);
+
+    $this->createTerm('foo');
+    $nodes = array();
+    for ($i = 0; $i < 5; $i++) {
+      $title = "node$i";
+      $node = array(
+        'title' => $title,
+        'type' => 'article',
+      );
+      // Add tags to the nodes 0 and 3.
+      if ($i % 3 == 0) {
+        $node['field_tags'][LANGUAGE_NONE][]['tid'] = 1;
+      }
+
+      // Set a body and the format to full_html for nodes 0 and 4.
+      if ($i % 4 == 0) {
+        $node['body'] = array(LANGUAGE_NONE => array(array('value' => l('foo', 'node'), 'format' => 'full_html')));
+      }
+      $nodes[$i] = $this->drupalCreateNode($node);
+    }
+
+    // Retrieve a list of nodes with json sorted by the title descending.
+    $result = $this->httpRequest('node.json', 'GET', $account, array('sort' => 'title', 'direction' => 'DESC'));
+    $result_nodes = drupal_json_decode($result);
+
+    // Start by checking if the last node created is the first in the result.
+    $i = 4;
+    foreach ($result_nodes['list'] as $key => $node) {
+      $this->assertEqual($nodes[$i]->title, $node['title'], "Node title $key was received correctly.");
+      $i--;
+    }
+    $this->assertResponse('200', 'HTTP response code is correct.');
+    $this->assertEqual(curl_getinfo($this->curlHandle, CURLINFO_CONTENT_TYPE), 'application/json', 'HTTP content type is correct.');
+
+    // Retrieve a list of nodes with xml.
+    $result = $this->drupalGet('node', array(), array('Accept: application/xml'));
+    $this->assertRaw('<list>', 'XML has been generated.');
+    for ($i = 0; $i < 5; $i++) {
+      $this->assertRaw("<title>node$i</title>", 'XML has been generated.');
+    }
+
+    // Query for a node with the title 'title1'.
+    $result = $this->httpRequest('node.json', 'GET', $account, array('title' => 'node1'));
+    $node = drupal_json_decode($result);
+    $this->assertEqual($node['list'][0]['title'], 'node1', 'Node title was received correctly.');
+
+    // Query for nodes with the taxonomy term foo which has the tid 1.
+    $result = $this->httpRequest('node.json', 'GET', $account, array('field_tags' => '1'));
+    $nodes = drupal_json_decode($result);
+
+    $this->assertEqual($nodes['list'][0]['title'], 'node0', 'Right node title was received.');
+    $this->assertEqual($nodes['list'][0]['field_tags'][0]['id'], 1, 'Node has taxonomy term.');
+
+    $this->assertEqual($nodes['list'][1]['title'], 'node3', 'Right node title was received.');
+    $this->assertEqual($nodes['list'][1]['field_tags'][0]['id'], 1, 'Node has taxonomy term.');
+
+    // Test paging and limiting.
+    $result = $this->httpRequest('node.json', 'GET', $account, array('limit' => 2, 'page' => 0));
+    $result_nodes = drupal_json_decode($result);
+
+    $this->assertTrue(count($result_nodes['list'] > 2), 'Only two elements where returned');
+
+    $this->assertTrue($result_nodes['self'] == url('node', array('absolute' => TRUE, 'query' => array('limit' => 2, 'page' => 0))), 'Self link was generated');
+    $this->assertTrue($result_nodes['first'] == url('node', array('absolute' => TRUE, 'query' => array('limit' => 2, 'page' => 0))), 'First link was generated');
+    $this->assertTrue($result_nodes['last'] == url('node', array('absolute' => TRUE, 'query' => array('limit' => 2, 'page' => 2))), 'Last link was generated');
+    $this->assertTrue($result_nodes['next'] == url('node', array('absolute' => TRUE, 'query' => array('limit' => 2, 'page' => 1))), 'Next link was generated');
+    $this->assertFalse(isset($result_nodes['prev']), 'Prev link was not generated');
+
+    $result = $this->httpRequest('node.json', 'GET', $account, array('limit' => 2, 'page' => 2));
+    $result_nodes = drupal_json_decode($result);
+
+    $this->assertFalse(isset($result_nodes['next']), 'Next link was not generated');
+    $this->assertTrue($result_nodes['prev'] == url('node', array('absolute' => TRUE, 'query' => array('limit' => 2, 'page' => 1))), 'Prev link was generated');
+
+    $result = $this->httpRequest('node.json', 'GET', $account, array('limit' => 2, 'page' => 5));
+    $this->assertResponse('404', 'HTTP response code is correct.');
+
+    // Test meta control full.
+    $result = $this->httpRequest('node.json', 'GET', $account, array('full' => 0));
+    $result_nodes = drupal_json_decode($result);
+
+    foreach ($result_nodes['list'] as $node) {
+      $this->assertTrue($node['uri'] == restws_resource_uri('node', $node['id']), 'Rerence to node ' . $node['id'] . ' was received correctly.');
+    }
+
+    // Test field column queries.
+    $result = $this->httpRequest('node.json', 'GET', $account, array('body[format]' => 'full_html'));
+    $result_nodes = drupal_json_decode($result);
+
+    $this->assertEqual($result_nodes['list'][0]['title'], 'node0', 'Right node title was received.');
+    $this->assertEqual($result_nodes['list'][0]['body']['format'], 'full_html', 'Node has body with full_html.');
+
+    $this->assertEqual($result_nodes['list'][1]['title'], 'node4', 'Right node title was received.');
+    $this->assertEqual($result_nodes['list'][1]['body']['format'], 'full_html', 'Node has body with full_html.');
+
+    // Test SQL injection via order direction.
+    $this->httpRequest('node.json', 'GET', $account, array('sort' => 'title', 'direction' => 'ASC; DELETE FROM ' . $this->databasePrefix . 'node WHERE nid = 1; --'));
+    $node = node_load(1, NULL, TRUE);
+    $this->assertNotEqual($node, FALSE, 'Node has not been deleted through SQL injection.');
+  }
+
+  /**
+   * Test that sensitive user data is hidden for the "access user profiles"
+   * permission and unpublished nodes.
+   */
+  public function testPermissions() {
+    // Test other user with "access user profiles" permission.
+    $test_user = $this->drupalCreateUser();
+    $account = $this->drupalCreateUser(array('access resource user', 'access user profiles'));
+    $result = $this->httpRequest('user/' . $test_user->uid . '.json', 'GET', $account);
+    $user_array = drupal_json_decode($result);
+    $this->assertEqual($test_user->name, $user_array['name'], 'User name was received correctly.');
+    $this->assertFalse(isset($user_array['mail']), 'User mail is not present in the response.');
+    $this->assertFalse(isset($user_array['roles']), 'User roles are not present in the response.');
+    $this->assertResponse('200', 'HTTP response code is correct.');
+    $this->assertEqual(curl_getinfo($this->curlHandle, CURLINFO_CONTENT_TYPE), 'application/json', 'HTTP content type is correct.');
+
+    // Test the own user - access to sensitive information should be allowed.
+    $result = $this->httpRequest('user/' . $account->uid . '.json', 'GET', $account);
+    $user_array = drupal_json_decode($result);
+    $this->assertEqual($account->name, $user_array['name'], 'User name was received correctly.');
+    $this->assertEqual($account->mail, $user_array['mail'], 'User mail is present in the response.');
+    $role_keys = array_keys($account->roles);
+    $this->assertEqual(sort($role_keys), sort($user_array['roles']), 'User roles are present in the response.');
+    $this->assertResponse('200', 'HTTP response code is correct.');
+    $this->assertEqual(curl_getinfo($this->curlHandle, CURLINFO_CONTENT_TYPE), 'application/json', 'HTTP content type is correct.');
+
+    // Test node access with an unpublished node.
+    $this->drupalCreateNode(array('title' => 'foo', 'status' => 0));
+
+    $this->drupalLogout();
+
+    $account = $this->drupalCreateUser(array('access resource node'));
+    $this->drupalLogin($account);
+
+    $result = $this->httpRequest('node.json', 'GET', $account);
+    $nodes = drupal_json_decode($result);
+    // No node should be returned.
+    $this->assertEqual(count($nodes['list']), 0, 'Unpublished node was successfully hidden.');
+
+  }
+
+  /**
+   * Test menu path resource setting.
+   */
+  public function testMenuPath() {
+    module_enable(array('restws_test'));
+
+    $account = $this->drupalCreateUser(array('access content',
+        'bypass node access', 'access resource node')
+    );
+    $this->drupalLogin($account);
+
+    $title = $this->randomName(8);
+    $node = $this->drupalCreateNode(array('title' => $title));
+
+    $result = $this->httpRequest('foo/1.json', 'GET', $account);
+    $this->assertEqual($node->title, $title, "Node was received correctly on the right menu path.");
+  }
+
+  /**
+   * Creates a term.
+   */
+  protected function createTerm($term_name) {
+    $term = new stdClass();
+    $term->name = $term_name;
+    $term->vid = 1;
+    taxonomy_term_save($term);
+  }
+
+  /**
+   * Helper function to issue a HTTP request with simpletest's cURL.
+   *
+   * @param array $body
+   *   Either the body for POST and PUT or additional URL parameters for GET.
+   */
+  protected function httpRequest($url, $method, $account = NULL, $body = NULL, $format = 'json') {
+    if (isset($account)) {
+      unset($this->curlHandle);
+      $this->drupalLogin($account);
+    }
+    if (in_array($method, array('POST', 'PUT', 'DELETE'))) {
+      // GET the CSRF token first for writing requests.
+      $token = $this->drupalGet('restws/session/token');
+    }
+    switch ($method) {
+      case 'GET':
+        // Set query if there are addition GET parameters.
+        $options = isset($body) ? array('absolute' => TRUE, 'query' => $body) : array('absolute' => TRUE);
+        $curl_options = array(
+          CURLOPT_HTTPGET => TRUE,
+          CURLOPT_URL => url($url, $options),
+          CURLOPT_NOBODY => FALSE,
+        );
+        break;
+
+      case 'POST':
+        $curl_options = array(
+          CURLOPT_HTTPGET => FALSE,
+          CURLOPT_POST => TRUE,
+          CURLOPT_POSTFIELDS => $body,
+          CURLOPT_URL => url($url, array('absolute' => TRUE)),
+          CURLOPT_NOBODY => FALSE,
+          CURLOPT_HTTPHEADER => array(
+            'Content-Type: application/' . $format,
+            'X-CSRF-Token: ' . $token,
+          ),
+        );
+        break;
+
+      case 'PUT':
+        $curl_options = array(
+          CURLOPT_HTTPGET => FALSE,
+          CURLOPT_CUSTOMREQUEST => 'PUT',
+          CURLOPT_POSTFIELDS => $body,
+          CURLOPT_URL => url($url, array('absolute' => TRUE)),
+          CURLOPT_NOBODY => FALSE,
+          CURLOPT_HTTPHEADER => array(
+            'Content-Type: application/' . $format,
+            'X-CSRF-Token: ' . $token,
+          ),
+        );
+        break;
+
+      case 'DELETE':
+        $curl_options = array(
+          CURLOPT_HTTPGET => FALSE,
+          CURLOPT_CUSTOMREQUEST => 'DELETE',
+          CURLOPT_URL => url($url, array('absolute' => TRUE)),
+          CURLOPT_NOBODY => FALSE,
+          CURLOPT_HTTPHEADER => array('X-CSRF-Token: ' . $token),
+        );
+        break;
+    }
+
+    $response = $this->curlExec($curl_options);
+    $headers = $this->drupalGetHeaders();
+    $headers = implode("\n", $headers);
+
+    $this->verbose($method . ' request to: ' . $url .
+      '<hr />Code: ' . curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE) .
+      '<hr />Response headers: ' . $headers .
+      '<hr />Response body: ' . $response);
+
+    return $response;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws_basic_auth/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,17 @@
+--------------------------------------------------------------------------------
+                 HTTP Basic Authentication for RESTful Web Services
+--------------------------------------------------------------------------------
+
+This module takes the user name and password from HTTP basic authentication
+headers to perform a Drupal user login. This is useful for authenticating remote
+web service calls with the standard Drupal user access system.
+
+Per default only user names starting with "restws" will be tried to log in. This
+can be configured with the "restws_basic_auth_user_regex" variable, which allows
+you to define an arbitrary pattern that the user names must match. This avoids
+unecessary login attempts for standard human users on protected sites.
+
+You can configure the regex (suitable for preg_match()) in your settings.php,
+e.g.:
+
+$conf['restws_basic_auth_user_regex'] = '/^web_service.*/';
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws_basic_auth/restws_basic_auth.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,10 @@
+name = Basic authentication login
+description = User login from HTTP authorization headers (part of RESTful web services).
+core = 7.x
+
+; Information added by drupal.org packaging script on 2013-08-07
+version = "7.x-2.1"
+core = "7.x"
+project = "restws"
+datestamp = "1375888987"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws_basic_auth/restws_basic_auth.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * @file
+ * Basic authentication login - install file.
+ */
+
+/**
+ * Implements hook_uninstall().
+ */
+function restws_basic_auth_uninstall() {
+  variable_del('restws_basic_auth_user_regex');
+}
+
+/**
+ * Set the user name regex to accept all for backwards compatibility.
+ */
+function restws_basic_auth_update_7100() {
+  // Set the user name regex to accept all.
+  variable_set('restws_basic_auth_user_regex', '/.*/');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/restws_basic_auth/restws_basic_auth.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * @file
+ * Basic authentication login - module file.
+ */
+
+/**
+ * Implements hook_init().
+ *
+ * Performs a user login from the credentials in the HTTP Authorization header.
+ */
+function restws_basic_auth_init() {
+  if (user_is_anonymous() && isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
+    // Login only user names that match a pattern.
+    $user_regex = variable_get('restws_basic_auth_user_regex', '/^restws.*/');
+    if (preg_match($user_regex, $_SERVER['PHP_AUTH_USER'])) {
+      $form_state = array();
+      $form_state['values']['name'] = $_SERVER['PHP_AUTH_USER'];
+      $form_state['values']['pass'] = $_SERVER['PHP_AUTH_PW'];
+      drupal_form_submit('user_login', $form_state);
+      if (!user_is_anonymous()) {
+        drupal_static_reset();
+      }
+      else {
+        // Clear the login form error and remove the login failure message.
+        $form = &drupal_static('form_set_error', array());
+        $form = array();
+        drupal_get_messages();
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/tests/restws_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+name = RESTful web services test module
+description = "Support module for the RestWS tests."
+package = Testing
+core = 7.x
+hidden = TRUE
+
+; Information added by drupal.org packaging script on 2013-08-07
+version = "7.x-2.1"
+core = "7.x"
+project = "restws"
+datestamp = "1375888987"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/restws/tests/restws_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * RESTful web services test module.
+ */
+
+/**
+ * Implements hook_restws_resource_info_alter().
+ *
+ * @see RestWSTestCase::testMenuPath().
+ */
+function restws_test_restws_resource_info_alter(&$resource_info) {
+  $resource_info['node']['menu_path'] = 'foo';
+}
+
+/**
+ * Implements hook_field_access().
+ *
+ * @see RestWSTestCase::testFieldAccess()
+ */
+function restws_test_field_access($op, $field, $entity_type, $entity, $account) {
+  if ($field['field_name'] == 'field_text' && $op == 'edit') {
+    // Only allow edit access for a higher level permission.
+    return user_access('administer users', $account);
+  }
+  return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.features.field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,251 @@
+<?php
+/**
+ * @file
+ * schemaorg_event.features.field.inc
+ */
+
+/**
+ * Implements hook_field_default_fields().
+ */
+function schemaorg_event_field_default_fields() {
+  $fields = array();
+
+  // Exported field: 'node-schemaorg_event-field_location'
+  $fields['node-schemaorg_event-field_location'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_location',
+      'foreign keys' => array(
+        'format' => array(
+          'columns' => array(
+            'format' => 'format',
+          ),
+          'table' => 'filter_format',
+        ),
+      ),
+      'indexes' => array(
+        'format' => array(
+          0 => 'format',
+        ),
+      ),
+      'module' => 'text',
+      'settings' => array(
+        'max_length' => '255',
+      ),
+      'translatable' => '0',
+      'type' => 'text',
+    ),
+    'field_instance' => array(
+      'bundle' => 'schemaorg_event',
+      'default_value' => NULL,
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'text',
+          'settings' => array(),
+          'type' => 'text_default',
+          'weight' => '1',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'module' => 'text',
+          'settings' => array(),
+          'type' => 'text_default',
+          'weight' => '1',
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_location',
+      'label' => 'Location',
+      'required' => 1,
+      'settings' => array(
+        'text_processing' => '0',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'text',
+        'settings' => array(
+          'size' => '60',
+        ),
+        'type' => 'text_textfield',
+        'weight' => '2',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-schemaorg_event-field_schemaorg_date'
+  $fields['node-schemaorg_event-field_schemaorg_date'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_schemaorg_date',
+      'foreign keys' => array(),
+      'indexes' => array(),
+      'module' => 'date',
+      'settings' => array(
+        'granularity' => array(
+          'day' => 'day',
+          'hour' => 0,
+          'minute' => 0,
+          'month' => 'month',
+          'second' => 0,
+          'year' => 'year',
+        ),
+        'repeat' => 0,
+        'timezone_db' => '',
+        'todate' => '',
+        'tz_handling' => 'none',
+      ),
+      'translatable' => '0',
+      'type' => 'datestamp',
+    ),
+    'field_instance' => array(
+      'bundle' => 'schemaorg_event',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'long',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '0',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'module' => 'date',
+          'settings' => array(
+            'format_type' => 'long',
+            'fromto' => 'both',
+            'multiple_from' => '',
+            'multiple_number' => '',
+            'multiple_to' => '',
+            'show_repeat_rule' => 'show',
+          ),
+          'type' => 'date_default',
+          'weight' => '0',
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_schemaorg_date',
+      'label' => 'Date',
+      'required' => 1,
+      'settings' => array(
+        'default_value' => 'now',
+        'default_value2' => 'blank',
+        'default_value_code' => '',
+        'default_value_code2' => '',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'date',
+        'settings' => array(
+          'increment' => '15',
+          'input_format' => 'm/d/Y - H:i:s',
+          'input_format_custom' => '',
+          'label_position' => 'above',
+          'repeat_collapsed' => 0,
+          'text_parts' => array(),
+          'year_range' => '-3:+3',
+        ),
+        'type' => 'date_popup',
+        'weight' => '1',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-schemaorg_event-field_schemaorg_description'
+  $fields['node-schemaorg_event-field_schemaorg_description'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_schemaorg_description',
+      'foreign keys' => array(
+        'format' => array(
+          'columns' => array(
+            'format' => 'format',
+          ),
+          'table' => 'filter_format',
+        ),
+      ),
+      'indexes' => array(
+        'format' => array(
+          0 => 'format',
+        ),
+      ),
+      'module' => 'text',
+      'settings' => array(),
+      'translatable' => '0',
+      'type' => 'text_with_summary',
+    ),
+    'field_instance' => array(
+      'bundle' => 'schemaorg_event',
+      'default_value' => NULL,
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'text',
+          'settings' => array(),
+          'type' => 'text_default',
+          'weight' => '2',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'module' => 'text',
+          'settings' => array(
+            'trim_length' => 600,
+          ),
+          'type' => 'text_summary_or_trimmed',
+          'weight' => '2',
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_schemaorg_description',
+      'label' => 'Description',
+      'required' => 1,
+      'settings' => array(
+        'display_summary' => 0,
+        'text_processing' => '1',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'text',
+        'settings' => array(
+          'rows' => '20',
+          'summary_rows' => 5,
+        ),
+        'type' => 'text_textarea_with_summary',
+        'weight' => '3',
+      ),
+    ),
+  );
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('Date');
+  t('Description');
+  t('Location');
+
+  return $fields;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,130 @@
+<?php
+/**
+ * @file
+ * schemaorg_event.features.inc
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function schemaorg_event_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "strongarm" && $api == "strongarm") {
+    return array("version" => "1");
+  }
+}
+
+/**
+ * Implements hook_views_api().
+ */
+function schemaorg_event_views_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "views" && $api == "views_default") {
+    return array("version" => "3.0");
+  }
+}
+
+/**
+ * Implements hook_node_info().
+ */
+function schemaorg_event_node_info() {
+  $items = array(
+    'schemaorg_event' => array(
+      'name' => t('Event'),
+      'base' => 'node_content',
+      'description' => '',
+      'has_title' => '1',
+      'title_label' => t('Title'),
+      'help' => '',
+    ),
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_rdf_default_mappings().
+ */
+function schemaorg_event_rdf_default_mappings() {
+  $schemaorg = array();
+
+  // Exported RDF mapping: schemaorg_event
+  $schemaorg['node']['schemaorg_event'] = array(
+    'rdftype' => array(
+      0 => 'schema:Event',
+      1 => 'sioc:Item',
+      2 => 'foaf:Document',
+    ),
+    'title' => array(
+      'predicates' => array(
+        0 => 'schema:name',
+      ),
+    ),
+    'created' => array(
+      'predicates' => array(
+        0 => 'dc:date',
+        1 => 'dc:created',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'changed' => array(
+      'predicates' => array(
+        0 => 'dc:modified',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'body' => array(
+      'predicates' => array(
+        0 => 'content:encoded',
+      ),
+    ),
+    'uid' => array(
+      'predicates' => array(
+        0 => 'sioc:has_creator',
+      ),
+      'type' => 'rel',
+    ),
+    'name' => array(
+      'predicates' => array(
+        0 => 'schema:name',
+      ),
+    ),
+    'comment_count' => array(
+      'predicates' => array(
+        0 => 'sioc:num_replies',
+      ),
+      'datatype' => 'xsd:integer',
+    ),
+    'last_activity' => array(
+      'predicates' => array(
+        0 => 'sioc:last_activity_date',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'field_schemaorg_date' => array(
+      'predicates' => array(
+        0 => 'schema:startDate',
+      ),
+    ),
+    'url' => array(
+      'predicates' => array(
+        0 => 'schema:url',
+      ),
+      'type' => 'rel',
+    ),
+    'field_location' => array(
+      'predicates' => array(
+        0 => 'schema:location',
+      ),
+    ),
+    'field_schemaorg_description' => array(
+      'predicates' => array(
+        0 => 'schema:summary',
+      ),
+    ),
+  );
+
+  return $schemaorg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,45 @@
+name = "Schema.org example: Event"
+description = "Example of an event content type with fields mapped to schema.org"
+core = "7.x"
+package = "Schema.org"
+dependencies[] = "ctools"
+dependencies[] = "date"
+dependencies[] = "date_api"
+dependencies[] = "date_popup"
+dependencies[] = "date_views"
+dependencies[] = "features"
+dependencies[] = "field_sql_storage"
+dependencies[] = "node"
+dependencies[] = "rdf"
+dependencies[] = "schemaorg"
+dependencies[] = "strongarm"
+dependencies[] = "text"
+dependencies[] = "views"
+dependencies[] = "views_ui"
+features[ctools][] = "strongarm:strongarm:1"
+features[ctools][] = "views:views_default:3.0"
+features[field][] = "node-schemaorg_event-field_location"
+features[field][] = "node-schemaorg_event-field_schemaorg_date"
+features[field][] = "node-schemaorg_event-field_schemaorg_description"
+features[node][] = "schemaorg_event"
+features[schemaorg][] = "node-schemaorg_event"
+features[variable][] = "comment_anonymous_schemaorg_event"
+features[variable][] = "comment_default_mode_schemaorg_event"
+features[variable][] = "comment_default_per_page_schemaorg_event"
+features[variable][] = "comment_form_location_schemaorg_event"
+features[variable][] = "comment_preview_schemaorg_event"
+features[variable][] = "comment_schemaorg_event"
+features[variable][] = "comment_subject_field_schemaorg_event"
+features[variable][] = "menu_options_schemaorg_event"
+features[variable][] = "menu_parent_schemaorg_event"
+features[variable][] = "node_options_schemaorg_event"
+features[variable][] = "node_preview_schemaorg_event"
+features[variable][] = "node_submitted_schemaorg_event"
+features[views_view][] = "events"
+
+; Information added by drupal.org packaging script on 2012-05-21
+version = "7.x-1.0-beta3"
+core = "7.x"
+project = "schemaorg"
+datestamp = "1337625394"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the schemaorg_event feature.
+ */
+
+
+/**
+ * Implements hook_disable().
+ */
+function schemaorg_event_disable() {
+  // There is currently a bug in features / core which prevents the content type
+  // delete link to be displayed for content types created with features.
+  // A message is displayed with a link to the content type delete form.
+  _schemaorg_event_show_disable_message();
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function schemaorg_event_uninstall() {
+  _schemaorg_event_show_disable_message();
+}
+
+function _schemaorg_event_show_disable_message() {
+  drupal_set_message('The event content type was not automatically removed. If you want to completely remove this content type and its fields, please browse to the <a href="'. url('admin/structure/types/manage/schemaorg-event/delete') .'">content type delete</a> form.', 'warning');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,7 @@
+<?php
+/**
+ * @file
+ * Code for the Schema.org: Event feature.
+ */
+
+include_once('schemaorg_event.features.inc');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.strongarm.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,103 @@
+<?php
+/**
+ * @file
+ * schemaorg_event.strongarm.inc
+ */
+
+/**
+ * Implements hook_strongarm().
+ */
+function schemaorg_event_strongarm() {
+  $export = array();
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_anonymous_schemaorg_event';
+  $strongarm->value = 0;
+  $export['comment_anonymous_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_default_mode_schemaorg_event';
+  $strongarm->value = 1;
+  $export['comment_default_mode_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_default_per_page_schemaorg_event';
+  $strongarm->value = '50';
+  $export['comment_default_per_page_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_form_location_schemaorg_event';
+  $strongarm->value = 1;
+  $export['comment_form_location_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_preview_schemaorg_event';
+  $strongarm->value = '1';
+  $export['comment_preview_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_schemaorg_event';
+  $strongarm->value = '2';
+  $export['comment_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_subject_field_schemaorg_event';
+  $strongarm->value = 1;
+  $export['comment_subject_field_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'menu_options_schemaorg_event';
+  $strongarm->value = array(
+    0 => 'main-menu',
+  );
+  $export['menu_options_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'menu_parent_schemaorg_event';
+  $strongarm->value = 'main-menu:0';
+  $export['menu_parent_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'node_options_schemaorg_event';
+  $strongarm->value = array(
+    0 => 'status',
+    1 => 'promote',
+  );
+  $export['node_options_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'node_preview_schemaorg_event';
+  $strongarm->value = '1';
+  $export['node_preview_schemaorg_event'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'node_submitted_schemaorg_event';
+  $strongarm->value = 1;
+  $export['node_submitted_schemaorg_event'] = $strongarm;
+
+  return $export;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_event/schemaorg_event.views_default.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,80 @@
+<?php
+/**
+ * @file
+ * schemaorg_event.views_default.inc
+ */
+
+/**
+ * Implements hook_views_default_views().
+ */
+function schemaorg_event_views_default_views() {
+  $export = array();
+
+  $view = new view;
+  $view->name = 'events';
+  $view->description = '';
+  $view->tag = 'default';
+  $view->base_table = 'node';
+  $view->human_name = 'Events';
+  $view->core = 7;
+  $view->api_version = '3.0';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Master */
+  $handler = $view->new_display('default', 'Master', 'default');
+  $handler->display->display_options['title'] = 'Events';
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['query']['options']['query_comment'] = FALSE;
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '10';
+  $handler->display->display_options['style_plugin'] = 'default';
+  $handler->display->display_options['row_plugin'] = 'node';
+  /* Field: Content: Title */
+  $handler->display->display_options['fields']['title']['id'] = 'title';
+  $handler->display->display_options['fields']['title']['table'] = 'node';
+  $handler->display->display_options['fields']['title']['field'] = 'title';
+  $handler->display->display_options['fields']['title']['label'] = '';
+  $handler->display->display_options['fields']['title']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['word_boundary'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['ellipsis'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['title']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['title']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['title']['link_to_node'] = 1;
+  /* Sort criterion: Content: Date (field_schemaorg_date) */
+  $handler->display->display_options['sorts']['field_schemaorg_date_value']['id'] = 'field_schemaorg_date_value';
+  $handler->display->display_options['sorts']['field_schemaorg_date_value']['table'] = 'field_data_field_schemaorg_date';
+  $handler->display->display_options['sorts']['field_schemaorg_date_value']['field'] = 'field_schemaorg_date_value';
+  /* Filter criterion: Content: Published */
+  $handler->display->display_options['filters']['status']['id'] = 'status';
+  $handler->display->display_options['filters']['status']['table'] = 'node';
+  $handler->display->display_options['filters']['status']['field'] = 'status';
+  $handler->display->display_options['filters']['status']['value'] = 1;
+  $handler->display->display_options['filters']['status']['group'] = 0;
+  $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
+  /* Filter criterion: Content: Type */
+  $handler->display->display_options['filters']['type']['id'] = 'type';
+  $handler->display->display_options['filters']['type']['table'] = 'node';
+  $handler->display->display_options['filters']['type']['field'] = 'type';
+  $handler->display->display_options['filters']['type']['value'] = array(
+    'schemaorg_event' => 'schemaorg_event',
+  );
+
+  /* Display: Page */
+  $handler = $view->new_display('page', 'Page', 'page');
+  $handler->display->display_options['path'] = 'events';
+  $handler->display->display_options['menu']['type'] = 'normal';
+  $handler->display->display_options['menu']['title'] = 'Events';
+  $handler->display->display_options['menu']['weight'] = '5';
+  $handler->display->display_options['menu']['name'] = 'main-menu';
+  $export['events'] = $view;
+
+  return $export;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.features.field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,303 @@
+<?php
+/**
+ * @file
+ * schemaorg_person.features.field.inc
+ */
+
+/**
+ * Implements hook_field_default_fields().
+ */
+function schemaorg_person_field_default_fields() {
+  $fields = array();
+
+  // Exported field: 'node-schemaorg_person-field_schemaorg_affiliation'
+  $fields['node-schemaorg_person-field_schemaorg_affiliation'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_schemaorg_affiliation',
+      'foreign keys' => array(
+        'format' => array(
+          'columns' => array(
+            'format' => 'format',
+          ),
+          'table' => 'filter_format',
+        ),
+      ),
+      'indexes' => array(
+        'format' => array(
+          0 => 'format',
+        ),
+      ),
+      'module' => 'text',
+      'settings' => array(
+        'max_length' => '255',
+      ),
+      'translatable' => '0',
+      'type' => 'text',
+    ),
+    'field_instance' => array(
+      'bundle' => 'schemaorg_person',
+      'default_value' => NULL,
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'text',
+          'settings' => array(),
+          'type' => 'text_default',
+          'weight' => '3',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_schemaorg_affiliation',
+      'label' => 'Affiliation',
+      'required' => 1,
+      'settings' => array(
+        'text_processing' => '0',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'text',
+        'settings' => array(
+          'size' => '60',
+        ),
+        'type' => 'text_textfield',
+        'weight' => '4',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-schemaorg_person-field_schemaorg_bio'
+  $fields['node-schemaorg_person-field_schemaorg_bio'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_schemaorg_bio',
+      'foreign keys' => array(
+        'format' => array(
+          'columns' => array(
+            'format' => 'format',
+          ),
+          'table' => 'filter_format',
+        ),
+      ),
+      'indexes' => array(
+        'format' => array(
+          0 => 'format',
+        ),
+      ),
+      'module' => 'text',
+      'settings' => array(),
+      'translatable' => '0',
+      'type' => 'text_with_summary',
+    ),
+    'field_instance' => array(
+      'bundle' => 'schemaorg_person',
+      'default_value' => NULL,
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'text',
+          'settings' => array(),
+          'type' => 'text_default',
+          'weight' => '1',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_schemaorg_bio',
+      'label' => 'Bio',
+      'required' => 1,
+      'settings' => array(
+        'display_summary' => 0,
+        'text_processing' => '1',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'text',
+        'settings' => array(
+          'rows' => '20',
+          'summary_rows' => 5,
+        ),
+        'type' => 'text_textarea_with_summary',
+        'weight' => '2',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-schemaorg_person-field_schemaorg_jobtitle'
+  $fields['node-schemaorg_person-field_schemaorg_jobtitle'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_schemaorg_jobtitle',
+      'foreign keys' => array(
+        'format' => array(
+          'columns' => array(
+            'format' => 'format',
+          ),
+          'table' => 'filter_format',
+        ),
+      ),
+      'indexes' => array(
+        'format' => array(
+          0 => 'format',
+        ),
+      ),
+      'module' => 'text',
+      'settings' => array(
+        'max_length' => '255',
+      ),
+      'translatable' => '0',
+      'type' => 'text',
+    ),
+    'field_instance' => array(
+      'bundle' => 'schemaorg_person',
+      'default_value' => NULL,
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'text',
+          'settings' => array(),
+          'type' => 'text_default',
+          'weight' => '2',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_schemaorg_jobtitle',
+      'label' => 'Job Title',
+      'required' => 1,
+      'settings' => array(
+        'text_processing' => '0',
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'text',
+        'settings' => array(
+          'size' => '60',
+        ),
+        'type' => 'text_textfield',
+        'weight' => '3',
+      ),
+    ),
+  );
+
+  // Exported field: 'node-schemaorg_person-field_schemaorg_photo'
+  $fields['node-schemaorg_person-field_schemaorg_photo'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_schemaorg_photo',
+      'foreign keys' => array(
+        'fid' => array(
+          'columns' => array(
+            'fid' => 'fid',
+          ),
+          'table' => 'file_managed',
+        ),
+      ),
+      'indexes' => array(
+        'fid' => array(
+          0 => 'fid',
+        ),
+      ),
+      'module' => 'image',
+      'settings' => array(
+        'default_image' => 0,
+        'uri_scheme' => 'public',
+      ),
+      'translatable' => '0',
+      'type' => 'image',
+    ),
+    'field_instance' => array(
+      'bundle' => 'schemaorg_person',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'image',
+          'settings' => array(
+            'image_link' => '',
+            'image_style' => '',
+          ),
+          'type' => 'image',
+          'weight' => '0',
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_schemaorg_photo',
+      'label' => 'Photo',
+      'required' => 1,
+      'settings' => array(
+        'alt_field' => 0,
+        'file_directory' => '',
+        'file_extensions' => 'png gif jpg jpeg',
+        'max_filesize' => '',
+        'max_resolution' => '',
+        'min_resolution' => '',
+        'title_field' => 0,
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'image',
+        'settings' => array(
+          'preview_image_style' => 'thumbnail',
+          'progress_indicator' => 'throbber',
+        ),
+        'type' => 'image_image',
+        'weight' => '1',
+      ),
+    ),
+  );
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('Affiliation');
+  t('Bio');
+  t('Job Title');
+  t('Photo');
+
+  return $fields;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,121 @@
+<?php
+/**
+ * @file
+ * schemaorg_person.features.inc
+ */
+
+/**
+ * Implements hook_ctools_plugin_api().
+ */
+function schemaorg_person_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "strongarm" && $api == "strongarm") {
+    return array("version" => "1");
+  }
+}
+
+/**
+ * Implements hook_node_info().
+ */
+function schemaorg_person_node_info() {
+  $items = array(
+    'schemaorg_person' => array(
+      'name' => t('Person'),
+      'base' => 'node_content',
+      'description' => t('A page representing a person'),
+      'has_title' => '1',
+      'title_label' => t('Name'),
+      'help' => '',
+    ),
+  );
+  return $items;
+}
+
+/**
+ * Implements hook_rdf_default_mappings().
+ */
+function schemaorg_person_rdf_default_mappings() {
+  $schemaorg = array();
+
+  // Exported RDF mapping: schemaorg_person
+  $schemaorg['node']['schemaorg_person'] = array(
+    'rdftype' => array(
+      0 => 'schema:Person',
+      1 => 'sioc:Item',
+      2 => 'foaf:Document',
+    ),
+    'title' => array(
+      'predicates' => array(
+        0 => 'schema:name',
+      ),
+    ),
+    'created' => array(
+      'predicates' => array(
+        0 => 'dc:date',
+        1 => 'dc:created',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'changed' => array(
+      'predicates' => array(
+        0 => 'dc:modified',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'body' => array(
+      'predicates' => array(
+        0 => 'content:encoded',
+      ),
+    ),
+    'uid' => array(
+      'predicates' => array(
+        0 => 'sioc:has_creator',
+      ),
+      'type' => 'rel',
+    ),
+    'name' => array(
+      'predicates' => array(
+        0 => 'schema:name',
+      ),
+    ),
+    'comment_count' => array(
+      'predicates' => array(
+        0 => 'sioc:num_replies',
+      ),
+      'datatype' => 'xsd:integer',
+    ),
+    'last_activity' => array(
+      'predicates' => array(
+        0 => 'sioc:last_activity_date',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'url' => array(
+      'predicates' => array(
+        0 => 'schema:url',
+      ),
+      'type' => 'rel',
+    ),
+    'field_schemaorg_jobtitle' => array(
+      'predicates' => array(
+        0 => 'schema:jobTitle',
+      ),
+    ),
+    'field_schemaorg_affiliation' => array(
+      'predicates' => array(
+        0 => 'schema:affiliation',
+      ),
+    ),
+    'field_schemaorg_photo' => array(
+      'predicates' => array(
+        0 => 'schema:image',
+      ),
+      'type' => 'rel',
+    ),
+  );
+
+  return $schemaorg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+name = "Schema.org example: Person"
+description = "Example of a person content type with fields mapped to schema.org"
+core = "7.x"
+package = "Schema.org"
+php = "5.2.4"
+dependencies[] = "features"
+dependencies[] = "image"
+dependencies[] = "rdf"
+dependencies[] = "schemaorg"
+dependencies[] = "strongarm"
+features[ctools][] = "strongarm:strongarm:1"
+features[field][] = "node-schemaorg_person-field_schemaorg_affiliation"
+features[field][] = "node-schemaorg_person-field_schemaorg_bio"
+features[field][] = "node-schemaorg_person-field_schemaorg_jobtitle"
+features[field][] = "node-schemaorg_person-field_schemaorg_photo"
+features[node][] = "schemaorg_person"
+features[schemaorg][] = "node-schemaorg_person"
+features[variable][] = "comment_anonymous_schemaorg_person"
+features[variable][] = "comment_default_mode_schemaorg_person"
+features[variable][] = "comment_default_per_page_schemaorg_person"
+features[variable][] = "comment_form_location_schemaorg_person"
+features[variable][] = "comment_preview_schemaorg_person"
+features[variable][] = "comment_schemaorg_person"
+features[variable][] = "comment_subject_field_schemaorg_person"
+features[variable][] = "menu_options_schemaorg_person"
+features[variable][] = "menu_parent_schemaorg_person"
+features[variable][] = "node_options_schemaorg_person"
+features[variable][] = "node_preview_schemaorg_person"
+features[variable][] = "node_submitted_schemaorg_person"
+
+; Information added by drupal.org packaging script on 2012-05-21
+version = "7.x-1.0-beta3"
+core = "7.x"
+project = "schemaorg"
+datestamp = "1337625394"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the schemaorg_person feature.
+ */
+
+
+/**
+ * Implements hook_disable().
+ */
+function schemaorg_person_disable() {
+  // There is currently a bug in features / core which prevents the content type
+  // delete link to be displayed for content types created with features.
+  // A message is displayed with a link to the content type delete form.
+  _schemaorg_person_show_disable_message();
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function schemaorg_person_uninstall() {
+  _schemaorg_person_show_disable_message();
+}
+
+function _schemaorg_person_show_disable_message() {
+  drupal_set_message('The person content type was not automatically removed. If you want to completely remove this content type and its fields, please browse to the <a href="'. url('admin/structure/types/manage/schemaorg-person/delete') .'">content type delete</a> form.', 'warning');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,7 @@
+<?php
+/**
+ * @file
+ * Code for the Schema.org: Person feature.
+ */
+
+include_once('schemaorg_person.features.inc');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_person/schemaorg_person.strongarm.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,103 @@
+<?php
+/**
+ * @file
+ * schemaorg_person.strongarm.inc
+ */
+
+/**
+ * Implements hook_strongarm().
+ */
+function schemaorg_person_strongarm() {
+  $export = array();
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_anonymous_schemaorg_person';
+  $strongarm->value = 0;
+  $export['comment_anonymous_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_default_mode_schemaorg_person';
+  $strongarm->value = 1;
+  $export['comment_default_mode_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_default_per_page_schemaorg_person';
+  $strongarm->value = '50';
+  $export['comment_default_per_page_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_form_location_schemaorg_person';
+  $strongarm->value = 1;
+  $export['comment_form_location_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_preview_schemaorg_person';
+  $strongarm->value = '1';
+  $export['comment_preview_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_schemaorg_person';
+  $strongarm->value = '1';
+  $export['comment_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'comment_subject_field_schemaorg_person';
+  $strongarm->value = 1;
+  $export['comment_subject_field_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'menu_options_schemaorg_person';
+  $strongarm->value = array(
+    0 => 'main-menu',
+  );
+  $export['menu_options_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'menu_parent_schemaorg_person';
+  $strongarm->value = 'main-menu:0';
+  $export['menu_parent_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'node_options_schemaorg_person';
+  $strongarm->value = array(
+    0 => 'status',
+    1 => 'promote',
+  );
+  $export['node_options_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'node_preview_schemaorg_person';
+  $strongarm->value = '1';
+  $export['node_preview_schemaorg_person'] = $strongarm;
+
+  $strongarm = new stdClass;
+  $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */
+  $strongarm->api_version = 1;
+  $strongarm->name = 'node_submitted_schemaorg_person';
+  $strongarm->value = 0;
+  $export['node_submitted_schemaorg_person'] = $strongarm;
+
+  return $export;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_recipe/schemaorg_recipe.features.field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,96 @@
+<?php
+/**
+ * @file
+ * schemaorg_recipe.features.field.inc
+ */
+
+/**
+ * Implements hook_field_default_fields().
+ */
+function schemaorg_recipe_field_default_fields() {
+  $fields = array();
+
+  // Exported field: 'node-recipe-field_schemaorg_image'
+  $fields['node-recipe-field_schemaorg_image'] = array(
+    'field_config' => array(
+      'active' => '1',
+      'cardinality' => '1',
+      'deleted' => '0',
+      'entity_types' => array(),
+      'field_name' => 'field_schemaorg_image',
+      'foreign keys' => array(
+        'fid' => array(
+          'columns' => array(
+            'fid' => 'fid',
+          ),
+          'table' => 'file_managed',
+        ),
+      ),
+      'indexes' => array(
+        'fid' => array(
+          0 => 'fid',
+        ),
+      ),
+      'module' => 'image',
+      'settings' => array(
+        'default_image' => 0,
+        'uri_scheme' => 'public',
+      ),
+      'translatable' => '0',
+      'type' => 'image',
+    ),
+    'field_instance' => array(
+      'bundle' => 'recipe',
+      'deleted' => '0',
+      'description' => '',
+      'display' => array(
+        'default' => array(
+          'label' => 'above',
+          'module' => 'image',
+          'settings' => array(
+            'image_link' => '',
+            'image_style' => '',
+          ),
+          'type' => 'image',
+          'weight' => 0,
+        ),
+        'teaser' => array(
+          'label' => 'above',
+          'settings' => array(),
+          'type' => 'hidden',
+          'weight' => 0,
+        ),
+      ),
+      'entity_type' => 'node',
+      'field_name' => 'field_schemaorg_image',
+      'label' => 'Image',
+      'required' => 1,
+      'settings' => array(
+        'alt_field' => 0,
+        'file_directory' => '',
+        'file_extensions' => 'png gif jpg jpeg',
+        'max_filesize' => '',
+        'max_resolution' => '',
+        'min_resolution' => '',
+        'title_field' => 0,
+        'user_register_form' => FALSE,
+      ),
+      'widget' => array(
+        'active' => 1,
+        'module' => 'image',
+        'settings' => array(
+          'preview_image_style' => 'thumbnail',
+          'progress_indicator' => 'throbber',
+        ),
+        'type' => 'image_image',
+        'weight' => 0,
+      ),
+    ),
+  );
+
+  // Translatables
+  // Included for use with string extractors like potx.
+  t('Image');
+
+  return $fields;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_recipe/schemaorg_recipe.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,113 @@
+<?php
+/**
+ * @file
+ * schemaorg_recipe.features.inc
+ */
+
+/**
+ * Implements hook_rdf_default_mappings().
+ */
+function schemaorg_recipe_rdf_default_mappings() {
+  $schemaorg = array();
+
+  // Exported RDF mapping: recipe
+  $schemaorg['node']['recipe'] = array(
+    'rdftype' => array(
+      0 => 'schema:Recipe',
+      1 => 'v:Recipe',
+    ),
+    'title' => array(
+      'predicates' => array(
+        0 => 'schema:name',
+      ),
+    ),
+    'recipe_instructions' => array(
+      'predicates' => array(
+        0 => 'v:instructions',
+      ),
+    ),
+    'recipe_description' => array(
+      'predicates' => array(
+        0 => 'v:summary',
+      ),
+    ),
+    'recipe_preptime' => array(
+      'predicates' => array(
+        0 => 'v:prepTime',
+      ),
+    ),
+    'recipe_cooktime' => array(
+      'predicates' => array(
+        0 => 'v:cookTime',
+      ),
+    ),
+    'recipe_totaltime' => array(
+      'predicates' => array(
+        0 => 'v:totalTime',
+      ),
+    ),
+    'recipe_yield' => array(
+      'predicates' => array(
+        0 => 'v:yield',
+      ),
+    ),
+    'created' => array(
+      'predicates' => array(
+        0 => 'dc:date',
+        1 => 'dc:created',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'changed' => array(
+      'predicates' => array(
+        0 => 'dc:modified',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'body' => array(
+      'predicates' => array(
+        0 => 'content:encoded',
+      ),
+    ),
+    'uid' => array(
+      'predicates' => array(
+        0 => 'sioc:has_creator',
+      ),
+      'type' => 'rel',
+    ),
+    'name' => array(
+      'predicates' => array(
+        0 => 'schema:name',
+      ),
+    ),
+    'comment_count' => array(
+      'predicates' => array(
+        0 => 'sioc:num_replies',
+      ),
+      'datatype' => 'xsd:integer',
+    ),
+    'last_activity' => array(
+      'predicates' => array(
+        0 => 'sioc:last_activity_date',
+      ),
+      'datatype' => 'xsd:dateTime',
+      'callback' => 'date_iso8601',
+    ),
+    'field_schemaorg_image' => array(
+      'predicates' => array(
+        0 => 'schema:photo',
+      ),
+      'type' => 'rel',
+    ),
+    'url' => array(
+      'predicates' => array(
+        0 => 'schema:url',
+      ),
+      'type' => 'rel',
+    ),
+  );
+
+  return $schemaorg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_recipe/schemaorg_recipe.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+name = "Schema.org example: Recipe"
+description = "Example of a recipe content type with fields mapped to schema.org"
+core = "7.x"
+package = "Schema.org"
+dependencies[] = "features"
+dependencies[] = "image"
+dependencies[] = "rdf"
+dependencies[] = "recipe"
+dependencies[] = "schemaorg"
+features[field][] = "node-recipe-field_schemaorg_image"
+features[schemaorg][] = "node-recipe"
+
+; Information added by drupal.org packaging script on 2012-05-21
+version = "7.x-1.0-beta3"
+core = "7.x"
+project = "schemaorg"
+datestamp = "1337625394"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/example/schemaorg_recipe/schemaorg_recipe.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,7 @@
+<?php
+/**
+ * @file
+ * Code for the Schema.org: Recipe feature.
+ */
+
+include_once('schemaorg_recipe.features.inc');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg.drush.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Drush integration for the schemaorg module.
+ */
+
+/**
+ * Implements hook_drush_command().
+ */
+function schemaorg_drush_command() {
+  $items['schemaorg-json'] = array(
+    'description' => dt('Generates JSON from rdfs.schema.org.'),
+    'options' => array(
+      '--with-comments' => 'Includes comment in the JSON output',
+    ),
+  );
+  return $items;
+}
+
+/**
+ * JSON output command callback.
+ */
+function drush_schemaorg_json() {
+  $data = json_decode(drupal_http_request('http://schema.rdfs.org/all.json')->data);
+
+  $curated_terms = array();
+
+  foreach ($data as $category => $terms) {
+    foreach ($terms as $id => $term) {
+      if (drush_get_option('with-comments')) {
+        // The value and label keys are what the jQuery UI autocomplete excepts.
+        $curated_terms[$category][$id]['value'] = $term->id;
+        $curated_terms[$category][$id]['label'] = $term->id . ': ' . $term->comment_plain;
+      }
+      else {
+        $curated_terms[$category][] = $term->id;
+      }
+    }
+  }
+
+  print json_encode($curated_terms);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg.features.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,101 @@
+<?php
+/**
+ * Implementation of hook_features_export().
+ *
+ * Defines one or more component types that are available to Features for export
+ * and a variety of settings for each type.
+ */
+function schemaorg_features_export($data, &$export, $module_name = '') {
+  // Any feature exporting RDF mappings need the rdf and rdfx modules.
+  $export['dependencies']['rdf'] = 'rdf';
+  $export['dependencies']['schemaorg'] = 'schemaorg';
+
+  foreach ($data as $name) {
+    $parts = explode('-', $name);
+    $entity_type = $parts[0];
+    $bundle_name = $parts[1];
+
+    if ($rdf_mapping = rdf_mapping_load($entity_type, $bundle_name)) {
+      $export['features']['schemaorg'][$entity_type . '-' . $bundle_name] = $rdf_mapping;
+    }
+  }
+
+  return array();
+}
+
+/**
+ * Implementation of hook_features_export_options().
+ *
+ * Provides an array of components that can be exported for a given type.
+ */
+function schemaorg_features_export_options() {
+  $bundles = array();
+
+  foreach (entity_get_info() as $entity_type => $entity) {
+    foreach ($entity['bundles'] as $bundle_name => $bundle) {
+      $bundles[$entity_type . '-' . $bundle_name] = $entity['label'] . ': ' . $bundle['label'];
+    }
+  }
+
+  return $bundles;
+}
+
+/**
+ * Implementation of hook_features_export_render().
+ *
+ * Renders a set of components to code as a defaults hook.
+ */
+function schemaorg_features_export_render($module, $data, $export = NULL) {
+  $code = array();
+  $code[] = '  $schemaorg = array();';
+  $code[] = '';
+
+  foreach ($data as $key => $entity_type_bundle) {
+    if (is_array($entity_type_bundle)) {
+      $entity_type_bundle = $key;
+    }
+    $parts = explode('-', $entity_type_bundle);
+    $entity_type = $parts[0];
+    $bundle_name = $parts[1];
+    if ($rdf_mapping = rdf_mapping_load($entity_type, $bundle_name)) {
+      $rdf_mapping_export = features_var_export($rdf_mapping, '  ');
+      $rdf_bundle = features_var_export($bundle_name);
+      $rdf_entity_type = features_var_export($entity_type);
+      $code[] = "  // Exported RDF mapping: {$bundle_name}";
+      $code[] = "  \$schemaorg[$rdf_entity_type][$rdf_bundle] = $rdf_mapping_export;";
+      $code[] = "";
+    }
+  }
+
+  $code[] = '  return $schemaorg;';
+  $code = implode("\n", $code);
+  return array('rdf_default_mappings' => $code);
+}
+
+/**
+ * Implementation of hook_features_revert().
+ *
+ * Reverts components of a feature back to their default state.
+ */
+function schemaorg_features_revert($module) {
+  return schemaorg_features_rebuild($module);
+}
+
+/**
+ * Implementation of hook_features_rebuild().
+ *
+ * Updates faux-exportable components back to their default state.
+ */
+function schemaorg_features_rebuild($module) {
+  if ($defaults = features_get_default('schemaorg', $module)) {
+    foreach ($defaults as $entity_type => $bundles) {
+      foreach ($bundles as $bundle => $mapping) {
+        rdf_mapping_save(array(
+          'type' => $entity_type,
+          'bundle' => $bundle,
+          'mapping' => $mapping,
+        ));
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,13 @@
+name = Schema.org
+description = Allows to annotate content using the schema.org vocabularies
+package = "Schema.org"
+dependencies[] = rdf
+core = 7.x
+files[] = schemaorg.test
+
+; Information added by drupal.org packaging script on 2012-05-21
+version = "7.x-1.0-beta3"
+core = "7.x"
+project = "schemaorg"
+datestamp = "1337625394"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the node module.
+ */
+
+/**
+ * Enable the schemaorg_ui module for sites which are running an older version
+ * of schema.org which had the UI integrated in the main module.
+ */
+function schemaorg_update_7000() {
+  module_enable(array('schemaorg_ui'));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Enables administrators to annotate their structured content with vocabularies
+ * from schema.org
+ */
+
+/**
+ * Implements hook_help().
+ */
+function schemaorg_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#schemaorg':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('<a href="@schemaorg">Schema.org</a> provides a collection of schemas useful for site builders and administrators to annotate their pages in ways recognized by major search engines including Bing, Google and Yahoo!. These semantic annotations allow search providers to improve the display of search results, making it easier for people to find what they are looking for on the Web. ', array('@schemaorg' => 'http://schema.org/')) . '</p>';
+      $output .= '<p>' . t('Each of your <a href="@content_types">content types</a> and their fields can be mapped to schema.org vocabularies. The type (e.g. Event) and the property of the title (e.g. name) are defined in the edit form of each content type, in the "Schema.org" vertical tab. The property of each field can be set when editing a field, in the schema.org fieldset.', array('@content_types' => url('admin/structure/types'))) . '</p>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_entity_view().
+ */
+function schemaorg_entity_view($entity, $type, $view_mode, $langcode) {
+  // Adds the schema.org url to the entity content as RDF metadata.
+  if (!empty($entity->rdf_mapping['url']['predicates'])) {
+    $attributes = rdf_rdfa_attributes($entity->rdf_mapping['url']);
+    $uri = entity_uri($type, $entity);
+    $attributes['resource'] = url($uri['path'], $uri['options']);
+    $entity->content['schemaorg_url'] = array(
+      '#markup' => theme('rdf_metadata', array('metadata' => array('span' => $attributes))),
+      '#weight' => 100,
+    );
+  }
+
+  // It seems parsers are expecting to find the title/name of the entity within
+  // the main content of the entity. Drupal displays the title outside the main
+  // content on full entity display, so we assert it as hidden RDF metadata.
+  foreach (array('title', 'subject', 'name') as $field_name) {
+    if (!empty($entity->{$field_name})) {
+      $label_field = $field_name;
+      break;
+    }
+  }
+  if (isset($label_field) && !empty($entity->rdf_mapping[$label_field]['predicates'])) {
+    $attributes = rdf_rdfa_attributes($entity->rdf_mapping[$label_field]);
+    $attributes['content'] = $entity->{$label_field};
+    $entity->content['schemaorg_name'] = array(
+      '#markup' => theme('rdf_metadata', array('metadata' => array('span' => $attributes))),
+      '#weight' => 100,
+    );
+  }
+}
+
+/**
+ * Implements hook_rdf_namespaces().
+ */
+function schemaorg_rdf_namespaces() {
+  return array(
+    'schema' => 'http://schema.org/',
+  );
+}
+
+/**
+ * Implementation of hook_features_api().
+ */
+function schemaorg_features_api() {
+  return array(
+    'schemaorg' => array(
+      'name' => t('Schema.org mappings'),
+      'default_hook' => 'rdf_default_mappings',
+      'file' => drupal_get_path('module', 'schemaorg') .'/schemaorg.features.inc',
+    ),
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,228 @@
+<?php
+
+/**
+ * @file
+ * Tests for schemaorg.module.
+ */
+
+/**
+ * Tests for schema.org namespaces declaration.
+ */
+class SchemaorgNamespaceTestCase extends DrupalWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Schema.org namespace',
+      'description' => 'Test the presence of the schema.org namespace in the page markup and in rdf_get_namespaces().',
+      'group' => 'Schema.org',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('schemaorg');
+  }
+
+  /**
+   * Test getting RDF namesapces.
+   */
+  function testSchemaorgNamespace() {
+    // Get all RDF namespaces.
+    $ns = rdf_get_namespaces();
+    $this->assertEqual($ns['schema'], 'http://schema.org/', t('Schema.org namespace is returned by rdf_get_namespaces().'));
+
+    // Fetches the front page and extracts XML namespaces.
+    $this->drupalGet('');
+    $xml = new SimpleXMLElement($this->content);
+    $ns = $xml->getDocNamespaces();
+    $this->assertEqual($ns['schema'], 'http://schema.org/', t('Schema.org namespace is present in the HTML document.'));
+  }
+}
+
+/**
+ * Schema.org Field UI tests.
+ */
+class SchemaorgFieldUIManageFieldsTestCase extends FieldUITestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Field UI schema.org form elements',
+      'description' => 'Test the schema.org form element in the Field UI.',
+      'group' => 'Schema.org',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('schemaorg', 'schemaorg_ui');
+
+    // Create random field name.
+    $this->field_label = $this->randomName(8);
+    $this->field_name_input =  strtolower($this->randomName(8));
+    $this->field_name = 'field_'. $this->field_name_input;
+  }
+
+  /**
+   * Tests that schema.org terms are saved on the content type edit form.
+   */
+  function testNodeTypeEditing() {
+    $admin_path = 'admin/structure/types/manage/page';
+    $type_element_id = 'edit-schemaorg-ui-type';
+    $type_element_name = 'schemaorg_ui_type';
+
+    $this->drupalGet($admin_path);
+    $this->assertFieldById($type_element_id, '', t('The schema.org type was empty.'));
+
+    // Check that the schema.org terms are saved.
+    $edit = array();
+    $edit[$type_element_name] = 'WebPage';
+    $this->drupalPost($admin_path, $edit, t('Save content type'));
+    $this->assertText("The content type Basic page has been updated.", t('The form was successfully submitted.'));
+    entity_info_cache_clear();
+    $rdf_mapping = rdf_mapping_load('node', 'page');
+    $rdf_mapping_type_expected = array(
+      'schema:WebPage',
+      'foaf:Document',
+    );
+    $this->assertEqual($rdf_mapping['rdftype'], $rdf_mapping_type_expected, t('The schema.org type was correctly saved.'));
+
+    // Check that the schema.org terms shows up in the form
+    $this->drupalGet($admin_path);
+    $this->assertFieldById($type_element_id, 'WebPage', t('The schema.org type form element was displayed with the correct value.'));
+
+    // Check that the schema.org type can be emptied.
+    $edit = array();
+    $edit[$type_element_name] = '';
+    $this->drupalPost($admin_path, $edit, t('Save content type'));
+    $this->assertText("The content type Basic page has been updated.", t('The form was successfully submitted.'));
+    entity_info_cache_clear();
+    $rdf_mapping = rdf_mapping_load('node', 'page');
+    $rdf_mapping_type_expected = array(
+      1 => 'foaf:Document',
+    );
+    $this->assertEqual($rdf_mapping['rdftype'], $rdf_mapping_type_expected, t('The schema.org type mapping was correctly saved.'));
+  }
+
+  /**
+   * Tests that schema.org property is correctly saved.
+   */
+  function testFieldUIManageFields() {
+    // Create a test field and instance.
+    $field_name = 'test';
+    $field = array(
+      'field_name' => $field_name,
+      'type' => 'test_field'
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'node',
+      'bundle' => $this->type,
+    );
+    field_create_instance($instance);
+
+    $langcode = LANGUAGE_NONE;
+    $admin_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $field_name;
+    $element_id = 'edit-schemaorg-ui-field-property';
+    $element_name = 'schemaorg_ui_field_property';
+    $this->drupalGet($admin_path);
+    $this->assertFieldById($element_id, '', t('The schema.org property was empty.'));
+
+    // Check that the schema.org property is saved.
+    $edit = array($element_name => 'telephone');
+    $this->drupalPost($admin_path, $edit, t('Save settings'));
+    $this->assertText("Saved $field_name configuration", t('The form was successfully submitted.'));
+    $rdf_mapping = rdf_mapping_load('node', $this->type);
+    $rdf_mapping_title_expected = array(
+      'predicates' => array(
+        'schema:name',
+      ),
+    );
+    $rdf_mapping_url_expected = array(
+      'predicates' => array(
+        'schema:url',
+      ),
+      'type' => 'rel',
+    );
+    $rdf_mapping_field_expected = array(
+      'predicates' => array(
+        'schema:telephone',
+      ),
+    );
+    $this->assertEqual($rdf_mapping['title'], $rdf_mapping_title_expected, t('The schema.org title property was correctly saved.'));
+    $this->assertEqual($rdf_mapping['url'], $rdf_mapping_url_expected, t('The schema.org url property was correctly saved.'));
+    $this->assertEqual($rdf_mapping[$field_name], $rdf_mapping_field_expected, t('The schema.org property was correctly saved.'));
+
+    // Check that the schema.org property shows up in the form
+    $this->drupalGet($admin_path);
+    $this->assertFieldById($element_id, 'telephone', t('The schema.org property form element was displayed with the correct value.'));
+
+    // Check that the schema.org property can be emptied.
+    $edit = array($element_name => '');
+    $this->drupalPost($admin_path, $edit, t('Save settings'));
+    $this->assertText("Saved $field_name configuration", t('The form was successfully submitted.'));
+    entity_info_cache_clear();
+    $rdf_mapping = rdf_mapping_load('node', $this->type);
+    $rdf_mapping_title_expected = array(
+      'predicates' => array(),
+    );
+    $rdf_mapping_field_expected = array(
+      'predicates' => array(),
+    );
+    $this->assertEqual($rdf_mapping['title'], $rdf_mapping_title_expected, t('The schema.org title mapping was correctly saved.'));
+    $this->assertTrue(!isset($rdf_mapping['url']), t('The schema.org url mapping was correctly removed.'));
+    $this->assertEqual($rdf_mapping[$field_name], $rdf_mapping_field_expected, t('The schema.org property was correctly saved.'));
+  }
+
+  /**
+   * Tests that schema.org property is correctly saved for advanced fields
+   * where the object is a resource (image, file, reference).
+   */
+  function testFieldUIManageFieldsReference() {
+    // Create a test field and instance.
+    $field_name = 'test';
+    $field = array(
+      'field_name' => $field_name,
+      'type' => 'taxonomy_term_reference'
+    );
+    field_create_field($field);
+    $instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'node',
+      'bundle' => $this->type,
+    );
+    field_create_instance($instance);
+
+    $langcode = LANGUAGE_NONE;
+    $admin_path = 'admin/structure/types/manage/' . $this->hyphen_type . '/fields/' . $field_name;
+    $element_id = 'edit-schemaorg-ui-field-property';
+    $element_name = 'schemaorg_ui_field_property';
+    $this->drupalGet($admin_path);
+    $this->assertFieldById($element_id, '', t('The schema.org property was empty.'));
+
+    // Check that the schema.org property is saved.
+    $edit = array($element_name => 'telephone');
+    $this->drupalPost($admin_path, $edit, t('Save settings'));
+    $this->assertText("Saved $field_name configuration", t('The form was successfully submitted.'));
+    $rdf_mapping = rdf_mapping_load('node', $this->type);
+    $rdf_mapping_field_expected = array(
+      'predicates' => array(
+        'schema:telephone',
+      ),
+      'type' => 'rel',
+    );
+    $this->assertEqual($rdf_mapping[$field_name], $rdf_mapping_field_expected, t('The schema.org property was correctly saved.'));
+
+    // Check that the schema.org property shows up in the form
+    $this->drupalGet($admin_path);
+    $this->assertFieldById($element_id, 'telephone', t('The schema.org property form element was displayed with the correct value.'));
+
+    // Check that the schema.org property can be emptied.
+    $edit = array($element_name => '');
+    $this->drupalPost($admin_path, $edit, t('Save settings'));
+    $this->assertText("Saved $field_name configuration", t('The form was successfully submitted.'));
+    entity_info_cache_clear();
+    $rdf_mapping = rdf_mapping_load('node', $this->type);
+    $rdf_mapping_field_expected = array(
+      'predicates' => array(),
+      'type' => 'rel',
+    );
+    $this->assertEqual($rdf_mapping[$field_name], $rdf_mapping_field_expected, t('The schema.org property was correctly saved.'));
+  }
+}
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_flat_0_aaaaaa_40x100.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_flat_75_ffffff_40x100.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_55_fbf9ee_1x400.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_65_ffffff_1x400.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_75_dadada_1x400.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_75_e6e6e6_1x400.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_glass_95_fef1ec_1x400.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_222222_256x240.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_2e83ff_256x240.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_454545_256x240.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_888888_256x240.png has changed
Binary file sites/all/modules/schemaorg/schemaorg_ui/css/images/ui-icons_cd0a0a_256x240.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg_ui/css/schemaorg_ui.jquery.ui.theme.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,256 @@
+/* The seven core theme overrides the default jQuery UI theme and breakd the
+   autocomplete. Reapply it here until this is fixed
+   see http://drupal.org/node/896728 */
+
+/*
+ * jQuery UI CSS Framework 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; }
+.ui-widget-content a { color: #222222/*{fcContent}*/; }
+.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; }
+.ui-widget-header a { color: #222222/*{fcHeader}*/; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight  {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary,  .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-right {  -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
+.ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; border-radius: 4px/*{cornerRadius}*/; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
+.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg_ui/js/schemaorg_ui.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,23 @@
+(function ($) {
+
+/**
+ * Attach schemaorg behavior for autocomplete.
+ */
+Drupal.behaviors.schemaorgs = {
+  attach: function(context) {
+    $.getJSON(Drupal.settings.schemaorguiapiTermsPath, function(data) {
+      $("input.schemaorg-ui-autocomplete-types").autocomplete({
+        source: data.types,
+        delay: 0,
+      });
+      $("input.schemaorg-ui-autocomplete-properties").autocomplete({
+        source: data.properties,
+        delay: 0,
+      });
+   });
+
+  }
+};
+
+
+})(jQuery);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg_ui/js/schemaorg_ui.terms.json	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,1 @@
+{"datatypes":["Boolean","DataType","Date","Float","Integer","Number","Text","URL"],"properties":["about","acceptsReservations","accountablePerson","actors","additionalName","address","addressCountry","addressLocality","addressRegion","affiliation","aggregateRating","albums","alternativeHeadline","alumni","alumniOf","articleBody","articleSection","associatedArticle","associatedMedia","attendees","audio","author","availability","awards","baseSalary","benefits","bestRating","birthDate","bitrate","blogPosts","bookEdition","bookFormat","box","branchOf","brand","breadcrumb","byArtist","calories","caption","carbohydrateContent","children","cholesterolContent","circle","colleagues","comment","commentText","commentTime","contactPoints","contactType","containedIn","contentLocation","contentRating","contentSize","contentURL","contributor","cookTime","cookingMethod","copyrightHolder","copyrightYear","creator","currenciesAccepted","dateCreated","dateModified","datePosted","datePublished","dateline","deathDate","description","director","discusses","discussionUrl","duration","editor","educationRequirements","elevation","email","embedURL","employees","employmentType","encodesCreativeWork","encodingFormat","encodings","endDate","episodeNumber","episodes","events","exifData","experienceRequirements","expires","familyName","fatContent","faxNumber","fiberContent","follows","founders","foundingDate","gender","genre","geo","givenName","headline","height","highPrice","hiringOrganization","homeLocation","honorificPrefix","honorificSuffix","illustrator","image","inAlbum","inLanguage","inPlaylist","incentives","industry","ingredients","interactionCount","isFamilyFriendly","isPartOf","isbn","itemCondition","itemListElement","itemListOrder","itemOffered","itemReviewed","jobLocation","jobTitle","keywords","knows","latitude","line","location","longitude","lowPrice","mainContentOfPage","manufacturer","maps","memberOf","members","mentions","menu","model","musicBy","musicGroupMember","name","nationality","numTracks","numberOfEpisodes","numberOfPages","nutrition","occupationalCategory","offerCount","offers","openingHours","parents","partOfSeason","partOfTVSeries","paymentAccepted","performerIn","performers","photos","playerType","polygon","postOfficeBoxNumber","postalCode","prepTime","price","priceCurrency","priceRange","priceValidUntil","primaryImageOfPage","printColumn","printEdition","printPage","printSection","producer","productID","productionCompany","proteinContent","provider","publisher","publishingPrinciples","qualifications","ratingCount","ratingValue","recipeCategory","recipeCuisine","recipeInstructions","recipeYield","regionsAllowed","relatedTo","replyToUrl","representativeOfPage","requiresSubscription","responsibilities","reviewBody","reviewCount","reviewRating","reviews","salaryCurrency","saturatedFatContent","seasonNumber","seasons","seller","servesCuisine","servingSize","siblings","significantLinks","skills","sodiumContent","sourceOrganization","specialCommitments","spouse","startDate","streetAddress","subEvents","sugarContent","superEvent","telephone","thumbnail","thumbnailUrl","tickerSymbol","title","totalTime","tracks","trailer","transFatContent","transcript","unsaturatedFatContent","uploadDate","url","version","video","videoFrameSize","videoQuality","width","wordCount","workHours","workLocation","worksFor","worstRating"],"types":["AboutPage","AccountingService","AdministrativeArea","AdultEntertainment","AggregateOffer","AggregateRating","Airport","AmusementPark","AnimalShelter","ApartmentComplex","Aquarium","ArtGallery","Article","Attorney","AudioObject","AutoBodyShop","AutoDealer","AutoPartsStore","AutoRental","AutoRepair","AutoWash","AutomatedTeller","AutomotiveBusiness","Bakery","BankOrCreditUnion","BarOrPub","Beach","BeautySalon","BedAndBreakfast","BikeStore","Blog","BlogPosting","BodyOfWater","Book","BookFormatType","BookStore","BowlingAlley","Brewery","BuddhistTemple","BusStation","BusStop","BusinessEvent","CafeOrCoffeeShop","Campground","Canal","Casino","CatholicChurch","Cemetery","CheckoutPage","ChildCare","ChildrensEvent","Church","City","CityHall","CivicStructure","ClothingStore","CollectionPage","CollegeOrUniversity","ComedyClub","ComedyEvent","ComputerStore","ContactPage","ContactPoint","Continent","ConvenienceStore","Corporation","Country","Courthouse","CreativeWork","Crematorium","DanceEvent","DanceGroup","DaySpa","DefenceEstablishment","Dentist","DepartmentStore","Distance","DryCleaningOrLaundry","Duration","EducationEvent","EducationalOrganization","Electrician","ElectronicsStore","ElementarySchool","Embassy","EmergencyService","EmploymentAgency","Energy","EntertainmentBusiness","Enumeration","Event","EventVenue","ExerciseGym","FastFoodRestaurant","Festival","FinancialService","FireStation","Florist","FoodEstablishment","FoodEvent","FurnitureStore","GardenStore","GasStation","GatedResidenceCommunity","GeneralContractor","GeoCoordinates","GeoShape","GolfCourse","GovernmentBuilding","GovernmentOffice","GovernmentOrganization","GroceryStore","HVACBusiness","HairSalon","HardwareStore","HealthAndBeautyBusiness","HealthClub","HighSchool","HinduTemple","HobbyShop","HomeAndConstructionBusiness","HomeGoodsStore","Hospital","Hostel","Hotel","HousePainter","IceCreamShop","ImageGallery","ImageObject","InsuranceAgency","Intangible","InternetCafe","ItemAvailability","ItemList","ItemPage","JewelryStore","JobPosting","LakeBodyOfWater","Landform","LandmarksOrHistoricalBuildings","Language","LegislativeBuilding","Library","LiquorStore","LiteraryEvent","LocalBusiness","Locksmith","LodgingBusiness","Map","Mass","MediaObject","MedicalClinic","MedicalOrganization","MensClothingStore","MiddleSchool","MobilePhoneStore","Mosque","Motel","MotorcycleDealer","MotorcycleRepair","Mountain","Movie","MovieRentalStore","MovieTheater","MovingCompany","Museum","MusicAlbum","MusicEvent","MusicGroup","MusicPlaylist","MusicRecording","MusicStore","MusicVenue","MusicVideoObject","NGO","NailSalon","NewsArticle","NightClub","Notary","NutritionInformation","OceanBodyOfWater","Offer","OfferItemCondition","OfficeEquipmentStore","Optician","Organization","OutletStore","Painting","Park","ParkingFacility","PawnShop","PerformingArtsTheater","PerformingGroup","Person","PetStore","Pharmacy","Photograph","Physician","Place","PlaceOfWorship","Playground","Plumber","PoliceStation","Pond","PostOffice","PostalAddress","Preschool","Product","ProfessionalService","ProfilePage","PublicSwimmingPool","Quantity","RVPark","RadioStation","Rating","RealEstateAgent","Recipe","RecyclingCenter","Reservoir","Residence","Restaurant","Review","RiverBodyOfWater","RoofingContractor","SaleEvent","ScholarlyArticle","School","Sculpture","SeaBodyOfWater","SearchResultsPage","SelfStorage","ShoeStore","ShoppingCenter","SingleFamilyResidence","SiteNavigationElement","SkiResort","SocialEvent","SportingGoodsStore","SportsActivityLocation","SportsClub","SportsEvent","SportsTeam","StadiumOrArena","State","Store","StructuredValue","SubwayStation","Synagogue","TVEpisode","TVSeason","TVSeries","Table","TattooParlor","TaxiStand","TelevisionStation","TennisComplex","TheaterEvent","TheaterGroup","Thing","TireShop","TouristAttraction","TouristInformationCenter","ToyStore","TrainStation","TravelAgency","UserBlocks","UserCheckins","UserComments","UserDownloads","UserInteraction","UserLikes","UserPageVisits","UserPlays","UserPlusOnes","UserTweets","VeterinaryCare","VideoGallery","VideoObject","VisualArtsEvent","Volcano","WPAdBlock","WPFooter","WPHeader","WPSideBar","Waterfall","WebPage","WebPageElement","WholesaleStore","Winery","Zoo"]}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg_ui/schemaorg_ui.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Schema.org UI
+description = User interface for setting the schema.org module mappings.
+package = "Schema.org"
+dependencies[] = rdf
+dependencies[] = schemaorg
+core = 7.x
+files[] = schemaorg.test
+
+; Information added by drupal.org packaging script on 2012-05-21
+version = "7.x-1.0-beta3"
+core = "7.x"
+project = "schemaorg"
+datestamp = "1337625394"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/schemaorg/schemaorg_ui/schemaorg_ui.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,234 @@
+<?php
+
+/**
+ * @file
+ * User interface for setting the schema.org mappings
+ */
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function schemaorg_ui_form_node_type_form_alter(&$form, $form_state) {
+  if (isset($form['type'])) {
+    $bundle = $form['#node_type']->type;
+    $form['schemaorg_ui'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Schema.org settings'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      '#group' => 'additional_settings',
+    );
+    $form['schemaorg_ui']['schemaorg_ui_type'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Type'),
+      '#description' => t('Specify the type you want to associated to this content type e.g. Article, Blog, etc.'),
+      '#default_value' => schemaorg_ui_term_load('node', $bundle, 'rdftype'),
+      '#attributes' => array('class' => array('schemaorg-ui-autocomplete-types')),
+    );
+    $form['#submit'][] = 'schemaorg_ui_node_type_form_submit';
+    // Use jQuery UI autocomplete to provide a faster autocomplete without
+    // callback to the server.
+    $form['#attached']['library'][] = array('system', 'ui.autocomplete');
+    $form['#attached']['css'][] = drupal_get_path('module', 'schemaorg_ui') . '/css/schemaorg_ui.jquery.ui.theme.css';
+    $form['#attached']['js'][] = drupal_get_path('module', 'schemaorg_ui') . '/js/schemaorg_ui.js';
+    $form['#attached']['js'][] =  array(
+          'data' => array('schemaorguiapiTermsPath' => base_path() . drupal_get_path('module', 'schemaorg_ui') . '/js/schemaorg_ui.terms.json'),
+          'type' => 'setting'
+    );
+  }
+}
+
+/**
+ * Submit function for node type form.
+ */
+function schemaorg_ui_node_type_form_submit($form, &$form_state) {
+  $bundle = $form_state['values']['type'];
+  $mapping = rdf_mapping_load('node', $bundle);
+  $mapping['rdftype'] = schemaorg_ui_terms_merge($form_state['values']['schemaorg_ui_type'], $mapping['rdftype']);
+
+  rdf_mapping_save(array(
+    'type' => 'node',
+    'bundle' => $bundle,
+    'mapping' => $mapping,
+    )
+  );
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function schemaorg_ui_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
+  $field_name = $form['#field']['field_name'];
+  $bundle = $form['instance']['bundle']['#value'];
+  $instance = $form['instance'];
+  $label = isset($instance['label']) ? $instance['label']['#default_value'] : $instance['field_name'];
+  $entity_type = $instance['entity_type']['#value'];
+  $mapping = rdf_mapping_load($entity_type, $instance['bundle']['#value']);
+
+  $form['schemaorg_ui'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('%label schema.org mapping', array('%label' => $label)),
+  );
+
+  $form['schemaorg_ui']['schemaorg_ui_field_property'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Property'),
+    '#description' => t('Specify the property you want to associated to this field.'),
+    '#default_value' => schemaorg_ui_term_load($entity_type, $bundle, $field_name),
+    '#attributes' => array('class' => array('schemaorg-ui-autocomplete-properties')),
+  );
+
+  $form['#submit'][] = 'schemaorg_ui_field_ui_field_edit_form_submit';
+  // Use jQuery UI autocomplete to provide a faster autocomplete without
+  // callback to the server.
+  $form['#attached']['library'][] = array('system', 'ui.autocomplete');
+  $form['#attached']['css'][] = drupal_get_path('module', 'schemaorg_ui') . '/css/schemaorg_ui.jquery.ui.theme.css';
+  $form['#attached']['js'][] = drupal_get_path('module', 'schemaorg_ui') . '/js/schemaorg_ui.js';
+  $form['#attached']['js'][] =  array(
+        'data' => array('schemaorguiapiTermsPath' => base_path() . drupal_get_path('module', 'schemaorg_ui') . '/js/schemaorg_ui.terms.json'),
+        'type' => 'setting'
+  );
+}
+
+/**
+ * Submit function for edit field form.
+ */
+function schemaorg_ui_field_ui_field_edit_form_submit($form, &$form_state) {
+  $entity_type = $form['#instance']['entity_type'];
+  $bundle = $form['#instance']['bundle'];
+  $field_name = $form['#field']['field_name'];
+  $field_type = $form['#field']['type'];
+
+  $mapping = rdf_mapping_load($entity_type, $bundle);
+
+  // This field might not have an RDF mapping yet.
+  if (empty($mapping[$field_name])) {
+    $mapping[$field_name]['predicates'] = array();
+  }
+
+  $mapping[$field_name]['predicates'] = schemaorg_ui_terms_merge($form_state['values']['schemaorg_ui_field_property'], $mapping[$field_name]['predicates']);
+
+  // Sets RDF mapping type in the case of fields where the object is a resource
+  // such as image, file, etc.
+  $rel_field_types = array('image', 'file', 'taxonomy_term_reference');
+  if (in_array($field_type, $rel_field_types)) {
+    $mapping[$field_name]['type'] = 'rel';
+  }
+
+  // Some terms from schema.org are not yet supported, and legacy properties
+  // are being used instead. The legacy property is added to the RDF mappings
+  // along with the official property.
+  $property = $form_state['values']['schemaorg_ui_field_property'];
+  $legacy_properties = array(
+    'description' => 'summary',
+  );
+  if (array_key_exists($property, $legacy_properties)) {
+    array_unshift($mapping[$field_name]['predicates'], 'schema:' . $legacy_properties[$property]);
+  }
+
+  // Performs some maintenance tasks based on whether the mapping contains
+  // schema.org terms or not.
+  // Scans the mapping array to see if some fields are mapped to schema.org.
+  $schemaorg_mappings = FALSE;
+  // Some fields are ignored since they are not input by the user.
+  $ignored_fields = array('title', 'name', 'url');
+  foreach ($mapping as $field => $info) {
+    if (!empty($info['predicates']) && !in_array($field, $ignored_fields)) {
+      if (count($info['predicates']) != count(array_filter($info['predicates'], 'schemaorg_ui_filter_schema_term'))) {
+        $schemaorg_mappings = TRUE;
+        break;
+      }
+    }
+  }
+  if ($schemaorg_mappings) {
+    // Specifies the title/name mapping as expected by schema.org. This mapping
+    // is always set to schema:name and is not exposed in the UI.
+    // The label of an entity is usually either 'title' (e.g. node) or
+    // 'name' (e.g. user).
+    if (!empty($mapping['title'])) {
+      $mapping['title']['predicates'] = array('schema:name');
+    }
+    if (!empty($mapping['name'])) {
+      $mapping['name']['predicates'] = array('schema:name');
+    }
+    // Sets the mapping for the url of the entity. This mapping is always set
+    // to schema:url and is not exposed in the UI.
+    $mapping['url']['predicates'] = array('schema:url');
+    $mapping['url']['type'] = 'rel';
+    // Add schema:Person type to user mapping.
+    if ($entity_type == 'user' && $bundle == 'user' ) {
+      $mapping['rdftype'] = schemaorg_ui_terms_merge('Person', $mapping['rdftype']);
+    }
+  }
+  else {
+    // Makes sure no schema.org mapping for title/name remains if no schema.org
+    // terms are used.
+    if (!empty($mapping['title'])) {
+      $mapping['title']['predicates'] = array_filter($mapping['title']['predicates'], 'schemaorg_ui_filter_schema_term');
+    }
+    if (!empty($mapping['name'])) {
+      $mapping['name']['predicates'] = array_filter($mapping['name']['predicates'], 'schemaorg_ui_filter_schema_term');
+    }
+    // Since this pseudo-field mapping is only used for the purpose of
+    // schema.org, it is entirely removed.
+    unset($mapping['url']);
+    // Remove schema.org type from the user mapping.
+    if ($entity_type == 'user' && $bundle == 'user' ) {
+      $mapping['rdftype'] = array_filter($mapping['rdftype'], 'schemaorg_ui_filter_schema_term');
+    }
+  }
+
+  rdf_mapping_save(array(
+    'type' => $entity_type,
+    'bundle' => $bundle,
+    'mapping' => $mapping,
+    )
+  );
+}
+
+/**
+ * Loads the schema.org term for a particular Drupal field or rdftype.
+ */
+function schemaorg_ui_term_load($type, $bundle, $field) {
+  $terms = array();
+  $mapping = rdf_mapping_load($type, $bundle);
+  if ($field == 'rdftype') {
+    $terms = $mapping['rdftype'];
+  }
+  elseif (!empty($mapping[$field]['predicates'])) {
+    $terms = $mapping[$field]['predicates'];
+  }
+  // Return the first schema: term.
+  foreach ($terms as $term) {
+    if (strpos(trim($term), 'schema:') === 0) {
+      return str_replace('schema:', '', $term);
+    }
+  }
+}
+
+/**
+ * Add, update or remove a schema term from a set of terms.
+ */
+function schemaorg_ui_terms_merge($schema_term, $terms) {
+  // Strip out existing schema.org mappings.
+  if (empty($terms)) {
+    $terms = array();
+  }
+  $terms = array_filter($terms, 'schemaorg_ui_filter_schema_term');
+
+  if ($schema_term) {
+    // Place the schema term first for commodity so it appears first in the
+    // list of CURIEs in the HTML output.
+    array_unshift($terms, 'schema:' . $schema_term);
+  }
+  return $terms;
+}
+
+/**
+ * Filters out non schema: terms.
+ *
+ * @see schemaorg_ui_terms_merge()
+ */
+function schemaorg_ui_filter_schema_term($term) {
+  return strpos(trim($term), 'schema:') !== 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,84 @@
+
+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
+*            Welcome to Search Autocomplete v7.x-3.x !
+* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*
+
+ ***
+ * Search Autocomplete
+ * Enables autocomplete functionality on search fields.
+ ***
+ 
+ @authors
+ Miroslav (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+
+ Sponsored by:
+ www.axiomcafe.fr
+
+--------------------------------------------------------------------------------- 
+-- 1.  Installing Search Autocomplete:
+
+Place the entirety of this directory in sites/all/modules/search_autocomplete 
+or in the equivalent directory of your Drupal installation.
+
+Make sure all dependency modules are available: Drupal Search Core and Views
+
+Navigate to administer >> build >> modules. Enable Search Autocomplete.
+
+If you're having trouble installing this module, please ensure that your tar 
+program is not flattening the directory tree, truncating filenames or losing 
+files.
+
+--------------------------------------------------------------------------------- 
+-- 2.  Updating Search Autocomplete:
+
+BEWARE: Update to 7.x-3.x from 7.x-2.x will lose every previous configuration. Please make
+sure you can produce the suggestion set you need using views. This should be 
+easy !
+
+Delete every files in the module directory sites/all/modules/search_autocomplete 
+or in the equivalent directory of your Drupal installation.
+
+Place all files from this 3.x version in this sites/all/modules/search_autocomplete
+or equivalent folder.
+
+Run the update script. Make sure to run the update functions.
+
+If you're having trouble installing this module, please ensure that your tar 
+program is not flattening the directory tree, truncating filenames or losing 
+files.
+You can also perform a full and complete uninstall of Search Autocomplete and try to
+re-install.
+
+Another solution would be to refer to the documentation: 
+http://projects.axiomcafe.fr/search-autocomplete
+
+Finally, you can also post an issue at:
+https://drupal.org/project/issues/search_autocomplete
+
+---------------------------------------------------------------------------------
+-- 3.  Setting Search Autocomplete
+
+Navigate to /admin/config/search/search_autocomplete
+
+The configuration options are not as quite easy to understand as it was in previous
+version. Please consider reading the documentation available at:
+http://projects.axiomcafe.fr/search-autocomplete
+
+---------------------------------------------------------------------------------
+-- 4.  Translating Search Autocomplete
+
+Please visit the module translation page to download translation:
+http://localize.drupal.org/translate/downloads?project=search_autocomplete.
+
+Please refer to section 5 (Helping) for typo, grammar or language issues.
+
+---------------------------------------------------------------------------------
+-- 5.  Helping and complaining on Search Autocomplete
+
+To help this module live, please post your issues, ideas and comments at:
+http://drupal.org/node/add/project-issue/search_autocomplete
+and view issues at:
+http://drupal.org/project/issues/search_autocomplete
+
+
+The maintainer: Miroslav
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/css/MAKE YOUR THEME.css_	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,78 @@
+/*
+ * SEARCH AUTOCOMPLETE (version 7.3-x)
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+ 
+ /**
+  * THEME CUSTOM
+  */ 
+
+  
+/*******     DO NOT CHANGE ANYTHING IN HERE : have a look at the end of css file ***********/  
+/* AUTOCOMPLETE  : */
+.ui-autocomplete { position: absolute; cursor: default; }	
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-autocomplete-input {
+  background-image: url("images/throbber.gif");
+  background-position: 100% 4px;
+  background-repeat: no-repeat;
+}
+.ui-autocomplete-loading {
+  background-image: url("images/throbber.gif");
+  background-position: 100% -16px;
+  background-repeat: no-repeat;
+}
+.ui-menu {
+	list-style:none;
+	padding: 2px;
+	margin: 0;
+	display:block;
+	float: left;
+}
+.ui-menu .ui-menu {
+	margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+	margin:0;
+	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
+	width: 100%;
+}
+.ui-menu .ui-menu-item a {
+	text-decoration:none;
+	display:block;
+	padding:.2em .4em;
+	line-height:1.5;
+	zoom:1;
+}
+.ui-menu .ui-menu-item a {
+	font-weight: normal;
+	margin: -1px;
+}
+
+/************************************************************/
+/*******     MAKE YOUR CUSTOM CHANGES IN HERE     ***********/  
+    
+/* make even odd distinction */
+#ui-theme-YOUR-THEME-NAME .ui-menu-item-odd { }
+#ui-theme-YOUR-THEME-NAME .ui-menu-item-even { }
+  
+/* Component containers */
+#ui-theme-YOUR-THEME-NAME { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
+#ui-theme-YOUR-THEME-NAME a { color: #333333; }
+
+/* Corner radius */
+#ui-theme-YOUR-THEME-NAME .ui-corner-all { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+#ui-theme-YOUR-THEME-NAME .ui-corner-all { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+#ui-theme-YOUR-THEME-NAME .ui-corner-all { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+#ui-theme-YOUR-THEME-NAME .ui-corner-all { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+
+/* Interaction States */
+#ui-theme-YOUR-THEME-NAME .ui-state-hover { border: 1px solid #fbcb09; background-image: none; font-weight: normal;}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/css/classic.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,78 @@
+/*
+ * SEARCH AUTOCOMPLETE (version 7.3-x)
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+ 
+ /**
+  * THEME NICE ORANGE
+  */ 
+
+  
+  
+/* AUTOCOMPLETE 
+----------------------------------*/
+.ui-autocomplete { position: absolute; cursor: default; }	
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-autocomplete-input {
+  background-image: url("images/throbber.gif");
+  background-position: 100% 4px;
+  background-repeat: no-repeat;
+}
+.ui-autocomplete-loading {
+  background-image: url("images/throbber.gif");
+  background-position: 100% -16px;
+  background-repeat: no-repeat;
+}
+.ui-menu {
+	list-style:none;
+	padding: 2px;
+	margin: 0;
+	display:block;
+	float: left;
+}
+.ui-menu .ui-menu {
+	margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+	margin:0;
+	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
+	width: 100%;
+}
+.ui-menu .ui-menu-item a {
+	text-decoration:none;
+	display:block;
+	padding:.2em .4em;
+	line-height:1.5;
+	zoom:1;
+}
+.ui-menu .ui-menu-item a {
+	font-weight: normal;
+	margin: -1px;
+}
+
+/* make even odd distinction */
+#ui-theme-classic .ui-menu-item-odd {
+	background-color: #eeeeee;
+}
+#ui-theme-classic .ui-menu-item-even { }
+
+/* Component containers */
+#ui-theme-classic { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
+#ui-theme-classic a { color: #333333; }
+
+/* Corner radius */
+#ui-theme-classic .ui-corner-all { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+#ui-theme-classic .ui-corner-all { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+#ui-theme-classic .ui-corner-all { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+#ui-theme-classic .ui-corner-all { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+
+/* Interaction States */
+#ui-theme-classic .ui-state-hover { font-weight: normal; border: none; background-image: none; background-color: #0A246A; color: white; }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/css/full paper brown.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,85 @@
+/*
+ * SEARCH AUTOCOMPLETE (version 7.3-x)
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+ 
+ /**
+  * THEME FULL PAPER BROWN
+  */ 
+
+  
+/* AUTOCOMPLETE 
+----------------------------------*/
+.ui-autocomplete { position: absolute; cursor: default; }	
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-autocomplete-input {
+  background-image: url("images/throbber.gif");
+  background-position: 100% 4px;
+  background-repeat: no-repeat;
+}
+.ui-autocomplete-loading {
+  background-image: url("images/throbber.gif");
+  background-position: 100% -16px;
+  background-repeat: no-repeat;
+}
+.ui-menu {
+	list-style:none;
+	padding: 2px;
+	margin: 0;
+	display:block;
+	float: left;
+}
+.ui-menu .ui-menu {
+	margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+	margin:0;
+	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
+	width: 100%;
+}
+.ui-menu .ui-menu-item a {
+	text-decoration:none;
+	display:block;
+	padding:.2em .4em;
+	line-height:1.5;
+	zoom:1;
+}
+.ui-menu .ui-menu-item a {
+	font-weight: normal;
+	margin: -1px;
+}
+
+
+/*!
+ * jQuery UI Autocomplete 1.8.22
+ *
+ * LIGHTNESS PAPER GINGER
+ *
+ * Copyright 2012
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+ 
+ /* Component containers */
+#ui-theme-full-paper-brown { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; border: 1px solid #d9d6c4; background: #eceadf url(images/ui-bg_fine-grain_10_eceadf_60x60.png) 50% 50% repeat; color: #1f1f1f; }
+#ui-theme-full-paper-brown. a { color: #1f1f1f; }
+
+/* Interaction states */
+#ui-theme-full-paper-brown .ui-state-hover { border: 1px solid #654b24; background: #654b24 url(images/ui-bg_fine-grain_65_654b24_60x60.png) 50% 50% repeat; font-weight: bold; color: #ffffff; }
+#ui-theme-full-paper-brown .ui-state-hover a, #ui-theme-full-paper-brown .ui-state-hover a:hover { color: #ffffff; text-decoration: none; }
+
+/* Corner radius */
+#ui-theme-full-paper-brown .ui-corner-all { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -khtml-border-top-left-radius: 5px; border-top-left-radius: 5px; }
+#ui-theme-full-paper-brown .ui-corner-all { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -khtml-border-top-right-radius: 5px; border-top-right-radius: 5px; }
+#ui-theme-full-paper-brown .ui-corner-all { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
+#ui-theme-full-paper-brown .ui-corner-all { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
Binary file sites/all/modules/search_autocomplete/css/images/help.png has changed
Binary file sites/all/modules/search_autocomplete/css/images/throbber.gif has changed
Binary file sites/all/modules/search_autocomplete/css/images/ui-bg_fine-grain_10_eceadf_60x60.png has changed
Binary file sites/all/modules/search_autocomplete/css/images/ui-bg_fine-grain_65_654b24_60x60.png has changed
Binary file sites/all/modules/search_autocomplete/css/images/ui-bg_glass_100_fdf5ce_1x400.png has changed
Binary file sites/all/modules/search_autocomplete/css/images/ui-bg_glass_55_1c1c1c_1x400.png has changed
Binary file sites/all/modules/search_autocomplete/css/images/ui-bg_glass_75_79c9ec_1x400.png has changed
Binary file sites/all/modules/search_autocomplete/css/images/ui-bg_highlight-hard_100_f9f9f9_1x100.png has changed
Binary file sites/all/modules/search_autocomplete/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png has changed
Binary file sites/all/modules/search_autocomplete/css/images/ui-bg_inset-hard_100_fcfdfd_1x100.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/css/nice black.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,86 @@
+/*
+ * SEARCH AUTOCOMPLETE (version 7.3-x)
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+ 
+ /**
+  * THEME NICE BLACK
+  */ 
+  
+
+
+/* AUTOCOMPLETE 
+----------------------------------*/
+.ui-autocomplete { position: absolute; cursor: default; }	
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-autocomplete-input {
+  background-image: url("images/throbber.gif");
+  background-position: 100% 4px;
+  background-repeat: no-repeat;
+}
+.ui-autocomplete-loading {
+  background-image: url("images/throbber.gif");
+  background-position: 100% -16px;
+  background-repeat: no-repeat;
+}
+.ui-menu {
+	list-style:none;
+	padding: 2px;
+	margin: 0;
+	display:block;
+	float: left;
+}
+.ui-menu .ui-menu {
+	margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+	margin:0;
+	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
+	width: 100%;
+}
+.ui-menu .ui-menu-item a {
+	text-decoration:none;
+	display:block;
+	padding:.2em .4em;
+	line-height:1.5;
+	zoom:1;
+}
+.ui-menu .ui-menu-item a {
+	font-weight: normal;
+	margin: -1px;
+}
+
+
+/*!
+ * jQuery UI Autocomplete 1.8.22
+ *
+ * LIGHTNESS THEME
+ *
+ * Copyright 2012
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Component containers */
+#ui-theme-nice-black { font-family: Verdana, Arial, sans-serif; font-size: 1.1em; border: 1px solid #cccccc; background: #f9f9f9 url(images/ui-bg_highlight-hard_100_f9f9f9_1x100.png) 50% top repeat-x; color: #222222; }
+#ui-theme-nice-black a { color: #222222; }
+
+/* Corner radius */
+#ui-theme-nice-black .ui-corner-all { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+#ui-theme-nice-black .ui-corner-all { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+#ui-theme-nice-black .ui-corner-all { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+#ui-theme-nice-black .ui-corner-all { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+
+/* Interaction States */
+#ui-theme-nice-black .ui-state-hover { border: 1px solid #000000; background: #1c1c1c url(images/ui-bg_glass_55_1c1c1c_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #ffffff; }
+#ui-theme-nice-black .ui-state-hover a, #ui-theme-nice-black .ui-state-hover a:hover { color: #ffffff; text-decoration: none; }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/css/nice blue.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,85 @@
+/*
+ * SEARCH AUTOCOMPLETE (version 7.3-x)
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+ 
+ /**
+  * THEME NICE BLUE
+  */ 
+  
+
+
+/* AUTOCOMPLETE 
+----------------------------------*/
+.ui-autocomplete { position: absolute; cursor: default; }	
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-autocomplete-input {
+  background-image: url("images/throbber.gif");
+  background-position: 100% 4px;
+  background-repeat: no-repeat;
+}
+.ui-autocomplete-loading {
+  background-image: url("images/throbber.gif");
+  background-position: 100% -16px;
+  background-repeat: no-repeat;
+}
+.ui-menu {
+	list-style:none;
+	padding: 2px;
+	margin: 0;
+	display:block;
+	float: left;
+}
+.ui-menu .ui-menu {
+	margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+	margin:0;
+	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
+	width: 100%;
+}
+.ui-menu .ui-menu-item a {
+	text-decoration:none;
+	display:block;
+	padding:.2em .4em;
+	line-height:1.5;
+	zoom:1;
+}
+.ui-menu .ui-menu-item a {
+	font-weight: normal;
+	margin: -1px;
+}
+
+ /*!
+ * jQuery UI CSS Framework 1.8.22
+ *
+ * START THEME
+ * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+ 
+ /* Component containers */
+#ui-theme-nice-blue { font-family: Verdana, Arial, sans-serif; font-size: 1.1em; border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
+#ui-theme-nice-blue a { color: #222222; }
+
+/* Corner radius */
+#ui-theme-nice-blue .ui-corner-all { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -khtml-border-top-left-radius: 5px; border-top-left-radius: 5px; }
+#ui-theme-nice-blue .ui-corner-all { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -khtml-border-top-right-radius: 5px; border-top-right-radius: 5px; }
+#ui-theme-nice-blue .ui-corner-all { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
+#ui-theme-nice-blue .ui-corner-all { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
+
+
+/* Interaction states */
+#ui-theme-nice-blue .ui-state-hover  { border: 1px solid #448dae; background: #79c9ec url(images/ui-bg_glass_75_79c9ec_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #026890; }
+#ui-theme-nice-blue .ui-state-hover a, #ui-theme-nice-blue .ui-state-hover a:hover { color: #026890; text-decoration: none; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/css/nice green.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,75 @@
+/*
+ * SEARCH AUTOCOMPLETE (version 7.3-x)
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+ 
+ /**
+  * THEME CUSTOM
+  */ 
+
+  
+/*******     DO NOT CHANGE ANYTHING IN HERE : have a look at the end of css file ***********/  
+/* AUTOCOMPLETE  : */
+.ui-autocomplete { position: absolute; cursor: default; }	
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-autocomplete-input {
+  background-image: url("images/throbber.gif");
+  background-position: 100% 4px;
+  background-repeat: no-repeat;
+}
+.ui-autocomplete-loading {
+  background-image: url("images/throbber.gif");
+  background-position: 100% -16px;
+  background-repeat: no-repeat;
+}
+.ui-menu {
+	list-style:none;
+	padding: 2px;
+	margin: 0;
+	display:block;
+	float: left;
+}
+.ui-menu .ui-menu {
+	margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+	margin:0;
+	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
+	width: 100%;
+}
+.ui-menu .ui-menu-item a {
+	text-decoration:none;
+	display:block;
+	padding:.2em .4em;
+	line-height:1.5;
+	zoom:1;
+}
+.ui-menu .ui-menu-item a {
+	font-weight: normal;
+	margin: -1px;
+}
+
+/************************************************************/
+/*******     MAKE YOUR CUSTOM CHANGES IN HERE     ***********/  
+  
+/* Component containers */
+#ui-theme-nice-green {  font-family: segoe ui, Arial, sans-serif; font-size: 1.1em; border: 1px solid #dfd9c3; background: #f5f3e5 url(images/ui-bg_highlight-hard_100_f5f3e5_1x100.png) 50% top repeat-x; color: #312e25; }
+#ui-theme-nice-green a { color: #312e25; }
+
+/* Corner radius */
+#ui-theme-nice-green .ui-corner-all { -moz-border-radius-topleft: 6px; -webkit-border-top-left-radius: 6px; -khtml-border-top-left-radius: 6px; border-top-left-radius: 6px; }
+#ui-theme-nice-green .ui-corner-all { -moz-border-radius-topright: 6px; -webkit-border-top-right-radius: 6px; -khtml-border-top-right-radius: 6px; border-top-right-radius: 6px; }
+#ui-theme-nice-green .ui-corner-all { -moz-border-radius-bottomleft: 6px; -webkit-border-bottom-left-radius: 6px; -khtml-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; }
+#ui-theme-nice-green .ui-corner-all { -moz-border-radius-bottomright: 6px; -webkit-border-bottom-right-radius: 6px; -khtml-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; }
+
+/* Interaction States */
+#ui-theme-nice-green .ui-state-hover { border: 1px solid #327e04; background: #67b021 url(images/ui-bg_highlight-soft_25_67b021_1x100.png) 50% 50% repeat-x; font-weight: normal; color: #ffffff; }
+#ui-theme-nice-green .ui-state-hover a, #ui-theme-nice-green .ui-state-hover a:hover { color: #ffffff; text-decoration: none; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/css/nice orange.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,84 @@
+/*
+ * SEARCH AUTOCOMPLETE (version 7.3-x)
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+ 
+ /**
+  * THEME NICE ORANGE
+  */ 
+
+  
+  
+/* AUTOCOMPLETE 
+----------------------------------*/
+.ui-autocomplete { position: absolute; cursor: default; }	
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+.ui-autocomplete-input {
+  background-image: url("images/throbber.gif");
+  background-position: 100% 4px;
+  background-repeat: no-repeat;
+}
+.ui-autocomplete-loading {
+  background-image: url("images/throbber.gif");
+  background-position: 100% -16px;
+  background-repeat: no-repeat;
+}
+.ui-menu {
+	list-style:none;
+	padding: 2px;
+	margin: 0;
+	display:block;
+	float: left;
+}
+.ui-menu .ui-menu {
+	margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+	margin:0;
+	padding: 0;
+	zoom: 1;
+	float: left;
+	clear: left;
+	width: 100%;
+}
+.ui-menu .ui-menu-item a {
+	text-decoration:none;
+	display:block;
+	padding:.2em .4em;
+	line-height:1.5;
+	zoom:1;
+}
+.ui-menu .ui-menu-item a {
+	font-weight: normal;
+	margin: -1px;
+}
+
+/*!
+ * jQuery UI Autocomplete 1.8.22
+ *
+ * LIGHTNESS THEME
+ *
+ * Copyright 2012
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+  
+/* Component containers */
+#ui-theme-nice-orange { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
+#ui-theme-nice-orange a { color: #333333; }
+
+/* Corner radius */
+#ui-theme-nice-orange .ui-corner-all { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+#ui-theme-nice-orange .ui-corner-all { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+#ui-theme-nice-orange .ui-corner-all { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+#ui-theme-nice-orange .ui-corner-all { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+
+/* Interaction States */
+#ui-theme-nice-orange .ui-state-hover { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #c77405; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/js/jquery.autocomplete.js	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,73 @@
+/**
+ * @file
+ * SEARCH AUTOCOMPLETE (version 7.3-x)
+ */
+ 
+/*
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+ 
+(function ($) {
+  Drupal.behaviors.search_autocomplete = {
+    attach: function(context) {
+      if (Drupal.settings.search_autocomplete) {
+        $.each(Drupal.settings.search_autocomplete, function(key, value) {
+          var NoResultsLabel = Drupal.settings.search_autocomplete[key].no_results;
+          $(Drupal.settings.search_autocomplete[key].selector).addClass('ui-autocomplete-processed').autocomplete({
+            minLength: Drupal.settings.search_autocomplete[key].minChars,
+            source: function(request, response) {
+              if (Drupal.settings.search_autocomplete[key].type == 0) {             // external URL
+                $.getJSON(Drupal.settings.search_autocomplete[key].datas, { q: request.term }, function (results) {
+                  // Only return the number of values set in the settings.
+                  if (!results.length && NoResultsLabel) {
+                      results = [NoResultsLabel];
+                  }   
+                  response(results.slice(0, Drupal.settings.search_autocomplete[key].max_sug));
+                });
+              } else if (Drupal.settings.search_autocomplete[key].type == 1) {      // internal URL
+                $.getJSON(Drupal.settings.search_autocomplete[key].datas + request.term, { }, function (results) {
+                  // Only return the number of values set in the settings.
+                  if (!results.length && NoResultsLabel) {
+                      results = [NoResultsLabel];
+                  }
+                  response(results.slice(0, Drupal.settings.search_autocomplete[key].max_sug));
+                });
+              } else if (Drupal.settings.search_autocomplete[key].type == 2) {      // static resources
+                var results = $.ui.autocomplete.filter( Drupal.settings.search_autocomplete[key].datas, request.term );
+                    if (!results.length && NoResultsLabel) {
+                    results = [NoResultsLabel];
+                }
+                // Only return the number of values set in the settings.
+                response(results.slice(0, Drupal.settings.search_autocomplete[key].max_sug));
+              }
+            },
+            open: function(event, ui) {
+              $(".ui-autocomplete li.ui-menu-item:odd").addClass("ui-menu-item-odd");
+              $(".ui-autocomplete li.ui-menu-item:even").addClass("ui-menu-item-even");
+            },
+            select: function(event, ui) { 
+              if (ui.item.label === NoResultsLabel) {
+                event.preventDefault();
+              } else
+              if (Drupal.settings.search_autocomplete[key].auto_redirect == 1 && ui.item.link) {
+                document.location.href = ui.item.link;
+              } else if (Drupal.settings.search_autocomplete[key].auto_submit == 1) {
+                  $(this).val(ui.item.label);
+                  $(this).closest("form").submit();
+              }
+            },
+            focus: function (event, ui) {
+              if (ui.item.label === NoResultsLabel) {
+                  event.preventDefault();
+              }
+            }
+          }).autocomplete("widget").attr("id", "ui-theme-" + Drupal.settings.search_autocomplete[key].theme);
+        });
+      }
+    }
+  };
+})(jQuery);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * @file
+ * Search Autocomplete
+ * Sets the admin part of the module: permissions, hooks, callbacks, etc...
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+
+
+/**
+ * Implements hook_permission().
+ * Valid permissions for this module
+ * @return
+ *   An array of valid permissions for the autocomplete module
+ */
+function search_autocomplete_permission() {
+  return array(
+    'administer Search Autocomplete' => array(
+      'title' => t('Administer Search Autocomplete'),
+      'description' => t('Access administration panel for autocompletion settings.'),
+    ),
+    'use Search Autocomplete' => array(
+      'title' => t('Use Search Autocomplete'),
+      'description' => t('Allow usage of autocompletion on forms.'),
+    ),
+  );
+} // function search_autocomplete_permissions()
+
+/**
+ * Implements hook_theme().
+ * Define the function to render our forms
+ */
+function search_autocomplete_theme($existing, $type, $theme, $path) {
+  return array(
+    'search_autocomplete_treelist_form' => array(                    // register theme function for draggable treelist search forms
+      'render element' => 'form',
+    )
+  );
+} // function search_autocomplete_theme($existing, $type, $theme, $path)
+
+/**
+ * Implements hook_menu().
+ * Create an administration page to access admin form
+ */
+function search_autocomplete_menu() {
+
+  // create the admin setting page: list of forms
+  $items['admin/config/search/search_autocomplete'] = array(
+    'title'             => 'Search Autocomplete settings',
+    'description'       => 'Choose settings and suggestion items for autocompletion in input forms.',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('search_autocomplete_treelist_form'),
+    'access arguments'  => array('administer Search Autocomplete'),
+    'file'              => 'search_autocomplete.form.treelist.inc',
+    'type'              => MENU_NORMAL_ITEM,
+    'weight'            => 0
+  );
+  // create a tab for settings
+  $items['admin/config/search/search_autocomplete/settings'] = array(
+    'title'             => 'Search Autocomplete settings',
+    'type'              => MENU_DEFAULT_LOCAL_TASK,
+    'weight'            => 1
+  );
+  // create an admin setting page: add a new form
+  $items['admin/config/search/search_autocomplete/add'] = array(
+    'title'             => 'Add a form',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('search_autocomplete_form_add'),
+    'access arguments'  => array('administer Search Autocomplete'),
+    'file'              => 'search_autocomplete.form.add.inc',
+    'type'              => MENU_LOCAL_TASK,
+    'weight'            => 2
+  );
+  // create an admin setting page: configure a form
+  $items['admin/config/search/search_autocomplete/%/configure'] = array(
+    'title'             => 'Search Autocomplete - Configuration',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('search_autocomplete_form_configure'),
+    'access arguments'  => array('administer Search Autocomplete'),
+    'file'              => 'search_autocomplete.form.configure.inc',
+  );
+  // create an admin setting page: delete a form
+  $items['admin/config/search/search_autocomplete/%/delete/%'] = array(
+    'title'             => 'Search Autocomplete - Delete',
+    'page callback'     => 'drupal_get_form',
+    'page arguments'    => array('search_autocomplete_form_delete', 4, 6),
+    'access arguments'  => array('administer Search Autocomplete'),
+    'file'              => 'search_autocomplete.form.delete.inc',
+  );
+  return $items;
+} // function search_autocomplete_menu()
+
+/**
+ * Implements hook_help().
+ */
+function search_autocomplete_help($path, $arg) {
+  $help = '';
+  switch ($path) {
+    case 'admin/modules#description':
+      $help = t('Allows the users with the right permission to use advanced autocompletion features on forms.');
+      break;
+    case 'admin/config/search/search_autocomplete':
+      $help  = '<div>' . t('Search Autocomplete helps you to enhance your search forms with autocompleted suggestions.') . '</div>';
+      $help .= '<div>' . t('Use this form to activate the forms you want to autocomplete.') . '</div>';
+      $help .= '<div>' . t('You may want to add new possible form to autocomplete. To do so, please use the tab <a href="search_autocomplete/add">Add a form</a>.') . '</div>';
+      break;
+    case 'admin/config/search/search_autocomplete/add':
+      $help  = '<div>' . t('This page allows you to add a new form to be autocompleted with the Search Autocomplete module.') . '</div>';
+      $help .= '<div>' . t('This is an advanced feature configuration. Use it only if you know what you are doing and after reading <a href="http://projects.axiomcafe.fr/search-autocomplete">documentation</a>. If you wish help, please ask for a new default form to be added in the next release of Search Autocomplete module.') . '</div>';
+      break;
+    case 'admin/config/search/search_autocomplete/%/configure':
+      $help  = '<div>' . t('You are currently configuring the options to autocomplete a form.') . '</div>';
+      $help .= '<div>' . t('Every children forms will be modified as well.') . '</div>';
+      break;
+  }
+  return $help;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.form.add.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * @file
+ * Search Autocomplete
+ * Add a new form to Search Autocomplete form list.
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+
+/**
+ * MENU CALLBACK:
+ * Define the page to add a form.
+ * @return  A rendered form
+ */
+function search_autocomplete_form_add() {
+
+  $form = array();
+  /* ------------------------------------------------------------------ */
+  $form['title'] = array(
+    '#title'          => t('Title'),
+    '#description'    => 'Please enter a title for this form',
+    '#type'           => 'textfield',
+    '#default_value'  => '',
+    '#maxlength'      => 255,
+    '#required'       => TRUE,
+  );
+  $descr = t('Enter a valid query selector for the form. This should be an id or a class surrounding the input box.') . '<br/>' . t('Do not include input. In case of a doubt, refer to the <a href="http://projects.axiomcafe.fr/search-autocomplete">documentation</a>');
+  $form['selector'] = array(
+    '#title'          => t('Selector'),
+    '#description'    => $descr,
+    '#type'           => 'textfield',
+    '#default_value'  => '',
+    '#maxlength'      => 255,
+    '#required'       => TRUE,
+  );
+  // submit buton
+  $form['submit'] = array(
+    '#type'           => 'submit',
+    '#value'          => t('Save'),
+  );
+  return $form;
+}
+
+// -------------------------------------------------------------------------------------
+/**
+ * Implements hook_submit().
+ * Save the new form in database
+ */
+function search_autocomplete_form_add_submit($form, &$form_state) {
+  $ok_query = TRUE;  // so far so good!
+
+  // Update the database with the new values
+  $what = '';
+  $sids = '';
+  $weights = '';
+
+  // Get the form values
+  $values = $form_state['values'];
+
+  // Check if aready existing records
+  $result = db_select('search_autocomplete_forms', 'f')
+    ->fields('f')
+    ->condition('title',    $values['title'])
+    ->condition('selector', $values['selector'])
+    ->execute()
+    ->fetchAll();
+
+  foreach ($result as $obj) {
+    drupal_set_message(t("The title or the selector already exists. Please choose another one."), 'error');
+    return;
+  }
+
+  // Insert the new form in database
+  $fid = db_insert('search_autocomplete_forms')
+          ->fields(array(
+            'title' => $values['title'],
+            'selector' => $values['selector']
+          ))
+          ->execute();
+
+  // redirect to configuration page
+  $form_state['redirect'] = 'admin/config/search/search_autocomplete/' . $fid . '/configure';
+
+  // Give a return to the user
+  $ok_query ? drupal_set_message(t('The form has been created successfully !') . '<br/>' . t('Please check its configuration.')) : drupal_set_message(t("An error has occured while creating the form. Please, double check your settings!"), 'error');
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.form.configure.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,301 @@
+<?php
+
+/**
+ * @file
+ * Search Autocomplete
+ * Helper functions to retrive suggestions from database
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+
+/**
+ * MENU CALLBACK:
+ * Define the form to configure the suggestions.
+ * @return  A rendered form
+ */
+function search_autocomplete_form_configure($form, &$form_state) {
+  $base = "admin/config/search/search_autocomplete";  // base URL for this module configurations
+
+  // get data from database
+  $fid = arg(4);
+
+  $result = db_select('search_autocomplete_forms', 'f')
+    ->fields('f')
+    ->condition('fid', $fid)
+    ->execute()
+    ->fetchAllAssoc('fid');
+
+  foreach ($result as $item) {
+    $form['fid'] = array(
+      '#type' => 'hidden',
+      '#value' => $fid,
+    );
+    // ------------------------------------------------------------------
+    // HOW - How to display Search Autocomplete suggestions
+    $form['search_autocomplete_how'] = array(
+      '#type'           => 'fieldset',
+      '#title'          => t('HOW - How to display Search Autocomplete suggestions?'),
+      '#collapsible'    => TRUE,
+      '#collapsed'      => TRUE
+    );
+    // Minimum characters to set autocompletion on
+    $form['search_autocomplete_how']['min_char'] = array(
+      '#type'           => 'textfield',
+      '#title'          => t('Minimum keyword size that uncouple autocomplete search'),
+      '#description'    => t('Please enter the minimum number of character a user must input before autocompletion starts.'),
+      '#default_value'  => $item->min_char,
+      '#maxlength'      => 2,
+      '#required'       => TRUE
+    );
+    // Number of suggestions to display
+    $form['search_autocomplete_how']['max_sug'] = array(
+      '#type'           => 'textfield',
+      '#title'          => t('Limit of the autocomplete search result'),
+      '#description'    => t('Please enter the maximim number of suggestion to display.'),
+      '#default_value'  => $item->max_sug,
+      '#maxlength'      => 2,
+      '#required'       => TRUE
+    );
+    // check if form should be autosubmitted
+    $form['search_autocomplete_how']['no_results'] = array(
+      '#type'           => 'textfield',
+      '#title'          => t('Behaviour when no suggestions are found'),
+      '#description'    => t('Enter a message to display when no results are found. Leave empty for no message.'),
+      '#default_value'  => $item->no_results,
+      '#maxlength'      => 50,
+      '#required'       => FALSE
+    );
+    // check if form should be autosubmitted
+    $form['search_autocomplete_how']['auto_submit'] = array(
+      '#type'           => 'checkbox',
+      '#title'          => t('Auto Submit'),
+      '#description'    => t('If enabled, the form will be submitted automatically as soon as your user choose a suggestion in the popup list.'),
+      '#default_value'  => $item->auto_submit
+    );
+    // check if form should be autoredirected
+    $form['search_autocomplete_how']['auto_redirect'] = array(
+      '#type'           => 'checkbox',
+      '#title'          => t('Auto Redirect'),
+      '#description'    => t('If enabled, the user will be directly routed to the suggestion he choosed instead of performing form validation process. Only works if "link" attribute is existing and if "Auto Submit" is enabled.'),
+      '#default_value'  => $item->auto_redirect
+    );
+
+    // ------------------------------------------------------------------
+    // WHAT - What to display in Search Autocomplete suggestions
+    $form['search_autocomplete_what'] = array(
+      '#type'           => 'fieldset',
+      '#title'          => t('WHAT - What to display in Search Autocomplete suggestions?'),
+      '#description'    => t('Choose which data should be added to autocompletion suggestions.'),
+      '#collapsible'    => TRUE,
+      '#collapsed'      => FALSE,
+      '#theme'          => 'search_autocomplete_form_configuration_fieldset'
+    );
+    $form['search_autocomplete_what']['suggestions'] = array(
+      '#type'           => 'item',
+      '#title'          => t('Suggestion source'),
+      '#description'    => t('Choose the source of suggestions to display in this form')
+    );
+    // use a callback
+    $form['search_autocomplete_what']['suggestions']['callback'] = array( );
+    $form['search_autocomplete_what']['callback']['callback_option'] = array(
+      '#type'           => 'radio',
+      '#title'          => t('Callback URL:'),
+      '#return_value'   => 1,
+      '#default_value'  => $item->data_source<2 ? 1 : 2,
+      '#prefix'         => '<div class="form-radios">',
+      '#parents'        => array('suggestions')
+    );
+    $descr =  t('Enter the url where to retrieve suggestions. It can be internal (absolute or relative) or external.') . '<br/>' .
+              t('To make an easy internal suggestion url, create a view using "Autocompletion JSON" view style ! (<a href="http://projects.axiomcafe.fr/search-autocomplete/advanced-configuration/add-suggestion-type-version-3x">see documentation</a>)') . '<br/>' .
+              t('Available views are:') . '<br/>' .
+              'autocomplete-nodes :  ' . t('suggest node titles'). '<br/>' .
+              'autocomplete-users :  ' . t('suggest user names'). '<br/>' .
+              'autocomplete-words :  ' . t('suggest the node titles for nodes containing the user input');
+    $form['search_autocomplete_what']['callback']['callback_textfield'] = array(
+      '#type'           => 'textfield',
+      '#description'    =>  $descr,
+      '#default_value'  => $item->data_callback,
+      '#size'           => 80,         // The default size is a bit large...
+      '#suffix'         => '',       // End of the "form-radios" style.
+      '#attributes'     => array('onClick' => '$("input[name=suggestions][value=1]").attr("checked", true);')
+    );
+    // use a static resource
+
+    $form['search_autocomplete_what']['suggestions']['staticresource'] = array( );
+    $form['search_autocomplete_what']['staticresource']['staticresource_option'] = array(
+      '#type'           => 'radio',
+      '#title'          => t('Static resource :'),
+      '#return_value'   => 2,
+      '#default_value'  => $item->data_source<2 ? 1 : 2,
+      '#parents'        => array('suggestions')
+    );
+    $form['search_autocomplete_what']['staticresource']['staticresource_textfield'] = array(
+      '#type'           => 'textarea',
+      '#description'    => t('Please enter one suggestion per line. You can use the syntax: "foo => http://bar" per line if you wish to add a jumping to URL for the suggestion. Please refer to <a href="http://projects.axiomcafe.fr/search-autocomplete">documentation</a>.'),
+      '#default_value'  => $item->data_static,
+      '#size'           => 20,         // The default size is a bit large...
+      '#suffix'         => '</div>',  // End of the "form-radios" style.
+      '#attributes'     => array('onClick' => '$("input[name=suggestions][value=2]").attr("checked", true);')
+    );
+
+    // template to use
+    $themes = array();
+    $files = file_scan_directory( drupal_get_path('module', 'search_autocomplete') . '/css', '/.*\.css\z/', array('recurse' => FALSE));
+    foreach ($files as $file) {
+      if ($file->name != 'jquery.autocomplete') $themes[$file->filename] = $file->name;
+    }
+    $form['search_autocomplete_what']['theme'] = array(
+      '#type'           => 'select',
+      '#title'          => t('Select a theme for your suggestions'),
+      '#options'        => $themes,
+      '#default_value'  => $item->theme,
+      '#description'    => t('Choose the theme to use for autocompletion dropdown popup. Read <a href="http://projects.axiomcafe.fr/search-autocomplete">documentation</a> to learn how to make your own.'),
+    );
+
+
+    // ------------------------------------------------------------------
+    // ADVANCED - Advanced options
+    $form['search_autocomplete_advanced'] = array(
+      '#type'             => 'fieldset',
+      '#title'            => t('ADVANCED - Advanced options'),
+      '#collapsible'      => TRUE,
+      '#collapsed'        => TRUE
+    );
+    $form['search_autocomplete_advanced']['selector'] = array(
+      '#type'             => 'textfield',
+      '#title'            => t('ID selector for this form'),
+      '#description'      => t('Please change only if you know what you do, read <a href="http://projects.axiomcafe.fr/search-autocomplete">documentation</a> first.'),
+      '#default_value'    => $item->selector,
+      '#maxlength'        => 255,
+      '#size'             => 35
+    );
+    // Add button validation
+    $form['submit'] = array(
+      '#type'             => 'submit',
+      '#value'            => t('Save configuration')
+    );
+  }
+  return $form;
+}
+// -------------------------------------------------------------------------------------
+/**
+ * Implements hook_validate().
+ * Save the changes in the database
+ */
+function search_autocomplete_form_configure_validate($form, &$form_state) {
+
+  $values = $form_state['values'];
+  if ($values['suggestions'] == 1) {
+    $new_url = preg_replace('/\?[^=]*=[^&]*/', '', $values['callback_textfield']);
+    if (!drupal_valid_path($new_url)) {
+      form_set_error('url', 'callback url is not valid: ' . $new_url);
+    }
+  }
+}
+
+// -------------------------------------------------------------------------------------
+/**
+ * Implements hook_submit().
+ * Save the changes in the database
+ */
+function search_autocomplete_form_configure_submit($form, &$form_state) {
+  global $base_url;
+
+  $ok_query = TRUE;  // so far so good!
+  // get form submission values
+  $values = $form_state['values'];
+  //Update the database with the new values
+  $what = '';
+  $sids = '';
+  $weights = '';
+
+  // analyse incoming callback
+  $callback = $values['callback_textfield'];
+  $data_type = 2;                                                               // if static resource => type = 2
+  if ($callback != '') {
+    if (url_is_external($callback)) {                                           // if path is absolute:
+      if (strcmp(substr($callback, 0, strlen($base_url)), $base_url) === 0) {       // if path is internal:
+        $callback = str_replace($base_url . "/", "", $callback);                    // get it relative
+        $data_type = 1;                                                             // type = 1
+      }
+      else {                                                                  // if external: type = 0
+        $data_type = 0;
+      }
+    }
+    else {                                                                    // if path is not absolute:
+      $data_type = 1;
+    }
+  }
+  if ($values['suggestions'] == 2) $data_type = 2;
+
+  // ###
+  // UPDATE THE FORM
+  // -> update form
+  db_update('search_autocomplete_forms')
+    ->fields(array(
+      'min_char'        => $values['min_char'],
+      'max_sug'         => $values['max_sug'],
+      'auto_submit'     => $values['auto_submit'],
+      'auto_redirect'   => $values['auto_redirect'],
+      'no_results'      => $values['no_results'],
+      'selector'        => $values['selector'],
+      'data_source'     => $data_type,
+      'data_callback'   => $callback,
+      'data_static'     => $values['staticresource_textfield'],
+      'theme'           => $values['theme']
+    ))
+    ->condition('fid', $values['fid'])
+    ->execute();
+  // ###
+  // UPDATE CHILD LIST BUT NOT THE ADVANCED OPTIONS
+  $fids = _search_autocomplete_get_all_children($values['fid']);
+  // update the settings for this form + every children form
+  foreach ($fids as $fid) {
+    // -> update form
+    db_update('search_autocomplete_forms')
+      ->fields(array(
+        'min_char'        => $values['min_char'],
+        'max_sug'         => $values['max_sug'],
+        'no_results'      => $values['no_results'],
+        'auto_submit'     => $values['auto_submit'],
+        'auto_redirect'   => $values['auto_redirect'],
+        'theme'           => $values['theme']
+      ))
+      ->condition('fid', $fid)
+      ->execute();
+  }
+  // ###
+  drupal_clear_css_cache();
+  $form_state['redirect'] = 'admin/config/search/search_autocomplete';
+  $ok_query ? drupal_set_message(t("Configuration success !")) : drupal_set_message(t("An error has occured while saving the settings. Please, double check your settings!"), 'error');
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+////                             HELPER FUNCTIONS                                    ////
+
+// -------------------------------------------------------------------------------------
+/**
+ * Helper function: get the array of fids every of his children of the caller but not
+ * caller fid.
+ */
+function _search_autocomplete_get_all_children($fid, &$items = array(), $depth = 0) {
+  if ($depth)
+    $items[] = $fid;
+
+  //$result = db_query('SELECT * FROM {search_autocomplete_forms} WHERE parent_fid=:parent_fid', array(':parent_fid' => $fid));
+  $result = db_select('search_autocomplete_forms', 'f')
+      ->fields('f')
+      ->condition('parent_fid', $fid)
+      ->execute()
+      ->fetchAllAssoc('fid');
+
+  foreach ($result as $item) {
+    ++$depth;
+    _search_autocomplete_get_all_children($item->fid, $items, $depth);
+  }
+  return $items;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.form.delete.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Search Autocomplete
+ * Delete a form from Search Autocomplete form list.
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+
+/**
+ * Return the filter delete form.
+ */
+function search_autocomplete_form_delete($form, &$form_state, $parent_fid, $fid) {
+
+  if (!$fid) {
+    drupal_set_message(
+      t('The form has not been found, or the menu callback received a wrong parameter.'),
+      'error'
+    );
+    watchdog(
+      'search_autocomplete',
+      'The form has not been found, or the menu callback received a wrong parameter.',
+      NULL,
+      WATCHDOG_ERROR
+    );
+
+    return $form;
+  }
+
+  $form['parent_fid'] = array(
+    '#type' => 'hidden',
+    '#value' => $parent_fid,
+  );
+  $form['fid'] = array(
+    '#type' => 'hidden',
+    '#value' => $fid,
+  );
+
+  return confirm_form(
+    $form,
+    t('Are you sure you want to delete this form?'),
+    'admin/config/search/search_autocomplete',
+    NULL,
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Submission callback for the filter delete form.
+ */
+function search_autocomplete_form_delete_submit($form, &$form_state) {
+
+  $ok = TRUE;
+  $values = $form_state['values'];
+  $fid = $values['fid'];
+  $parent_fid = $values['parent_fid'];
+
+  db_update('search_autocomplete_forms')
+            ->fields(array(
+              'parent_fid'  => $parent_fid,
+            ))
+            ->condition('parent_fid', $fid)
+            ->execute();
+  db_query('DELETE FROM {search_autocomplete_forms} WHERE fid = :fid', array(':fid' => $fid));
+
+  // Give a return to the user
+  drupal_set_message(t("The form has been successfully deleted !"));
+
+  $form_state['redirect'] = 'admin/config/search/search_autocomplete';
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.form.treelist.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,250 @@
+<?php
+
+/**
+ * @file
+ * Search Autocomplete
+ * Display the list of form to autocomplete and themis it as a draggable table.
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+
+//-------------------------------------------------------------------------------------
+/**
+ * Menu Callback: create the form to list the searchforms
+ * @return     the form
+ */
+function search_autocomplete_treelist_form($form, &$form_state) {
+  $base = "admin/config/search/search_autocomplete";  // base URL for this module configurations
+
+  $data = _search_autocomplete_get_items();  // get all forms ordered as a tree;
+  $form['my_items'] = array();
+  $form['my_items']['#tree'] = TRUE;
+
+  // for each items to render in the form
+  foreach ($data as $values) {
+    $fid        = $values->fid;
+    $title      = $values->title;
+    $weight     = $values->weight;
+    $enabled    = $values->enabled;
+    $parent_fid = $values->parent_fid;
+    $translite  = $values->translite;
+
+    $form['my_items'][$fid] = array(       // element for this item
+      'title' => array(                      // -> human readeable title
+        '#type' => 'item',
+        '#title' => check_plain($title),
+      ),
+      'enabled' => array(                    // -> defines if the autocompletion is enabled for this item
+        '#type' => 'checkbox',
+        '#default_value' => $enabled,
+      ),
+      'operations' => array(
+        'configure' => array(
+          '#type' => 'item',
+          '#title' => filter_xss(l(t('configure'), "$base/$fid/configure")),
+        ),
+        'delete' => array(
+          '#type' => 'item',
+          '#title' => filter_xss(l(t('delete'), "$base/$parent_fid/delete/$fid")),
+        ),
+      ),
+      'weight' => array(                     // -> weight of the item in hierarchy
+        '#type' => 'weight',
+        '#delta' => count($data),
+        '#default_value' => $weight,
+      ),
+      'fid' => array(                        // -> the individual id if the item
+        '#type' => 'hidden',
+        '#value' => $fid,
+      ),
+      'parent_fid' => array(                 // -> id of the parent item in hierarchy
+        '#type' => 'textfield',
+        '#default_value' => $parent_fid
+      ),
+      '#depth' => $values->depth,          // -> depth of the item
+    );
+  }
+
+  // translite option
+  $title = t('Translite special characters.') . ' (' . t('Requires <a href="https://drupal.org/project/transliteration">Transliteration</a> module.') . ' :  ';
+  $title .= module_exists('transliteration') ? '<b>' . t('Installed') . '</b>' : '<b>' . t('Not installed') . '</b>';
+  $title .= ')';
+  $form['translite'] = array(
+    '#type'           => 'checkbox',
+    '#title'          => $title,
+    '#description'    => t('If enabled, the user will be suggested with all special characters suggestions when using standard characters. In other word, when entering "foo", suggestions may contain also "f&oacute;&ocirc;bar", "fo&otilde;bar", ...'),
+    '#disabled'       => module_exists('transliteration') ? FALSE : TRUE,
+    '#default_value'  => $translite
+  );
+
+  // submit buton
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+  );
+  return $form;
+} // function search_autocomplete_treelist_form()
+
+//-------------------------------------------------------------------------------------
+/**
+ * Implements hook_submit().
+ * Save the changes in the database
+ */
+function search_autocomplete_treelist_form_submit($form, &$form_state) {
+  //Update the database with the new values
+  foreach ($form_state['values']['my_items'] as $item) {
+    db_update('search_autocomplete_forms')
+      ->fields(array(
+        'weight' => $item['weight'],
+        'parent_fid' => $item['parent_fid'],
+        'enabled' => $item['enabled'],
+        'translite' => $form_state['values']['translite']
+      ))
+      ->condition('fid', $item['fid'])
+      ->execute();
+  }
+  drupal_set_message(t('Configuration success'));
+} //function search_autocomplete_treelist_form_submit()
+
+/**
+ * This function transforms the choices into a string.
+ */
+function array2str($myarray, &$output = '', $parentkey = "---") {
+  foreach ($myarray as $key => $value) {
+    if (is_array($value)) {
+      $parentkey .= "---";
+      array2str($value, $output, $parentkey);
+      $parentkey = substr($parentkey, 0, -3);
+    }
+    else {
+      $output .= $parentkey . "[" . $key . "] => " . $value . "<br/>";
+    }
+  }
+  return $output;
+}
+//-------------------------------------------------------------------------------------
+/**
+ * CALLBACK:
+ * Theme function for this treelist form
+ */
+function theme_search_autocomplete_treelist_form($variables) {
+  $form = $variables['form'];
+
+  drupal_add_tabledrag('my-draggable-table', 'order', 'sibling', 'weight-group');
+  drupal_add_tabledrag('my-draggable-table', 'match', 'parent', 'parent-group', 'parent-group', 'id-group');
+
+  $rows = array();
+  // for each elements to anchor in the form
+  foreach (element_children($form['my_items']) as $key) {
+
+    $element                                        = &$form['my_items'][$key];
+    $element['weight']['#attributes']['class']      = array('weight-group');
+    $element['fid']['#attributes']['class']         = array('id-group');
+    $element['parent_fid']['#attributes']['class']  = array('parent-group');
+
+    $rows[] = array(
+      'data' => array(
+        theme('indentation', array('size' => $element['#depth'])) . drupal_render($element['title']),
+        drupal_render($element['enabled']),
+        drupal_render($element['weight']) .
+        drupal_render($element['fid']) .
+        drupal_render($element['parent_fid']),
+        drupal_render($element['operations']['configure']),
+        drupal_render($element['operations']['delete']),
+      ),
+      'class' => array('draggable'),
+    );
+  }
+  // create table headers
+  $header = array(t('Form nam'), t('Enabled'), t('Weight'), array(
+    'data' => t('Operations'),
+    'colspan' => 2,
+  ));
+  // Themize the table and render the form
+  $output  = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'my-draggable-table')));
+  $output .= drupal_render_children($form);
+  $output .= drupal_render($form['submit']);
+
+  return $output;
+} //function theme_search_autocomplete_treelist_form()
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+////                             HELPER FUNCTIONS                                    ////
+
+//-------------------------------------------------------------------------------------
+/**
+ * Helper function: get the forms from database and render them hierarchically
+ * return the items sorted
+ */
+function _search_autocomplete_get_items() {
+  $items = array();
+  // get data in database and fetch it
+  $result = db_select('search_autocomplete_forms', 'f')
+    ->fields('f')
+    ->orderBy('weight')  //ORDER BY created
+    ->execute()
+    ->fetchAllAssoc('fid');
+
+  // order the list
+  return _search_autocomplete_get_ordered_list(0, $result);
+} //function _search_autocomplete_get_items()
+
+//-------------------------------------------------------------------------------------
+/**
+ * HELPER:
+ * Returns a tree list of all items in the $items array that are children
+ * of the supplied parent, ordered appropriately
+ * @return the ordered tree
+ */
+function _search_autocomplete_get_ordered_list($parent, $items, $depth = 0) {
+
+  $remnant = array(); $children = array();
+  // Insert direct children in $children
+  // and remaining in $remnant
+  foreach ($items as $item) {
+    if ($item->parent_fid == $parent) {
+      $item->depth = $depth;
+      $children[] = $item;
+    }
+    else
+      $remnant[] = $item;
+  }
+
+  // Sort the direct children by weight
+  usort($children, '_search_autocomplete_sort_by_weight');
+
+  $ancestors = array();
+
+  foreach ($children as $child) {
+    // Order the child ancestors iteratively
+    $child_children = _search_autocomplete_get_ordered_list($child->fid, $remnant, $depth + 1);
+    // Push the results into the main array below the child
+    $ancestors[] = $child;
+    // Merge it if needed
+    if (count($child_children)) {
+      $ancestors = array_merge($ancestors, $child_children);
+    }
+  }
+  return $ancestors;
+}
+
+//-------------------------------------------------------------------------------------
+/**
+ * HELPER:
+ * Usort function for sorting arrays by weight
+ * @return   1: if ($a < $b),
+ *      0 if equal,
+ *      -1 otherwise
+ */
+function _search_autocomplete_sort_by_weight($a, $b) {
+  if ($a->weight == $b->weight)
+    return 0;
+  return ($a->weight < $b->weight) ? -1 : 1;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = Search Autocomplete
+description = Provides aucompletion for Drupal search forms.
+core = 7.x
+version = 3.2
+package = Search
+files[] = views/plugins/views_plugin_style_autocomplete.inc
+dependencies[] = search
+configure = admin/config/search/search_autocomplete
+; Information added by drupal.org packaging script on 2013-06-09
+version = "7.x-3.2"
+core = "7.x"
+project = "search_autocomplete"
+datestamp = "1370795153"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,338 @@
+<?php
+
+/**
+ * @file
+ * This file is used to install/update/delete the module tables in database
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+
+// -----------------------------------------------------------------------------------------------
+/**
+ * Implements hook_schema().
+ * Set the schema of database
+ * @return the schema for of the table to create
+ */
+function search_autocomplete_schema() {
+  // schema for search_autocomplete database
+  $schema['search_autocomplete_forms'] = array(
+    'description' => t('Store the forms to autocomplete using Search Autocomplete.'),
+    'fields' => array(
+      'fid'       => array(
+        'type'        => 'serial',
+        'unsigned'    => TRUE,
+        'not null'    => TRUE,
+      ),
+      'title'     => array(
+        'description' => 'Human readable name for the form',
+        'type'        => 'varchar',
+        'length'      => 255,
+        'not null'    => TRUE,
+        'default'     => '',
+      ),
+      'selector'  => array(
+        'description' => 'Reference id selector of the the form in drupal',
+        'type'        => 'varchar',
+        'length'      => 255,
+        'not null'    => TRUE,
+        'default'     => '',
+      ),
+      'weight'    => array(
+        'description' => 'Form weight in table',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 0,
+      ),
+      'enabled'   => array(
+        'description' => 'Define if autocomplete is activated or not',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 0,
+      ),
+      'parent_fid' => array(
+        'description' => 'Define if the from follows the configuration of another one',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 0,
+      ),
+      'min_char'  => array(
+        'description' => 'Minimum of character before triggering suggestions',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 3,
+      ),
+      'max_sug'   => array(
+        'description' => 'Maximum number of suggestions',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 10,
+      ),
+      'no_results'   => array(
+        'description' => 'Maximum number of suggestions',
+        'type'        => 'varchar',
+        'length'      => 50,
+        'not null'    => FALSE,
+        'default'     => '-- no results --',
+      ),
+      'auto_submit'   => array(
+        'description' => 'Define if form should be autosubmitted when suggestion is choosen',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 1,
+      ),
+      'auto_redirect'   => array(
+        'description' => 'Define if user should be redirected to suggestion directly',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 1,
+      ),
+      'translite'    => array(
+        'description' => 'Define if suggestion searches should be translited',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 1,
+      ),
+      'data_source'  => array(
+        'description' => 'Should data come from callback or from static resource',
+        'type'        => 'int',
+        'not null'    => TRUE,
+        'default'     => 1,
+      ),
+      'data_callback'  => array(
+        'description' => 'Callback URL for data source',
+        'type'        => 'varchar',
+        'length'      => 255,
+        'default'     => '',
+      ),
+      'data_static'  => array(
+        'description' => 'Static text as a data',
+        'type'        => 'text',
+        'size'         => 'big',
+      ),
+      'theme'  => array(
+        'description' => 'Theme to use with this form',
+        'type'        => 'varchar',
+        'length'      => 255,
+        'not null'    => TRUE,
+        'default'     => 'lightness',
+      ),
+    ),
+    'primary key' => array('fid'),
+  );
+
+  return $schema;
+} // function search_autocomplete_schema
+
+//-----------------------------------------------------------------------------------------------
+/**
+ * Implements hook_install().
+ */
+function search_autocomplete_install() {
+  global $base_url;
+  
+  $limit            = variable_get('search_autocomplete_limit', 10);
+  $trigger          = variable_get('search_autocomplete_trigger', 3);
+  $enabled          = 1;
+
+  // ----------------
+  // declare insertion statement
+  $insert = db_insert('search_autocomplete_forms')
+                ->fields(array('title', 'selector', 'weight', 'enabled', 'min_char', 'max_sug', 'auto_submit', 'auto_redirect', 'data_source', 'data_callback', 'data_static', 'theme'));     
+  $insert->values(array(
+    'title' => st('Search page - Node Tab') . "  (search/node/%)",
+    'selector'      => '#search-form[action="/search/node"] #edit-keys',
+    'weight'        => 0,
+    'enabled'       => $enabled,
+    'min_char'      => $trigger,
+    'max_sug'       => $limit,
+    'translite'     => 1,
+    'auto_submit'   => 1,
+    'auto_redirect' => 1,
+    'data_source'   => 1,
+    'data_callback' => 'autocomplete-nodes?filter=',
+    'data_static'   => '',
+    'theme'         => 'classic.css'
+  ));
+  $insert->values(array(
+    'title'     => st('Search page - User Tab') . "  (search/user/%)",
+    'selector'  => '#search-form[action="/search/user"] #edit-keys',
+    'weight'    => 1,
+    'enabled'   => $enabled,
+    'min_char'  => $trigger,
+    'max_sug'   => $limit,
+    'translite'     => 1,
+    'auto_submit'   => 1,
+    'auto_redirect' => 1,
+    'data_source'   => 1,
+    'data_callback' => 'autocomplete-users?filter=',
+    'data_static'   => '',
+    'theme'         => 'classic.css'
+  ));
+  $insert->values(array(
+    'title'     => st('Search Block'),
+    'selector'  => "#edit-search-block-form--2",
+    'weight'    => 0,
+    'enabled'   => $enabled,
+    'min_char'  => $trigger,
+    'max_sug'   => $limit,
+    'translite'     => 1,
+    'auto_submit'   => 1,
+    'auto_redirect' => 1,
+    'data_source'   => 1,
+    'data_callback' => 'autocomplete-nodes?filter=',
+    'data_static'   => '',
+    'theme'         => 'classic.css'
+  ));
+  $insert->execute();
+
+  drupal_set_message(st('Search Autocomplete is now correctly installed!') . "<br/>" . st('If you see some functionalities missing or broken, please post an issue here:') . '  <a href="http://drupal.org/project/issues/search_autocomplete">http://drupal.org/project/issues/search_autocomplete</a>');
+
+
+} // function search_autocomplete_install
+
+/**
+ * Permission fix for update process from 6.x
+ */
+function search_autocomplete_update_7000() {
+  $t = get_t();
+  // In Drupal 6 the permissions were wrapped in t(), but in Drupal 7 they are
+  // not. So we want to make sure the database is storing the untranslated
+  // permission or we could run into issues on upgraded Drupal 7 sites.
+  db_update('role_permission')
+    ->fields(array(
+      'permission' => 'administer Search Autocomplete',
+    ))
+    ->condition('permission', $t('administer Search Autocomplete'))
+    ->execute();
+
+  db_update('role_permission')
+    ->fields(array(
+      'permission' => 'use Search Autocomplete',
+    ))
+    ->condition('permission', $t('use Search Autocomplete'))
+    ->execute();
+}
+
+/**
+  * Get ready for Search Autocomplete 7.3-x
+  */
+function search_autocomplete_update_7300(&$sandbox) {
+  $ret = array();
+
+  $num_deleted =  db_drop_table('search_autocomplete_forms');
+  $num_deleted &= db_drop_table('search_autocomplete_suggestions');
+  
+  db_create_table('search_autocomplete_forms', drupal_get_schema('search_autocomplete_forms', TRUE));
+  search_autocomplete_install();
+  
+  return t('The update process is successfull.');
+
+  // In case of an error, simply throw an exception with an error message.
+  throw new DrupalUpdateException('Something went wrong. Please uninstall and install the module again.');
+  return $ret;
+}
+/**
+  * Get ready for Search Autocomplete 7.x-3.0-rc2
+  */
+function search_autocomplete_update_7301(&$sandbox) {
+  global $base_url;
+  $ret = array();
+  
+  $result = db_select('search_autocomplete_forms', 'f')
+    ->fields('f', array('fid', 'data_callback'))
+    ->execute()
+    ->fetchAll();
+
+  foreach ($result as $item) {
+    db_update('search_autocomplete_forms')
+      ->fields(array(
+        'data_callback'   => str_replace($base_url . "/", "", $item->data_callback)
+      ))
+      ->condition('fid', $item->fid)
+      ->execute();
+  }
+  drupal_clear_js_cache();
+
+  return t('Update has:<br/>- change internal callback URL from absolute to relative.<br/>- clear JS cache.<br/> Done with success.');
+
+  // In case of an error, simply throw an exception with an error message.
+  throw new DrupalUpdateException('Something went wrong. Please uninstall and install the module again.');
+  return $ret;
+}
+
+/**
+  * Get ready for Search Autocomplete 7.x-3.0-rc3
+  */
+function search_autocomplete_update_7302(&$sandbox) {
+  $ret = array();
+  cache_clear_all();
+  return $ret;
+}
+/**
+  * Get ready for Search Autocomplete 7.x-3.1
+  */
+function search_autocomplete_update_7310(&$sandbox) {
+  $ret = array();
+
+  $translite_field = array(
+    'description' => 'Define if suggestion searches should be translited',
+    'type'        => 'int',
+    'not null'    => TRUE,
+    'default'     => 1,
+  ); 
+  db_add_field( 'search_autocomplete_forms', 'translite', $translite_field);
+  $no_results_field = array(
+    'description' => 'Maximum number of suggestions',
+    'type'        => 'varchar',
+    'length'      => 50,
+    'not null'    => FALSE,
+    'default'     => '-- no results --',
+  ); 
+  db_add_field( 'search_autocomplete_forms', 'no_results', $no_results_field);
+  
+  drupal_clear_js_cache();
+  return t('Update has:<br/>- add a column "translite" in the search autocomplete database.<br/>- add a column "no_results" in the search autocomplete database.<br/> Done with success.');
+
+  // In case of an error, simply throw an exception with an error message.
+  throw new DrupalUpdateException('Something went wrong. Please uninstall and install the module again.');
+  return $ret;
+}
+// -----------------------------------------------------------------------------------------------
+
+/**
+  * Get ready for Search Autocomplete 7.x-3.2
+  */
+function search_autocomplete_update_7320(&$sandbox) {
+  // Create the definition for the field
+  $new_field = array(
+    'description' => 'Static text as a data',
+    'type'        => 'text',
+    'size'        => 'big',
+  );
+  db_change_field('search_autocomplete_forms', 'data_static', 'data_static', $new_field);
+  
+  // Select data_callbacks of 
+  $result = db_select('search_autocomplete_forms', 'f')
+    ->fields('f', array('fid', 'data_callback'))
+    ->execute()
+    ->fetchAll();
+  foreach ($result as $item) {
+    db_update('search_autocomplete_forms')
+      ->fields(array(
+        'data_callback'   => $item->data_callback . '?filter=')
+      )
+      ->condition('data_callback', array('autocomplete-nodes', 'autocomplete-users'), 'IN')
+      ->execute();
+  }
+
+  return (t('Update has:') . '<br/>' . t('- changed column type "data_static" from TEXT to LONGTEXT.')
+                           . '<br/>' . t('- Add filter to VIEWS callback for performance improvement.'));
+  
+  // In case of an error, simply throw an exception with an error message.
+  throw new DrupalUpdateException('Something went wrong. Please uninstall and install the module again.');
+  return $ret;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * @file
+ * Search Autocomplete
+ * Enables autocomplete functionality on search fields.
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+
+include_once('search_autocomplete.admin.inc');
+include_once('search_autocomplete.view_autocomplete.inc');
+
+
+/**
+ * Implements hook_init().
+ * Add autocomplete.js on everypage.
+ */
+function search_autocomplete_init() {
+
+  // checkout if user have authorization to access the autocompleted form
+  if (user_access('use Search Autocomplete')) {
+    // init:
+    $settings = array();
+  
+    // checkout if the db exists (it should)
+    if (db_table_exists('search_autocomplete_forms')) {
+      // get every form to autocomplete
+      $result = db_query('SELECT * FROM {search_autocomplete_forms} WHERE enabled=1');
+      // build the setting array to transfert to JS
+      foreach ($result as $match) {
+        $form_id = 'form' . $match->fid;
+        $input_data  = explode("\n", $match->data_static);
+        $data_static = array();
+        for ($i=0; $i < count($input_data); $i++) {
+          $cut = strripos($input_data[$i], '=>');
+          $object = array();
+          if ($cut > 0) {
+            $object['label']  = trim(substr($input_data[$i], 0, $cut));
+            $object['value']  = trim(substr($input_data[$i], 0, $cut));
+            $object['link']   = trim(substr($input_data[$i], $cut+2, strlen($input_data[$i])));
+          } 
+          else {
+            $object['label']  = trim($input_data[$i]);
+            $object['value']  = trim($input_data[$i]);
+          }
+          $data_static[] = $object;
+        }
+        
+        $theme_id      = preg_replace("/\\.[^.\\s]{3,4}$/", "", $match->theme);
+        $data_source  = $match->data_callback;
+        if ($match->data_source == 1 && !url_is_external($match->data_callback)) {
+          $data_source = urldecode(url($match->data_callback, array('absolute' => TRUE)));
+        }
+
+        drupal_add_js(array('search_autocomplete' => array(
+          $form_id          => array(
+            'selector'      => $match->selector,
+            'minChars'      => $match->min_char,
+            'max_sug'       => $match->max_sug,
+            'no_results'    => $match->no_results,
+            'type'          => $match->data_source,
+            'datas'         => $match->data_source > 1 ? $data_static : $data_source,
+            'fid'           => $match->fid,
+            'theme'         => str_replace(' ', '-', strtolower($theme_id)),    // get the css filename with '-' instead of ' ', lower case and no '.css'
+            'auto_submit'   => $match->auto_submit,
+            'auto_redirect' => $match->auto_redirect
+          )
+        )), 'setting');
+        drupal_add_css(drupal_get_path('module', 'search_autocomplete') . '/css/' . $match->theme);         
+      }
+      // If there is some results: need to include the css and js....
+      if ($result) {
+        drupal_add_library('system', 'ui');
+        drupal_add_library('system', 'ui.widget');
+        drupal_add_library('system', 'ui.position');
+        drupal_add_library('system', 'ui.autocomplete');
+        drupal_add_js(drupal_get_path('module', 'search_autocomplete') . '/js/jquery.autocomplete.js');
+      }
+    }
+  }
+  
+  if (isset($_GET['sort_order'])) {
+    $_GET['sort_order'] = drupal_strtoupper($_GET['sort_order']);
+  }
+  
+} // search_autocomplete_init()
+
+
+/**
+ * HELP FUNCTION: replace placeholders in the input string
+ * @param $input  the string to be replaced
+ * @param $args   the array of placeholders and values
+ */
+function search_autocomplete_replaceArguments(&$input, &$args) {
+  $modified = FALSE;
+  foreach ($args as $key => $data) {
+    $input = preg_replace('#' . $key . '#', $data, $input);
+    $modified = TRUE;
+  }
+  return $modified;
+}
+
+/**
+ * Helper function: get from database if suggestions should be translited
+ */
+function search_autocomplete_get_translite() {
+// get data in database and fetch it
+  $result = db_select('search_autocomplete_forms', 'f')
+    ->fields('f', array('translite'))
+    ->range(0, 1)
+    ->execute()
+    ->fetchField();
+
+  return $result;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/search_autocomplete.view_autocomplete.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,599 @@
+<?php
+
+/**
+ * @file
+ * Search Autocomplete
+ * Enables autocomplete functionality on search fields.
+ *
+ * @authors
+ * Miroslav Talenberg (Dominique CLAUSE) <http://www.axiomcafe.fr/contact>
+ *
+ * Sponsored by:
+ * www.axiomcafe.fr
+ */
+
+/**
+ * Implements hook_views_api().
+ */
+function search_autocomplete_views_api() {
+  return array(
+    'api' => '3.0',
+    'path' => drupal_get_path('module', 'search_autocomplete') . '/views',
+  );
+}
+
+/**
+ * Implements hook_views_pre_render().
+ */
+function search_autocomplete_views_pre_render(&$view) {
+  if (isset($view->plugin_name) && $view->plugin_name == 'search_autocomplete') {
+    // Support for Video field.
+    if (!empty($view->result)) {
+      // Process each View result.
+      foreach ($view->result as $row => $result) {
+        // Only process the entity fields defined by the View.
+        foreach ($view->field as $field_name => $field) {
+          if ($field instanceof views_handler_field_field) {
+            if ($field->field_info['type'] == 'video') {
+
+              // Get the Video URL.
+              $video  = $field->get_value($view->result[$row]);
+              $url    = file_create_url($video[0]['uri']);
+              $render_array = array(
+                '#type'   => 'markup',
+                '#markup' => filter_xss($url),
+              );
+              // Substitute embed code with URL. @todo Add support for escaped embed codes.
+              $view->result[$row]->{'field_' . $field_name}[0]['rendered'] = $render_array;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * We almost duplicate the content_handler_field_multiple::render function
+ * to get the multiple rendered field values in an array
+ * @param $field
+ * @param $values
+ * @return unknown_type
+ */
+function _search_autocomplete_render_multiple_field($field, $values) {
+  $options = $field->options;
+  // If this is not a grouped field, use content_handler_field::render().
+  if (!$field->defer_query) {
+    return $field->render($values);
+  }
+  // We're down to a single node here, so we can retrieve the actual field
+  // definition for the node type being considered.
+  $content_field = content_fields($field->content_field['field_name'], $values->{$field->aliases['type']});
+  $vid = $values->{$field->field_alias};
+  if (isset($field->field_values[$vid])) {
+    // Gather items, respecting the 'Display n values starting from m' settings.
+    $count_skipped = 0;
+    $items = array();
+    foreach ($field->field_values[$vid] as $item) {
+      if (empty($options['multiple']['multiple_from']) || ($count_skipped >= $options['multiple']['multiple_from'])) {
+        if (empty($options['multiple']['multiple_number']) || (count($items) < $options['multiple']['multiple_number'])) {
+          // Grab the nid - needed for render_link().
+          $nid = $item['_nid'];
+          unset($item['_nid']);
+          $items[] = $item;
+        }
+        else {
+          break;
+        }
+      }
+      ++$count_skipped;
+    }
+
+    // Build a pseudo-node from the retrieved values.
+    $node = drupal_clone($values);
+    // content_format and formatters will need a 'type'.
+    $node->type = $values->{$field->aliases['type']};
+    $node->nid = $values->{$field->aliases['nid']};
+    $node->vid = $values->{$field->aliases['vid']};
+
+    // Some formatters need to behave differently depending on the build_mode
+    // (for instance: preview), so we provide one.
+    $node->build_mode = NODE_BUILD_NORMAL;
+
+    // Render items.
+    $formatter_name = $options['format'];
+    if ($items && ($formatter = _content_get_formatter($formatter_name, $content_field['type']))) {
+      $rendered = array();
+      if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) {
+        // Single-value formatter.
+        $n = 0;
+        foreach ($items as $item) {
+          $output = content_format($content_field, $item, $formatter_name, $node);
+          if (!empty($output)) {
+            $rendered[++$n] = $field->render_link($output, (object) array('nid' => $nid));
+          }
+        }
+      }
+      else {
+        // Multiple values formatter.
+        $output = content_format($content_field, $items, $formatter_name, $values);
+        if (!empty($output)) {
+          $rendered[++$n] = $field->render_link($output, (object) array('nid' => $nid));
+        }
+      }
+      if (count($rendered) > 1) {
+        // TODO: could we use generic field display ?
+        //return theme('content_view_multiple_field', $rendered, $content_field, $values);
+        return $rendered;
+      }
+      elseif ($rendered) {
+        return $rendered[1];
+      }
+    }
+  }
+
+  return '';
+}
+
+/**
+ * Takes each field from a row object and renders the field as determined by the field's theme
+ *
+ * @param $view
+ *   View the row belongs to
+ * @param $row
+ *   Row object
+ * @return array
+ *   Object containing all the raw and rendered fields
+ */
+function _search_autocomplete_render_fields($view, $row) {
+  $field_ids = array_keys($view->field);
+  $rendered_fields = array();
+  foreach ($field_ids as $id) {
+    $field = $view->field[$id];
+    $field_is_multiple = FALSE;
+    $field_raw = array();
+    if ((isset($field->options['multiple']['group']))&& isset($field->field_values)) {
+      $field_output = _search_autocomplete_render_multiple_field($field, $row);
+      $n = 0;
+      if (is_array($field_output)) {
+        foreach ($field->field_values[$row->{$field->field_alias}] as $item) {
+          $field_raw[++$n] = $item["value"];
+        }
+        $field_is_multiple = TRUE;
+      }
+      else $field_raw = $view->field[$field->options['id']]->advanced_render($row);
+    }
+    else {
+      $field_output = $view->field[$field->options['id']]->advanced_render($row);
+      $field_raw = (isset($view->field[$id]->field_alias) && isset($row->{$view->field[$id]->field_alias})) ? $row->{$view->field[$id]->field_alias} : NULL;
+    }
+
+    $img_match = array();
+    $src_match = array();
+    if (is_array($field_output)) {
+      foreach ($field_output as $i => $f) {
+        if (preg_match("/<img[^>]+>/i", $f, $img_match)) {
+          if (preg_match('/(src)="([^"]*)"/i', $img_match[0], $src_match))
+          $field_output[$i] = ($src_match[2]);
+        }
+      }
+    }
+    else {
+      if (preg_match("/<img[^>]+>/i", $field_output, $img_match)) {
+        if (preg_match('/(src)="([^"]*)"/i', $img_match[0], $src_match))
+          $field_output = ($src_match[2]);
+      }
+    }
+
+    if (empty($field->options['exclude'])) {
+      if (empty($field->options['exclude']) && !($field->options['hide_empty'] && (empty($field_output)))) {
+        $object = new stdClass();
+        $object->id = $id;
+        // Respect the 'empty' value if empty and "No results text" is given.
+        if (empty($field_output) && $field->options['empty']) {
+          $object->content = $field->options['empty'];
+        }
+        else {
+          $object->content = $field_output;
+        }
+        $object->raw = $field_raw;
+        $object->class = drupal_clean_css_identifier(strtolower($id));//views_css_safe($id);
+
+        $object->label = check_plain($view->field[$id]->label());
+
+        if ($object->label) {
+          if ($view->field[$id]->options['element_label_colon']) {
+            $object->label .= ': ';
+          }
+          else {
+            $object->label .= ' ';
+          }
+        }
+
+        $object->is_multiple = $field_is_multiple;
+        $rendered_fields[$id] = $object;
+
+      }
+    }
+  }
+  return $rendered_fields;
+}
+
+/**
+ * Gets JSON data from a View rendered in the JSON data document style.
+ *
+ * This is useful for when working with a JSON view in code.
+ *
+ * @param $name
+ *   The name of the view.
+ * @param $display_id
+ *   The display of the view to use.
+ * @param $args
+ *   The arguments to pass to the view.
+ * @param $raw
+ *   If TRUE, the JSON data is returned as a string.  Otherwise, an object
+ *   representation is returned.
+ * @return
+ *   The JSON data in the form of an object or a string or NULL otherwise.
+ */
+function search_autocomplete_get($name, $display_id = 'default', $args = array(), $raw = FALSE) {
+  $view = views_get_view($name);
+  if (!is_object($view)) return NULL;
+
+  $preview    = $view->preview($display_id, $args);
+  $start_pos  = strpos($preview, '{');
+  $finish_pos = strrpos($preview, '}');
+  $length     = $finish_pos - $start_pos + 1;
+  $json       = trim(substr($preview, $start_pos, $length));
+
+  if ($raw) {
+    return $json;
+  }
+
+  return json_decode($json);
+}
+
+/**
+ * Render a view's output as JSON.
+ *
+ * The function will directly output a JSON string instead of returning it.
+ *
+ * @param $items
+ *   The collection of items to encode into JSON.
+ * @param $options
+ *   Render options.
+ */
+
+/**
+ * Encodes JSON in a pretty-printed fashion.
+ *
+ * @deprecated The $option parameter in PHP 5.4.0 json_encode() deprecates this function.
+ *
+ * @see _search_autocomplete_json_encode
+ */
+function _search_autocomplete_encode_formatted($v, $depth = 0) {
+  $base_indent  = '&nbsp;&nbsp;';
+  $eol          = '<br />';
+  $indent       = str_repeat($base_indent, $depth);
+
+  // This is based on the drupal_to_js() function.
+  switch (gettype($v)) {
+    case 'boolean':
+      // Lowercase is necessary!
+      return $v ? 'true' : 'false';
+
+    case 'integer':
+    case 'double':
+      return $v;
+
+    case 'resource':
+    case 'string':
+      $search   = array('"', chr(92), chr(8), chr(12), chr(13) . chr(10), chr(10), chr(13), chr(9));
+      $replace  = array('\"', '\\', '\b', '\f', '\n', '\n', '\r', '\t');
+      $output   = str_replace($search, $replace, $v);
+/* *
+      $output = str_replace(array("\r", "\n", "<", ">", "&"),
+                           array('\r', '\n', '\x3c', '\x3e', '\x26'),
+                           addslashes($output));
+/* */
+      return '"' . check_plain($output) . '"';
+
+    case 'array':
+      // Arrays in JSON can't be associative.  If the array is empty or if it
+      // has sequential whole number keys starting with 0, it's not associative
+      // so we can go ahead and convert it as an array.
+      if (empty($v) || array_keys($v) === range(0, sizeof($v) - 1)) {
+        $output = array();
+        foreach ($v as $val) {
+          $output[] = $indent . $base_indent . _search_autocomplete_encode_formatted($val, $depth + 1);
+        }
+        return '[' . (!empty($output) ? $eol . implode(',' . $eol, $output) . $eol . $indent : '') . ']';
+      }
+      // Otherwise, fall through to convert the array as an object.
+
+    case 'object':
+      $output = array();
+      foreach ($v as $key => $val) {
+        $output[] = $indent . $base_indent . _search_autocomplete_encode_formatted(strval($key)) . ' : ' . _search_autocomplete_encode_formatted($val, $depth + 1);
+      }
+      return '{' . (!empty($output) ? $eol . implode(',' . $eol, $output) . $eol . $indent : '') . '}';
+
+    default:
+      return 'null';
+  }
+}
+
+function _search_autocomplete_debug_stop($var, $location) {
+  print("Location:$location\n");
+  var_dump($var);
+  module_Invoke_all('exit');
+  exit;
+}
+
+/**
+ * Backwards-compatible JSON encoder.
+ *
+ * Provides backwars-compatible support for more JSON encoding formats.
+ * Uses PHP's native JSON encoding when PHP 5.3.0 or greater is detected.
+ * Fallbacks to manual encoding/escaping when PHP 5.2.x and below is detected.
+ *
+ * @param array $rows
+ *   Results from template_preprocess_views_search_autocomplete_style_simple().
+ * @param int $bitmask
+ *   Integer to use as the $bitmask parameter for json_encode().
+ */
+function _search_autocomplete_json_encode($rows, $bitmask = NULL) {
+
+  if (PHP_MAJOR_VERSION >= 5 && PHP_MINOR_VERSION >= 3) {
+    $json = json_encode($rows, $bitmask);
+    // Encoding features not supported before 5.4.x.
+    if (PHP_MINOR_VERSION <= 4) {
+      $json = str_replace(array('\/'), array('/'), $json);
+    }
+  }
+  else {
+    $json = json_encode($rows);
+    $json = str_replace(array('\/'), array('/'), $json);
+  }
+  return $json;
+}
+
+/**
+ * Implements hook_views_default_views().
+ * Creates a defaults view as a user helper
+ */
+function search_autocomplete_views_default_views() {
+  return search_autocomplete_view_autocomplete();
+}
+/**
+ * Begin view
+ */
+function search_autocomplete_view_autocomplete() {
+
+  // AUTOCOMPLETE NODE VIEW
+  $view_nodes = new view();
+  $view_nodes->name = 'autocomplete_nodes';
+  $view_nodes->description = '';
+  $view_nodes->tag = 'default';
+  $view_nodes->base_table = 'node';
+  $view_nodes->human_name = 'autocomplete-nodes';
+  $view_nodes->core = 7;
+  $view_nodes->api_version = '3.0';
+  $view_nodes->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  /* Display: Master */
+  $handler = $view_nodes->new_display('default', 'Master', 'default');
+  $handler->display->display_options['title'] = 'Node title suggestions for autocompletion';
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['query']['options']['query_comment'] = FALSE;
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['options']['reset_button_label'] = 'Réinitialiser';
+  $handler->display->display_options['pager']['type'] = 'some';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '15';
+  $handler->display->display_options['pager']['options']['offset'] = '0';
+  $handler->display->display_options['style_plugin'] = 'search_autocomplete';
+  /* Champ: Contenu: Titre */
+  $handler->display->display_options['fields']['title']['id'] = 'title';
+  $handler->display->display_options['fields']['title']['table'] = 'node';
+  $handler->display->display_options['fields']['title']['field'] = 'title';
+  $handler->display->display_options['fields']['title']['label'] = 'title';
+  $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
+  $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;
+  /* Sort criterion: Contenu: Titre */
+  $handler->display->display_options['sorts']['title']['id'] = 'title';
+  $handler->display->display_options['sorts']['title']['table'] = 'node';
+  $handler->display->display_options['sorts']['title']['field'] = 'title';
+  /* Filter criterion: Contenu: Publié */
+  $handler->display->display_options['filters']['status']['id'] = 'status';
+  $handler->display->display_options['filters']['status']['table'] = 'node';
+  $handler->display->display_options['filters']['status']['field'] = 'status';
+  $handler->display->display_options['filters']['status']['value'] = 1;
+  $handler->display->display_options['filters']['status']['group'] = 1;
+  $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
+  /* Filter criterion: Content revision: Titre */
+  $handler->display->display_options['filters']['title']['id'] = 'title';
+  $handler->display->display_options['filters']['title']['table'] = 'node_revision';
+  $handler->display->display_options['filters']['title']['field'] = 'title';
+  $handler->display->display_options['filters']['title']['operator'] = 'contains';
+  $handler->display->display_options['filters']['title']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['title']['expose']['operator_id'] = 'title_op';
+  $handler->display->display_options['filters']['title']['expose']['label'] = 'title';
+  $handler->display->display_options['filters']['title']['expose']['operator'] = 'title_op';
+  $handler->display->display_options['filters']['title']['expose']['identifier'] = 'filter';
+  $handler->display->display_options['filters']['title']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
+
+  /* Display: Page */
+  $handler = $view_nodes->new_display('page', 'Page', 'page');
+  $handler->display->display_options['path'] = 'autocomplete-nodes';
+  $translatables['autocomplete_nodes'] = array(
+    t('Master'),
+    t('Node title suggestions for autocompletion'),
+    t('more'),
+    t('Apply'),
+    t('Réinitialiser'),
+    t('Sort by'),
+    t('Asc'),
+    t('Desc'),
+    t('title'),
+    t('Page'),
+  );
+  /* Add the view */
+  $views[$view_nodes->name] = $view_nodes;
+
+  // AUTOCOMPLETE USER VIEW
+  $view_users = new view();
+  $view_users->name = 'autocomplete_users';
+  $view_users->description = '';
+  $view_users->tag = 'default';
+  $view_users->base_table = 'users';
+  $view_users->human_name = 'autocomplete-users';
+  $view_users->core = 7;
+  $view_users->api_version = '3.0';
+  $view_users->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  /* Display: Master */
+  $handler = $view_users->new_display('default', 'Master', 'default');
+  $handler->display->display_options['title'] = 'autocomplete_users';
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['access']['perm'] = 'access user profiles';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['query']['options']['query_comment'] = FALSE;
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['exposed_form']['options']['reset_button_label'] = 'Réinitialiser';
+  $handler->display->display_options['pager']['type'] = 'some';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '15';
+  $handler->display->display_options['pager']['options']['offset'] = '0';
+  $handler->display->display_options['style_plugin'] = 'search_autocomplete';
+  /* Champ: Utilisateur: Nom */
+  $handler->display->display_options['fields']['name']['id'] = 'name';
+  $handler->display->display_options['fields']['name']['table'] = 'users';
+  $handler->display->display_options['fields']['name']['field'] = 'name';
+  $handler->display->display_options['fields']['name']['label'] = '';
+  $handler->display->display_options['fields']['name']['alter']['word_boundary'] = FALSE;
+  $handler->display->display_options['fields']['name']['alter']['ellipsis'] = FALSE;
+  /* Sort criterion: Utilisateur: Nom */
+  $handler->display->display_options['sorts']['name']['id'] = 'name';
+  $handler->display->display_options['sorts']['name']['table'] = 'users';
+  $handler->display->display_options['sorts']['name']['field'] = 'name';
+  /* Filter criterion: Utilisateur: Actif */
+  $handler->display->display_options['filters']['status']['id'] = 'status';
+  $handler->display->display_options['filters']['status']['table'] = 'users';
+  $handler->display->display_options['filters']['status']['field'] = 'status';
+  $handler->display->display_options['filters']['status']['value'] = '1';
+  $handler->display->display_options['filters']['status']['group'] = 1;
+  $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
+  /* Filter criterion: Utilisateur: Name (raw) */
+  $handler->display->display_options['filters']['name']['id'] = 'name';
+  $handler->display->display_options['filters']['name']['table'] = 'users';
+  $handler->display->display_options['filters']['name']['field'] = 'name';
+  $handler->display->display_options['filters']['name']['operator'] = 'contains';
+  $handler->display->display_options['filters']['name']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['name']['expose']['operator_id'] = 'name_op';
+  $handler->display->display_options['filters']['name']['expose']['label'] = 'Authenticated user name (raw)';
+  $handler->display->display_options['filters']['name']['expose']['operator'] = 'name_op';
+  $handler->display->display_options['filters']['name']['expose']['identifier'] = 'filter';
+  $handler->display->display_options['filters']['name']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
+  /* Display: Page */
+  $handler = $view_users->new_display('page', 'Page', 'page');
+  $handler->display->display_options['path'] = 'autocomplete-users';
+  $translatables['autocomplete_users'] = array(
+    t('Master'),
+    t('autocomplete_users'),
+    t('more'),
+    t('Apply'),
+    t('Réinitialiser'),
+    t('Sort by'),
+    t('Asc'),
+    t('Desc'),
+    t('Authenticated user name (raw)'),
+    t('Page'),
+  );
+  $views[$view_users->name] = $view_users;
+
+  // AUTOCOMPLETE NODE WORDS
+  $view_words = new view();
+  $view_words->name = 'autocomplete_words';
+  $view_words->description = '';
+  $view_words->tag = 'default';
+  $view_words->base_table = 'node';
+  $view_words->human_name = 'autocomplete-words';
+  $view_words->core = 7;
+  $view_words->api_version = '3.0';
+  $view_words->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Master */
+  $handler = $view_words->new_display('default', 'Master', 'default');
+  $handler->display->display_options['title'] = 'autocomplete-words';
+  $handler->display->display_options['use_more_always'] = FALSE;
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'some';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '15';
+  $handler->display->display_options['style_plugin'] = 'search_autocomplete';
+  /* Field: Content: Title */
+  $handler->display->display_options['fields']['title']['id'] = 'title';
+  $handler->display->display_options['fields']['title']['table'] = 'node';
+  $handler->display->display_options['fields']['title']['field'] = 'title';
+  $handler->display->display_options['fields']['title']['label'] = 'is contained in';
+  $handler->display->display_options['fields']['title']['alter']['word_boundary'] = FALSE;
+  $handler->display->display_options['fields']['title']['alter']['ellipsis'] = FALSE;
+  /* Sort criterion: Content: Post date */
+  $handler->display->display_options['sorts']['created']['id'] = 'created';
+  $handler->display->display_options['sorts']['created']['table'] = 'node';
+  $handler->display->display_options['sorts']['created']['field'] = 'created';
+  $handler->display->display_options['sorts']['created']['order'] = 'DESC';
+  /* Filter criterion: Content: Published */
+  $handler->display->display_options['filters']['status']['id'] = 'status';
+  $handler->display->display_options['filters']['status']['table'] = 'node';
+  $handler->display->display_options['filters']['status']['field'] = 'status';
+  $handler->display->display_options['filters']['status']['value'] = 1;
+  $handler->display->display_options['filters']['status']['group'] = 1;
+  $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
+  /* Filter criterion: Content: Body (body) */
+  $handler->display->display_options['filters']['body_value']['id'] = 'body_value';
+  $handler->display->display_options['filters']['body_value']['table'] = 'field_data_body';
+  $handler->display->display_options['filters']['body_value']['field'] = 'body_value';
+  $handler->display->display_options['filters']['body_value']['operator'] = 'contains';
+  $handler->display->display_options['filters']['body_value']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['body_value']['expose']['operator_id'] = 'body_value_op';
+  $handler->display->display_options['filters']['body_value']['expose']['label'] = 'Body (body)';
+  $handler->display->display_options['filters']['body_value']['expose']['operator'] = 'body_value_op';
+  $handler->display->display_options['filters']['body_value']['expose']['identifier'] = 'filter';
+  $handler->display->display_options['filters']['body_value']['expose']['remember_roles'] = array(
+    2 => '2',
+    1 => 0,
+    3 => 0,
+  );
+  /* Display: Page */
+  $handler = $view_words->new_display('page', 'Page', 'page');
+  $handler->display->display_options['path'] = 'autocomplete-words';
+  $translatables['autocomplete_words'] = array(
+    t('Master'),
+    t('autocomplete-words'),
+    t('more'),
+    t('Apply'),
+    t('Reset'),
+    t('Sort by'),
+    t('Asc'),
+    t('Desc'),
+    t('is contained in'),
+    t('Body (body)'),
+    t('Page'),
+  );
+  $views[$view_words->name] = $view_words;
+
+  return $views;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/views/plugins/views_plugin_style_autocomplete.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,61 @@
+<?php
+/**
+ * @file
+ * Implements views_plugin_style for search_autocomplete
+ */
+
+/**
+ * Implements views_plugin_style
+ */
+class views_plugin_style_autocomplete extends views_plugin_style {
+  /**
+   * Implements views_plugin_style::option_definition
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    return $options;
+  }
+
+  /**
+   * Provide a form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+  }
+
+  /**
+   * Implements view_style_plugin::theme_functions(). Returns an array of theme functions to use
+   * for the current style plugin
+   * @return array
+   */
+  function theme_functions() {
+    $options = $this->options;
+    $hook = 'views_search_autocomplete_style';
+    return views_theme_functions($hook, $this->view, $this->display);
+  }
+
+  /**
+   * Implements views_style_plugin::additional_theme_functions(). Returns empty array.
+   * @return array
+   */
+  function additional_theme_functions() {
+    return array();
+  }
+
+  /**
+   * Implements view_style_plugin::render()
+   */
+  function render() {
+    $view = $this->view;
+    $options = $this->options;
+    $field = $view->field;
+
+    $rows = array();
+    foreach ($view->result as $count => $row) {
+      $view->row_index = $count;
+      $rows[] = _search_autocomplete_render_fields($view, $row);
+    }
+    unset($view->row_index);
+
+    return theme($this->theme_functions(), array('view' => $view, 'options' => $options, 'rows' => $rows));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/views/search_autocomplete.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,36 @@
+<?php
+/**
+ * @file
+ * Views style plugin to render nodes in the JSON data format.
+ *
+ * @see views_plugin_style_json.inc
+ * @ingroup views_plugins
+ */
+
+/**
+ * Implements hook_views_plugins().
+ */
+function search_autocomplete_views_plugins() {
+
+  $path = drupal_get_path('module', 'search_autocomplete') . '/views';
+  return array(
+    'module' => 'search_autocomplete',
+    'style' => array(
+      'search_autocomplete' => array(
+        'title'             => t('Autocompletion JSON'),
+        'path'              => $path . '/plugins',
+        'help'              => t('Displays nodes in the JSON data format.'),
+        'handler'           => 'views_plugin_style_autocomplete',
+        'theme'             => 'views_search_autocomplete_style',
+        'theme file'        => 'views_search_autocomplete_style.theme.inc',
+        'theme path'        => $path . '/theme',
+        'uses row plugin'   => FALSE,
+        'uses fields'       => TRUE,
+        'uses options'      => TRUE,
+        'type'              => 'normal',
+        'help_topic'        => 'style-autocomplete',
+        'even empty'        => TRUE,
+      ),
+    ),
+  );
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/views/theme/views-search-autocomplete-style.tpl.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,33 @@
+<?php
+/**
+ * @file views-views-json-style.tpl.php
+ * This template file is never used. The switch for choosing among the different
+ * views_search_autocomplete_* themes based on format is done in
+ * views_plugin_style_json->theme_functions()
+ *
+ * - $view: The View object.
+ * - $rows: Array of row objects as rendered by _search_autocomplete_render_fields
+ *   $options: Array of plugin style options
+ *
+ * @ingroup views_templates
+ * @see views_plugin_style_json.inc
+ * @see views_search_autocomplete_style.theme.inc
+ */
+
+if ($view->override_path) {
+  // We're inside a live preview where the JSON is pretty-printed.
+  $json = _search_autocomplete_encode_formatted($rows);
+  print "<code>$json</code>";
+}
+else {
+  $json = _search_autocomplete_json_encode($rows, $bitmask);
+
+  // We want to send the JSON as a server response so switch the content
+  // type and stop further processing of the page.
+  $content_type = 'application/json';
+  drupal_add_http_header("Content-Type", "$content_type; charset=utf-8");
+  print $json;
+  //Don't think this is needed in .tpl.php files: module_invoke_all('exit');
+  exit;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/search_autocomplete/views/theme/views_search_autocomplete_style.theme.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * @file
+ * Views theme to render view fields as JSON.
+ *
+ * - $view: The view in use.
+ * - $rows: Array of row objects as rendered by _search_autocomplete_render_fields
+ * - $attachment: Not used currently
+ * - $options: The options for the style passed in from the UI.
+ *
+ * @ingroup views_templates
+ * @see search_autocomplete.views.inc
+ */
+function template_preprocess_views_search_autocomplete_style(&$vars) {
+  global $base_root;
+
+  $view = $vars["view"];
+  $rows = $vars["rows"];
+
+  $arg = '';
+  if (array_key_exists(0, $view->args))
+    $arg = $view->args[0] ? $view->args[0] : '';
+
+  $base = $view->base_table;
+  $objects = array();
+
+  $vars['bitmask'] = NULL;
+
+  $should_translite = search_autocomplete_get_translite();
+
+  foreach ($rows as $row) {
+
+    $object = array();
+
+    /* Convert the $rows into a hierachial key=>value array */
+    foreach ($row as  $field) {
+      $matches = array();
+
+      $regexp = "<a\s[^>]*href=(\"??)([^\" >]*?)\\1[^>]*>(.*)<\/a>";
+      if (preg_match("/$regexp/siU", htmlspecialchars_decode($field->content, ENT_QUOTES), $matches)) {
+
+        $link   = $base_root . $matches[2];
+        $value  = $matches[3];
+
+        //hack to romanize accents, this needs module transliteration enabled
+        if (function_exists('transliteration_get') && $should_translite) {
+          $romanised = transliteration_get($value, '?', language_default('language'));
+        }
+        else  $romanised = $value;
+
+        //compare both $value and $romanised
+        if ($arg == '' || mb_stripos($value, $arg, 0, 'UTF-8')  !== FALSE || mb_stripos( $romanised, $arg, 0, 'UTF-8')  !== FALSE ) {
+
+          $label = "";
+          if ($field->label)
+            $label = strip_tags($field->label);
+
+          $object['link']  = $link;
+          $object['label'] = $label . $value;
+          $object['value'] = $romanised;
+
+          $objects[] = $object;
+
+        }
+      }
+    }
+  }
+
+  // check if user wants nested arrays
+  $vars["rows"] = $objects;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,190 @@
+
+About
+=====
+
+Semantic Views allows you to alter the default HTML output by the Views module without overriding template files. This means, for example, you can change a field from being wrapped by a `<span>` tag to being wrapped in a `<h2>` tag.
+
+The module provides a Views 2 style and row style plugin. These plugins ideally work together but can be used separately.
+
+When properly configured, the Semantic Views style plugin can effectively replace Views' own unformatted, HTML List and Grid styles. The row style plugin can let help leverage your theme's other CSS styles more easily.
+
+Install
+=======
+
+Unzip the file into your `sites/all/modules` folder. Visit `admin/modules` and locate the module under *Other*. Tick the box, and 'Save' changes at the bottom of the page to enable it.
+
+For more help installing modules, see <http://drupal.org/node/70151>.
+
+Terminology
+===========
+
+* *Output style* -- Views output styles are the wrapper around row output. Grouping, row striping, and enumeration are managed by the output style plugin.
+* *Row style* -- Views row styles are the wrappers around individual field output. All of the fields for a result constitute a single row. Typically, this has been the most difficult output to theme.
+
+Example
+=======
+
+Semantic Views does not relieve site builders of the burden of theming their views, but it does allow them to create a hierarchical cascade of tags and to select CSS styles that have not been tailored for Views field row style output.
+
+A proper demonstration of the capabilities of this module is to compare the output of a single row in the original row style and the Semantic Views row style.
+
+Original Views field row style output
+-------------------------------------
+    <div class="views-row views-row-1 views-row-odd views-row-first">
+      <div class="views-field-title">
+        <span class="field-content">
+          <a href="/node/1" title="Augue Magna Cui Conventio Valetudo" alt="Augue Magna Cui Conventio Valetudo">
+            Augue Magna Cui Conventio Valetudo</a>
+        </span>
+      </div>
+      <div class="views-field-type">
+        <span class="field-content">
+          Story
+        </span>
+      </div>
+      <div class="views-field-teaser">
+        <div class="field-content">
+          <p>
+            node (story) - Abigo bene feugiat loquor neo lenis qui imputo. Suscipere molior obruo typicus jus euismod ille illum meus. Acsi populus pecus populus lobortis metuo voco. Aptent plaga incassum. Iriure cui cui commoveo eum hos dolor ex consectetuer. Typicus eros vulputate defui comis nobis humo. Ulciscor abigo occuro. Sagaciter tego dolore. Voco iusto jus. Abdo dolor verto gilvus mos iaceo vel loquor.
+          </p>
+        </div>
+      </div>
+      <div class="views-field-delete-node">
+        <label class="views-label-delete-node">
+          Delete link:
+        </label>
+        <span class="field-content">
+          <a href="/node/1/delete&amp;destination=demo%2Fviews">
+            delete</a>
+        </span>
+      </div>
+      <div class="views-field-edit-node">
+        <label class="views-label-edit-node">
+          Edit link:
+        </label>
+        <span class="field-content">
+          <a href="/node/1/edit&amp;destination=demo%2Fviews">
+            edit</a>
+        </span>
+      </div>
+    </div>
+
+Semantic Views field row style output
+-------------------------------------
+    <div class="row row-0 first odd">
+      <h2 class="title">
+        <a href="/node/1" title="Augue Magna Cui Conventio Valetudo" alt="Augue Magna Cui Conventio Valetudo">
+          Augue Magna Cui Conventio Valetudo
+        </a>
+      </h2>
+      <div class="node-type">
+        Story
+      </div>
+      <p>
+        node (story) - Abigo bene feugiat loquor neo lenis qui imputo. Suscipere molior obruo typicus jus euismod ille illum meus. Acsi populus pecus populus lobortis metuo voco. Aptent plaga incassum. Iriure cui cui commoveo eum hos dolor ex consectetuer. Typicus eros vulputate defui comis nobis humo. Ulciscor abigo occuro. Sagaciter tego dolore. Voco iusto jus. Abdo dolor verto gilvus mos iaceo vel loquor.
+      </p>
+      <label>
+        Delete link:
+      </label>
+      <a href="/node/1/delete&amp;destination=demo%2Fsemantic">
+        delete
+      </a>
+      <label>
+        Edit link:
+      </label>
+      <a href="/node/1/edit&amp;destination=demo%2Fsemantic">
+        edit
+      </a>
+    </div>
+
+Requirements
+============
+
+* Drupal 6
+* Views 2
+
+Suggestions
+----------
+
+* Advanced Help
+
+Usage
+=====
+
+After enabling the module, create a new view or edit an existing one that outputs fields not nodes. This module works for any Views base table (e.g., nodes, users, terms) and any display plugin (e.g., page, block, attachment). Select "Semantic Views" for the style and "Semantic Views : Fields" for the row style.
+
+It is possible to use the two plugins separately. The *row style* plugin lets you change the HTML markup that wraps around the field content. The *style* plugin lets you change the HTML markup that wraps around each row.
+
+Output style options
+--------------------
+![Output style options form](<path:output-style-options.png>)
+
+All of these options are **optional**. When an option allows a HTML element and a class attribute, omitting the HTML element will cause the class attribute to be ignored and that content will be output without any HTML wrapping it.
+
+**Note** Always input HTML elements without the `<` and `>`. Your valid input will be inserted between the angle brackets in the template.
+
+**Note** Any class attributes you input will be concatenated and rendered as the class attribute's value in the template. For example, your valid input `row node blog` as the class attribute for a `div` element will be rendered as `<div class="row node blog">`.
+
+### Grouping title
+
+For Views where the results are grouped, the HTML **element** and **class attribute** can be specified for the element that wraps the title.
+
+### List
+
+With this option, Semantic Views can behave like the Views 2 **HTML List** display plugin. HTML unordered, ordered and definition lists can be created in the by choosing a list type. It's important to remember that HTML lists have additional constraints on their child elements. `<ul>` and `<ol>` must have `<li>` children and `<dl>` must have `<dt>` and `<dd>` children.
+
+### Row
+
+Rows are the results of the executed view. The number of rows in a view display is determined by the pager (or if the number of results is less than the pager limit, the number of results).
+
+#### HTML element
+
+The HTML element for the row is usually `<div>`.
+
+#### Class attribute
+
+This is the basic class attribute for each row. If it includes a # the row number will be substituted. Multiple class attributes can be specified: `row` or `row row-#`.
+
+#### First and last classes
+
+By default, Views row style adds a `first` class attribute to the first result in the pager and a `last` class attribute to the last result in the pager.
+
+##### First/Last every n<sup>th</sup>
+
+When this is set to `0`, the *first* and *last* class attributes are added first and last results in the pager. If you specify a number greater than 1, *first* and *last* class attributes are added at that interval within the pager result set. This can be used to improve upon the **Grid** display plugin that comes with Views 2.
+
+For example, if you have a grid layout with 5 column units with a gutter maintained by right margins on all units except the last one, setting this option to `5` will add a `last` class to every 5th result row (not to be confused with rows in your grid layout). `first` class attributes are added to the first result row in the pager and to each result that follows a `last` result.
+
+If the following two options are left empty, the `first/last every nth` option has no effect.
+
+##### FIRST class attribute
+
+This is the actual class attribute that is inserted. It is optional and defaults to `first`.
+
+##### LAST class attribute
+
+This is the actual class attribute that is inserted. It is optional and defaults to `last`.
+
+#### Striping class attributes
+
+When this is set, every row will have *one* of the class attributes specified here. The default is `odd even` so that *n* row has a class attribute of `odd` and *n + 1* row has a class attribute of `even`. You are not limited to only two striping class attributes. It's perfectly valid to use `north south east west` to stripe your rows 4 different ways or to leave this option empty to disable striping.
+
+Row style options
+-----------------
+![Row style options form](<path:row-style-options.png>)
+
+For each field in your view, you can specify the HTML element and class attribute. These are both **optional**. Omitting the HTML element will cause the class attribute to be ignored and that content will be output without any HTML wrapping it. For example, you may want to omit the HTML element from the wrapper on a node teaser or user picture because these may already have adequate markup.
+
+* HTML element
+* Class attribute
+
+**Important!** There is no good way for Semantic Views to provide a default value for these options when new fields are added to your view. If you do not update the options for the row style, your field output will have no HTML element around it. The `div` that appears when you view the settings form for the row style is only saved when you actually click the `Update` button on the settings form.
+
+Author and credit
+=================
+
+Developer:
+Benjamin Doherty "bangpound" <http://drupal.org/user/16496>
+
+Documentation and Advanced Help:
+Heather James "heather" <http://drupal.org/user/740>
Binary file sites/all/modules/semanticviews/help/output-style-options.png has changed
Binary file sites/all/modules/semanticviews/help/row-style-options.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/help/semanticviews-help.html	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,4 @@
+<p>About Semantic Views</p>
+<p>Semantic Views allows you to alter the default HTML output by the Views module. This means, for example, you can change a field from being wrapped by a &lt;span&gt; tag to being wrapped in a &lt;h2&gt; tag.</p>
+<p>You can change the HTML wrapped around an entire row, or the HTML for each field.</p>
+<p>To use Semantic Views you must specify a Style: Semantic View and/or a Row style: Semantic Views : Fields. By just selecting the Style you can change the HTML output of the entire view, and group rows. If you select the Row Style: Semantic Views : Fields you can control the output of the HTML per field.</p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/help/semanticviews-tutorial.html	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,42 @@
+<p>This tutorial will guide you through specifying the elements for your views output using <em>Semantic Views : Fields</em> settings. This tutorial assumes you have Views installed.</p>
+<ul>
+  <li><strong>Create a view</strong>
+    <ol>
+      <li>Visit the <a href="base_url:admin/build/views">Views administration page</a></li>
+      <li>Click Add new view. Type in the name test_semantic view, select type 'Node', click <strong>Next</strong>.</li>
+    </ol>
+  </li>
+  <li><strong>Modify the view to use Semantic Views options</strong>
+    <ol>
+      <li>Locate the Basic settings column, click the <strong>Style:</strong> settings. </li>
+      <li> At the bottom section of this area, you will see a list of options under <em>How should this view be styled</em>. Select <em>Semantic Views</em>, and click <strong>Update</strong>. </li>
+      <li>Click options next to <strong>Row style. </strong>Select <em>Semantic Views : Fields</em>.</li>
+    </ol>
+  </li>
+  <li><strong>Select which fields to style</strong>
+    <ul>
+      <li>Click the <strong>+</strong> icon next to <strong>Fields</strong>.</li>
+      <li>In the <strong>Groups</strong> drop-down menu select 'Node', then check <em>Node: Body</em>, <em>Node: Post Date</em> and <em>Node: Title</em>. Click <strong>Add</strong>.</li>
+      <li>Under the next three options for Body, Post Date and Title, click <strong>Update</strong>, staying with the default settings for this tutorial.</li>
+      <li>Scroll back up to <strong>Fields</strong> and click the <strong>&uarr;&darr;</strong> icon to rearrange fields, so it is Title first.</li>
+    </ul>
+  </li>
+  <li><strong>Preview the default </strong></li>
+  <ol>
+    <li>At this stage you can preview the default settings. Click <strong>Save</strong>.</li>
+    <li>View the unstyled fields previewed at the bottom of the Views User Interface.</li>
+  </ol>
+  <li><strong>Modify the output for these fields</strong> </li>
+  <ol>
+    <li>Click the settings gear icon next to Row style: Semantic Views : Fields.</li>
+    <li>Scroll down to the <em>Row style options</em>, you can see the menu built for the fields you have chosen Title, Body and Post date.</li>
+    <li>Do not capitalize the elements and do not use &lt;&gt; symboles to specify the elements in the form.</li>
+    <li>Under <em>Ttitle</em> specify the element: <strong>h3</strong>. Optional: You can also edit your settings and specify custom Class attributes. put spaces in between each class attibute, and do not wrap class attributes in &quot;double quotes&quot;.</li>
+    <li>Under <em>Body</em> specify the element <strong>div</strong>. You are likely to have other block level elements such as a paragraph or blockquote. </li>
+    <li>Under <em>Post date</em> specify the element <strong>p.</strong></li>
+    <li>Select Skip empty fields</li>
+    <li>Click <strong>Update</strong>.</li>
+    <li>Click <strong>Save</strong> to save your settings.</li>
+  </ol>
+  <li><strong>You're done!</strong> You should see the modifications to your view when you preview it. </li>
+</ul>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/help/semanticviews.help.ini	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,24 @@
+[semanticviews-help]
+title = Semantic Views Help
+file = semanticviews-help
+weight = 0
+parent = 
+
+[style-unformatted]
+title = Style: Semantic Views
+file = style-unformatted
+weight = -5
+parent = semanticviews-help
+
+[style-row-fields]
+title = Row style: Semantic Views : Fields
+file = style-row-fields
+weight = 0
+parent = semanticviews-help
+
+[semanticviews-tutorial]
+title = Semantic Views Tutorial
+file = semanticviews-tutorial
+weight = 7
+parent = semanticviews-help
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/help/style-row-fields.html	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+<h2>Row style options</h2>
+
+<p><img src="path:row-style-options.png" alt="Row style options form" title="" /></p>
+
+<p>For each field in your view, you can specify the HTML element and class attribute. These are both <strong>optional</strong>. Omitting the HTML element will cause the class attribute to be ignored and that content will be output without any HTML wrapping it. For example, you may want to omit the HTML element from the wrapper on a node teaser or user picture because these may already have adequate markup.</p>
+
+<ul>
+<li>HTML element</li>
+<li>Class attribute</li>
+</ul>
+
+<p><strong>Important!</strong> There is no good way for Semantic Views to provide a default value for these options when new fields are added to your view. If you do not update the options for the row style, your field output will have no HTML element around it. The <pre>div</pre> that appears when you view the settings form for the row style is only saved when you actually click the <code>Update</code> button on the settings form.</p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/help/style-unformatted.html	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,53 @@
+<h2>Output style options</h2>
+
+<p><img src="path:output-style-options.png" alt="Output style options form" title="" /></p>
+
+<p>All of these options are <strong>optional</strong>. When an option allows a HTML element and a class attribute, omitting the HTML element will cause the class attribute to be ignored and that content will be output without any HTML wrapping it.</p>
+
+<p><strong>Note</strong> Always input HTML elements without the <code>&lt;</code> and <code>&gt;</code>. Your valid input will be inserted between the angle brackets in the template.</p>
+
+<p><strong>Note</strong> Any class attributes you input will be concatenated and rendered as the class attribute's value in the template. For example, your valid input <code>row node blog</code> as the class attribute for a <code>div</code> element will be rendered as <code>&lt;div class="row node blog"&gt;</code>.</p>
+
+<h3>Grouping title</h3>
+
+<p>For Views where the results are grouped, the HTML <strong>element</strong> and <strong>class attribute</strong> can be specified for the element that wraps the title.</p>
+
+<h3>List</h3>
+
+<p>With this option, Semantic Views can behave like the Views 2 <strong>HTML List</strong> display plugin. HTML unordered, ordered and definition lists can be created in the by choosing a list type. It's important to remember that HTML lists have additional constraints on their child elements. <code>&lt;ul&gt;</code> and <code>&lt;ol&gt;</code> must have <code>&lt;li&gt;</code> children and <code>&lt;dl&gt;</code> must have <code>&lt;dt&gt;</code> and <code>&lt;dd&gt;</code> children.</p>
+
+<h3>Row</h3>
+
+<p>Rows are the results of the executed view. The number of rows in a view display is determined by the pager (or if the number of results is less than the pager limit, the number of results).</p>
+
+<h4>HTML element</h4>
+
+<p>The HTML element for the row is usually <code>&lt;div&gt;</code>.</p>
+
+<h4>Class attribute</h4>
+
+<p>This is the basic class attribute for each row. If it includes a # the row number will be substituted. Multiple class attributes can be specified: <code>row</code> or <code>row row-#</code>.</p>
+
+<h4>First and last classes</h4>
+
+<p>By default, Views row style adds a <code>first</code> class attribute to the first result in the pager and a <code>last</code> class attribute to the last result in the pager.</p>
+
+<h5>First/Last every n<sup>th</sup></h5>
+
+<p>When this is set to <code>0</code>, the <em>first</em> and <em>last</em> class attributes are added first and last results in the pager. If you specify a number greater than 1, <em>first</em> and <em>last</em> class attributes are added at that interval within the pager result set. This can be used to improve upon the <strong>Grid</strong> display plugin that comes with Views 2.</p>
+
+<p>For example, if you have a grid layout with 5 column units with a gutter maintained by right margins on all units except the last one, setting this option to <code>5</code> will add a <code>last</code> class to every 5th result row (not to be confused with rows in your grid layout). <code>first</code> class attributes are added to the first result row in the pager and to each result that follows a <code>last</code> result.</p>
+
+<p>If the following two options are left empty, the <code>first/last every nth</code> option has no effect.</p>
+
+<h5>FIRST class attribute</h5>
+
+<p>This is the actual class attribute that is inserted. It is optional and defaults to <code>first</code>.</p>
+
+<h5>LAST class attribute</h5>
+
+<p>This is the actual class attribute that is inserted. It is optional and defaults to <code>last</code>.</p>
+
+<h4>Striping class attributes</h4>
+
+<p>When this is set, every row will have <em>one</em> of the class attributes specified here. The default is <code>odd even</code> so that <em>n</em> row has a class attribute of <code>odd</code> and <em>n + 1</em> row has a class attribute of <code>even</code>. You are not limited to only two striping class attributes. It's perfectly valid to use <code>north south east west</code> to stripe your rows 4 different ways or to leave this option empty to disable striping.</p>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews-view-fields.tpl.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,55 @@
+<?php
+/**
+ * @file semanticviews-view-fields.tpl.php
+ * Default simple view template to display all the fields as a row. The template
+ * outputs a full row by looping through the $fields array, printing the field's
+ * HTML element (as configured in the UI) and the class attributes. If a label
+ * is specified for the field, it is printed wrapped in a <label> element with
+ * the same class attributes as the field's HTML element.
+ *
+ * - $view: The view in use.
+ * - $fields: an array of $field objects. Each one contains:
+ *   - $field->content: The output of the field.
+ *   - $field->raw: The raw data for the field, if it exists. This is NOT output
+ *     safe.
+ *   - $field->element_type: The HTML element wrapping the field content and
+ *     label.
+ *   - $field->attributes: An array of attributes for the field wrapper.
+ *   - $field->handler: The Views field handler object controlling this field.
+ *     Do not use var_export to dump this object, as it can't handle the
+ *     recursion.
+ * - $row: The raw result object from the query, with all data it fetched.
+ *
+ * @see template_preprocess_semanticviews_view_fields()
+ * @ingroup views_templates
+ * @todo Justify this template. Excluding the PHP, this template outputs angle
+ * brackets, the label element, slashes and whitespace.
+ */
+?>
+<?php foreach ($fields as $id => $field): ?>
+
+  <?php if ($field->element_type): ?>
+    <<?php print $field->element_type; ?><?php print drupal_attributes($field->attributes); ?>>
+  <?php endif; ?>
+
+    <?php if ($field->label): ?>
+
+      <?php if ($field->label_element_type): ?>
+        <<?php print $field->label_element_type; ?><?php print drupal_attributes($field->label_attributes); ?>>
+      <?php endif; ?>
+
+          <?php print $field->label; ?>:
+
+      <?php if ($field->label_element_type): ?>
+        </<?php print $field->label_element_type; ?>>
+      <?php endif; ?>
+
+    <?php endif; ?>
+
+      <?php print $field->content; ?>
+
+  <?php if ($field->element_type): ?>
+    </<?php print $field->element_type; ?>>
+  <?php endif; ?>
+
+<?php endforeach; ?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews-view-unformatted.tpl.php	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,28 @@
+<?php
+/**
+ * @file views-view-unformatted.tpl.php
+ * Default simple view template to display a list of rows.
+ *
+ * @ingroup views_templates
+ */
+?>
+<?php if (!empty($title)): ?>
+  <<?php print $group_element; ?><?php print drupal_attributes($group_attributes); ?>>
+    <?php print $title; ?>
+  </<?php print $group_element; ?>>
+<?php endif; ?>
+<?php if (!empty($list_element)): ?>
+  <<?php print $list_element; ?><?php print drupal_attributes($list_attributes); ?>>
+<?php endif; ?>
+<?php foreach ($rows as $id => $row): ?>
+  <?php if (!empty($row_element)): ?>
+  <<?php print $row_element; ?><?php print drupal_attributes($row_attributes[$id]); ?>>
+  <?php endif; ?>
+    <?php print $row; ?>
+  <?php if (!empty($row_element)): ?>
+  </<?php print $row_element; ?>>
+  <?php endif; ?>
+<?php endforeach; ?>
+<?php if (!empty($list_element)): ?>
+  </<?php print $list_element; ?>>
+<?php endif; ?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,18 @@
+name = Semantic Views
+description = Views 3 plugins for UI management of output markup
+core = 7.x
+dependencies[] = views
+package = Views
+files[] = semanticviews.module
+files[] = semanticviews_plugin_row_fields.inc
+files[] = semanticviews_plugin_style_default.inc
+files[] = semanticviews.theme.inc
+files[] = semanticviews.views_default.inc
+files[] = semanticviews.views.inc
+
+; Information added by drupal.org packaging script on 2013-05-25
+version = "7.x-1.x-dev"
+core = "7.x"
+project = "semanticviews"
+datestamp = "1369453055"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,42 @@
+<?php
+/**
+ * @file semanticviews.module
+ * TODO: Enter file description here.
+ */
+
+/**
+ *  Implementation of hook_views_api().
+ */
+function semanticviews_views_api() {
+  return array(
+    'api' => 2.0,
+  );
+}
+
+/**
+ * Helper function that returns an array with field aliases as key and the
+ * field tokens as values.
+ *
+ * @see views_handler_field::get_render_tokens()
+ */
+function semanticviews_get_alias_tokens($view) {
+  $tokens = array();
+  // Now add replacements for our fields.
+  foreach ($view->display_handler->get_handlers('field') as $name => $handler) {
+    $tokens[$handler->field_alias] = "[$name]";
+  }
+  return $tokens;
+}
+
+/**
+ * Helper function that returns row replacements given a row and all tokens.
+ */
+function semanticviews_get_token_replacements($row, $tokens) {
+  $replacements = array();
+  foreach ($row as $alias => $value) {
+    if (!empty($tokens[$alias])) {
+      $replacements[$tokens[$alias]] = $value;
+    }
+  }
+  return $replacements;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews.theme.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,135 @@
+<?php
+/**
+ * @file semanticviews.theme.inc
+ * TODO: Enter file description here.
+ */
+
+/**
+ * Preprocess theme function to print a single record from a row, with fields
+ */
+function template_preprocess_semanticviews_view_fields(&$vars) {
+  $view = $vars['view'];
+
+  // Loop through the fields for this view.
+  $vars['fields'] = array(); // ensure it's at least an empty array.
+  foreach ($view->field as $id => $field) {
+    // render this even if set to exclude so it can be used elsewhere.
+    $field_output = $view->field[$id]->theme($vars['row']);
+    $empty = $field_output !== 0 && empty($field_output);
+    if (empty($field->options['exclude']) && !(($vars['options']['skip_blank'] || $field->options['hide_empty']) && $empty)) {
+      $object = new stdClass();
+
+      $object->content = $field_output;
+      if (isset($view->field[$id]->field_alias) && isset($vars['row']->{$view->field[$id]->field_alias})) {
+        $object->raw = $vars['row']->{$view->field[$id]->field_alias};
+      }
+      else {
+        $object->raw = NULL; // make sure it exists to reduce NOTICE
+      }
+
+      $object->handler = &$view->field[$id];
+
+      $semantic_html = $vars['options']['semantic_html'][$id];
+
+      // Field content
+      $object->element_type = check_plain($semantic_html['element_type']);
+      $object->attributes = array();
+      if ($semantic_html['class']) {
+        $object->attributes['class'] = $semantic_html['class'];
+      }
+
+      // Field label
+      $object->label = check_plain($view->field[$id]->label());
+      if (!empty($object->label)) {
+        $object->label_element_type = check_plain($semantic_html['label_element_type']);
+        $object->label_attributes = array();
+        if ($semantic_html['label_class']) {
+          $object->label_attributes['class'] = $semantic_html['label_class'];
+        }
+      }
+
+      $vars['fields'][$id] = $object;
+    }
+  }
+
+}
+
+/**
+ * Display the simple view of rows one after another
+ */
+function template_preprocess_semanticviews_view_unformatted(&$vars) {
+  $view = $vars['view'];
+
+  $vars['group_element'] = check_plain($vars['options']['group']['element_type']);
+  $vars['group_attributes'] = array();
+  if ($vars['options']['group']['class']) {
+    $vars['group_attributes']['class'] = $vars['options']['group']['class'];
+  }
+
+  $vars['list_element'] = check_plain($vars['options']['list']['element_type']);
+  $vars['list_attributes'] = array();
+  if ($vars['options']['list']['class']) {
+    $vars['list_attributes']['class'] = $vars['options']['list']['class'];
+  }
+
+  // TODO: set a default or handle empty value.
+  $vars['row_element'] = check_plain($vars['options']['row']['element_type']);
+  $last_every_nth = $vars['options']['row']['last_every_nth'];
+
+  $vars['row_attributes'] = array();
+
+  // Set up striping class array.
+  $stripes = array();
+  if (trim($vars['options']['row']['striping_classes'])) {
+    $stripes = explode(' ', trim($vars['options']['row']['striping_classes']));
+  }
+  $striping = count($stripes);
+
+  // Get alias tokens.
+  $tokens = semanticviews_get_alias_tokens($view);
+
+  foreach ($vars['rows'] as $id => $row) {
+    // Get token replacements.
+    $replacements = semanticviews_get_token_replacements($view->result[$id], $tokens);
+    // Add replacement for the row number.
+    $replacements['#'] = $id;
+
+    $vars['row_attributes'][$id] = array();
+    $classes = array();
+    if ($vars['options']['row']['class']) {
+      $classes[] = strtr($vars['options']['row']['class'], $replacements);
+    }
+    if ($vars['options']['row']['first_class']) {
+      // The FIRST class attribute can be used in two ways. When the "last every
+      // nth" option is specified, the FIRST attribute is added to the class in
+      // those intervals. This could be useful for grid designs where the first
+      // unit in a row needs a zero width margin.
+      if (($last_every_nth && $id % $last_every_nth == 0) ||
+         // Otherwise when last every nth is not set, the FIRST class is added
+         // to the first row in the pager set.
+         (!$last_every_nth && $id == 0)) {
+        $classes[] = strtr($vars['options']['row']['first_class'], $replacements);
+      }
+    }
+    if ($vars['options']['row']['last_class']) {
+      // The LAST class attribute can be used in two ways. When the "last every
+      // nth" option is specified, the LAST attribute is added to the class in
+      // those intervals. This could be useful for grid designs where the last
+      // unit in a row needs a zero width margin.
+      if (($last_every_nth && ($id + 1) % $last_every_nth == 0) ||
+         // Otherwise when last every nth is not set, the LAST class is added
+         // to the last row in the pager set.
+         (!$last_every_nth && ($id + 1) == count($vars['rows']))) {
+        $classes[] = strtr($vars['options']['row']['last_class'], $replacements);
+      }
+    }
+
+    if ($striping) {
+      $classes[] = strtr($stripes[$id % $striping], $replacements);
+    }
+
+    if (!empty($classes)) {
+      $vars['row_attributes'][$id]['class'] = implode(' ', $classes);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * Implementation of hook_views_plugins().
+ */
+function semanticviews_views_plugins() {
+  return array(
+    'style' => array(
+      'semanticviews_default' => array(
+        'title' => t('Semantic Views'),
+        'help' => t('Displays rows one after another.'),
+        'handler' => 'semanticviews_plugin_style_default',
+        'theme' => 'semanticviews_view_unformatted',
+        'theme file' => 'semanticviews.theme.inc',
+        'theme path' => drupal_get_path('module', 'semanticviews'),
+        'uses row plugin' => TRUE,
+        'uses options' => TRUE,
+        'uses grouping' => TRUE,
+        'type' => 'normal',
+        'help topic' => 'style-unformatted',
+      ),
+    ),
+    'row' => array(
+      'semanticviews_fields' => array(
+        'title' => t('Semantic Views : Fields'),
+        'help' => t('Displays the fields with an optional template.'),
+        'handler' => 'semanticviews_plugin_row_fields',
+        'theme' => 'semanticviews_view_fields',
+        'theme file' => 'semanticviews.theme.inc',
+        'theme path' => drupal_get_path('module', 'semanticviews'),
+        'uses fields' => TRUE,
+        'uses options' => TRUE,
+        'type' => 'normal',
+        'help topic' => 'style-row-fields',
+      ),
+    ),
+  );
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews.views_default.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,286 @@
+<?php
+
+/**
+ * Implementation of hook_views_default_views().
+ */
+function semanticviews_views_default_views() {
+  $view = new view;
+  $view->name = 'semantic_demo';
+  $view->description = '';
+  $view->tag = '';
+  $view->base_table = 'node';
+  $view->api_version = '3.0-alpha1';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Defaults */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->display->display_options['title'] = 'Semantic Views demo';
+  $handler->display->display_options['access']['type'] = 'none';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['style_plugin'] = 'default';
+  $handler->display->display_options['row_plugin'] = 'fields';
+  /* Field: Node: Title */
+  $handler->display->display_options['fields']['title']['id'] = 'title';
+  $handler->display->display_options['fields']['title']['table'] = 'node';
+  $handler->display->display_options['fields']['title']['field'] = 'title';
+  $handler->display->display_options['fields']['title']['label'] = '';
+  $handler->display->display_options['fields']['title']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['title']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['title']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['title']['link_to_node'] = 1;
+  /* Field: Node: Type */
+  $handler->display->display_options['fields']['type']['id'] = 'type';
+  $handler->display->display_options['fields']['type']['table'] = 'node';
+  $handler->display->display_options['fields']['type']['field'] = 'type';
+  $handler->display->display_options['fields']['type']['label'] = '';
+  $handler->display->display_options['fields']['type']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['type']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['type']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['type']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['type']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['type']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['type']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['type']['link_to_node'] = 0;
+  /* Field: Fields: body */
+  $handler->display->display_options['fields']['entity_id']['id'] = 'entity_id';
+  $handler->display->display_options['fields']['entity_id']['table'] = 'field_data_body';
+  $handler->display->display_options['fields']['entity_id']['field'] = 'entity_id';
+  $handler->display->display_options['fields']['entity_id']['label'] = '';
+  $handler->display->display_options['fields']['entity_id']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['entity_id']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['entity_id']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['entity_id']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['entity_id']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['entity_id']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['entity_id']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['entity_id']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['entity_id']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['entity_id']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['entity_id']['type'] = 'text_summary_or_trimmed';
+  $handler->display->display_options['fields']['entity_id']['settings'] = array(
+    'trim_length' => '600',
+  );
+  /* Field: Node: Delete link */
+  $handler->display->display_options['fields']['delete_node']['id'] = 'delete_node';
+  $handler->display->display_options['fields']['delete_node']['table'] = 'node';
+  $handler->display->display_options['fields']['delete_node']['field'] = 'delete_node';
+  $handler->display->display_options['fields']['delete_node']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['delete_node']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['delete_node']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['delete_node']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['delete_node']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['delete_node']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['delete_node']['alter']['html'] = 0;
+  /* Field: Node: Edit link */
+  $handler->display->display_options['fields']['edit_node']['id'] = 'edit_node';
+  $handler->display->display_options['fields']['edit_node']['table'] = 'node';
+  $handler->display->display_options['fields']['edit_node']['field'] = 'edit_node';
+  $handler->display->display_options['fields']['edit_node']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['edit_node']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['edit_node']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['edit_node']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['edit_node']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['edit_node']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['edit_node']['alter']['html'] = 0;
+  /* Filter: Node: Published */
+  $handler->display->display_options['filters']['status']['id'] = 'status';
+  $handler->display->display_options['filters']['status']['table'] = 'node';
+  $handler->display->display_options['filters']['status']['field'] = 'status';
+  $handler->display->display_options['filters']['status']['value'] = '1';
+  $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
+
+  /* Display: Unformatted (default) */
+  $handler = $view->new_display('page', 'Unformatted (default)', 'page_1');
+  $handler->display->display_options['path'] = 'semantic-views-demo/unformatted';
+  $handler->display->display_options['menu']['type'] = 'default tab';
+  $handler->display->display_options['menu']['title'] = 'Unformatted';
+  $handler->display->display_options['menu']['weight'] = '0';
+  $handler->display->display_options['tab_options']['type'] = 'normal';
+  $handler->display->display_options['tab_options']['title'] = 'Semantic Views demo';
+  $handler->display->display_options['tab_options']['weight'] = '0';
+
+  /* Display: Grid (default) */
+  $handler = $view->new_display('page', 'Grid (default)', 'page_2');
+  $handler->display->display_options['defaults']['style_plugin'] = FALSE;
+  $handler->display->display_options['style_plugin'] = 'grid';
+  $handler->display->display_options['defaults']['style_options'] = FALSE;
+  $handler->display->display_options['defaults']['row_plugin'] = FALSE;
+  $handler->display->display_options['row_plugin'] = 'fields';
+  $handler->display->display_options['defaults']['row_options'] = FALSE;
+  $handler->display->display_options['path'] = 'semantic-views-demo/grid';
+  $handler->display->display_options['menu']['type'] = 'tab';
+  $handler->display->display_options['menu']['title'] = 'Grid';
+  $handler->display->display_options['menu']['weight'] = '1';
+
+  /* Display: List (default) */
+  $handler = $view->new_display('page', 'List (default)', 'page_3');
+  $handler->display->display_options['defaults']['style_plugin'] = FALSE;
+  $handler->display->display_options['style_plugin'] = 'list';
+  $handler->display->display_options['defaults']['style_options'] = FALSE;
+  $handler->display->display_options['defaults']['row_plugin'] = FALSE;
+  $handler->display->display_options['row_plugin'] = 'fields';
+  $handler->display->display_options['defaults']['row_options'] = FALSE;
+  $handler->display->display_options['path'] = 'semantic-views-demo/list';
+  $handler->display->display_options['menu']['type'] = 'tab';
+  $handler->display->display_options['menu']['title'] = 'List';
+  $handler->display->display_options['menu']['weight'] = '2';
+
+  /* Display: Unformatted (semantic) */
+  $handler = $view->new_display('page', 'Unformatted (semantic)', 'page_4');
+  $handler->display->display_options['defaults']['style_plugin'] = FALSE;
+  $handler->display->display_options['style_plugin'] = 'semanticviews_default';
+  $handler->display->display_options['defaults']['style_options'] = FALSE;
+  $handler->display->display_options['defaults']['row_plugin'] = FALSE;
+  $handler->display->display_options['row_plugin'] = 'semanticviews_fields';
+  $handler->display->display_options['row_options']['skip_blank'] = 1;
+  $handler->display->display_options['row_options']['semantic_html'] = array(
+    'title' => array(
+      'element_type' => 'h2',
+      'class' => 'title',
+    ),
+    'type' => array(
+      'element_type' => 'div',
+      'class' => 'node-type',
+    ),
+    'entity_id' => array(
+      'element_type' => 'div',
+      'class' => 'teaser',
+    ),
+    'delete_node' => array(
+      'element_type' => 'div',
+      'class' => 'delete',
+      'label_element_type' => 'label',
+      'label_class' => '',
+    ),
+    'edit_node' => array(
+      'element_type' => 'div',
+      'class' => 'edit',
+      'label_element_type' => 'label',
+      'label_class' => '',
+    ),
+  );
+  $handler->display->display_options['defaults']['row_options'] = FALSE;
+  $handler->display->display_options['path'] = 'semantic-views-demo/unformatted-semantic';
+  $handler->display->display_options['menu']['type'] = 'tab';
+  $handler->display->display_options['menu']['title'] = 'Unformatted (semantic)';
+  $handler->display->display_options['menu']['weight'] = '0';
+  $handler->display->display_options['tab_options']['weight'] = '0';
+
+  /* Display: Grid (semantic) */
+  $handler = $view->new_display('page', 'Grid (semantic)', 'page_5');
+  $handler->display->display_options['defaults']['style_plugin'] = FALSE;
+  $handler->display->display_options['style_plugin'] = 'semanticviews_default';
+  $handler->display->display_options['style_options']['row']['class'] = 'grid-unit';
+  $handler->display->display_options['style_options']['row']['last_every_nth'] = '4';
+  $handler->display->display_options['defaults']['style_options'] = FALSE;
+  $handler->display->display_options['defaults']['row_plugin'] = FALSE;
+  $handler->display->display_options['row_plugin'] = 'semanticviews_fields';
+  $handler->display->display_options['row_options']['skip_blank'] = 1;
+  $handler->display->display_options['row_options']['semantic_html'] = array(
+    'title' => array(
+      'element_type' => 'h2',
+      'class' => 'title',
+    ),
+    'type' => array(
+      'element_type' => 'div',
+      'class' => 'node-type',
+    ),
+    'entity_id' => array(
+      'element_type' => 'div',
+      'class' => 'teaser',
+    ),
+    'delete_node' => array(
+      'element_type' => 'div',
+      'class' => 'delete',
+      'label_element_type' => 'label',
+      'label_class' => '',
+    ),
+    'edit_node' => array(
+      'element_type' => 'div',
+      'class' => 'edit',
+      'label_element_type' => 'label',
+      'label_class' => '',
+    ),
+  );
+  $handler->display->display_options['defaults']['row_options'] = FALSE;
+  $handler->display->display_options['defaults']['header'] = FALSE;
+  /* Header: Global: Text area */
+  $handler->display->display_options['header']['text']['id'] = 'area';
+  $handler->display->display_options['header']['text']['table'] = 'views';
+  $handler->display->display_options['header']['text']['field'] = 'area';
+  $handler->display->display_options['header']['text']['empty'] = FALSE;
+  $handler->display->display_options['header']['text']['content'] = '<style>
+    .grid-unit {
+      width: 20%;
+      margin-right: 5%;
+      float: left;
+    }
+    .first {
+      clear: left;
+    }
+    .last {
+      margin-right: 0;
+    }
+    </style>';
+  $handler->display->display_options['header']['text']['format'] = '2';
+  $handler->display->display_options['path'] = 'semantic-views-demo/grid-semantic';
+  $handler->display->display_options['menu']['type'] = 'tab';
+  $handler->display->display_options['menu']['title'] = 'Grid (semantic)';
+  $handler->display->display_options['menu']['weight'] = '1';
+  $handler->display->display_options['tab_options']['weight'] = '0';
+
+  /* Display: List (semantic) */
+  $handler = $view->new_display('page', 'List (semantic)', 'page_6');
+  $handler->display->display_options['defaults']['style_plugin'] = FALSE;
+  $handler->display->display_options['style_plugin'] = 'semanticviews_default';
+  $handler->display->display_options['style_options']['list']['element_type'] = 'ul';
+  $handler->display->display_options['style_options']['row']['element_type'] = 'li';
+  $handler->display->display_options['defaults']['style_options'] = FALSE;
+  $handler->display->display_options['defaults']['row_plugin'] = FALSE;
+  $handler->display->display_options['row_plugin'] = 'semanticviews_fields';
+  $handler->display->display_options['row_options']['skip_blank'] = 1;
+  $handler->display->display_options['row_options']['semantic_html'] = array(
+    'title' => array(
+      'element_type' => 'h2',
+      'class' => 'title',
+    ),
+    'type' => array(
+      'element_type' => 'div',
+      'class' => 'node-type',
+    ),
+    'entity_id' => array(
+      'element_type' => 'div',
+      'class' => 'teaser',
+    ),
+    'delete_node' => array(
+      'element_type' => 'div',
+      'class' => 'delete',
+      'label_element_type' => 'label',
+      'label_class' => '',
+    ),
+    'edit_node' => array(
+      'element_type' => 'div',
+      'class' => 'edit',
+      'label_element_type' => 'label',
+      'label_class' => '',
+    ),
+  );
+  $handler->display->display_options['defaults']['row_options'] = FALSE;
+  $handler->display->display_options['path'] = 'semantic-views-demo/list-semantic';
+  $handler->display->display_options['menu']['type'] = 'tab';
+  $handler->display->display_options['menu']['title'] = 'List (semantic)';
+  $handler->display->display_options['menu']['weight'] = '2';
+  $handler->display->display_options['tab_options']['weight'] = '0';
+  $views[$view->name] = $view;
+
+  return $views;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews_plugin_row_fields.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,116 @@
+<?php
+/**
+ * @file
+ * Contains the semantic row style plugin.
+ */
+
+/**
+ * The semantic 'fields' row plugin
+ *
+ * This displays fields one after another, giving options for HTML element and
+ * class.
+ *
+ * @ingroup views_row_plugins
+ */
+class semanticviews_plugin_row_fields extends views_plugin_row {
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['skip_blank'] = array('default' => FALSE);
+    // Field element_type and classes cannot be defined in the options
+    // definition because the field handlers are not attached when the option
+    // defaults are set up in the object's init() method.
+    $options['semantic_html'] = array('default' => array());
+    return $options;
+  }
+
+  /**
+   * Provide a form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $form['semantic_html'] = array(
+      '#tree' => TRUE,
+    );
+    foreach ($this->display->handler->get_handlers('field') as $field => $handler) {
+      if (!$handler->options['exclude']) {
+        $default_value = (isset($this->options['semantic_html'][$field]) && is_array($this->options['semantic_html'][$field])) ? $this->options['semantic_html'][$field] : array(
+          'element_type' => 'div',
+          'class' => '',
+          'label_element_type' => 'label',
+          'label_class' => ''
+        );
+        $form['semantic_html'][$field] = array(
+          '#title' => $handler->label() ? $handler->label() : $handler->ui_name(),
+          '#type' => 'fieldset',
+          '#attributes' => array(
+            'class' => 'clear-block',
+          ),
+        );
+        $form['semantic_html'][$field]['element_type'] = array(
+          '#prefix' => '<div class="views-left-30">',
+          '#suffix' => '</div>',
+          '#title' => 'Element',
+          '#type' => 'textfield',
+          '#size' => '10',
+          '#default_value' => $default_value['element_type'],
+        );
+        $form['semantic_html'][$field]['class'] = array(
+          '#prefix' => '<div class="views-right-70">',
+          '#suffix' => '</div>',
+          '#title' => 'Class attribute',
+          '#type' => 'textfield',
+          '#size' => '30',
+          '#default_value' => $default_value['class'],
+        );
+        if ($handler->label()) {
+          $form['semantic_html'][$field]['label_element_type'] = array(
+            '#prefix' => '<div class="views-left-30">',
+            '#suffix' => '</div>',
+            '#title' => 'Label element',
+            '#type' => 'textfield',
+            '#size' => '10',
+            '#default_value' => $default_value['label_element_type'],
+          );
+          $form['semantic_html'][$field]['label_class'] = array(
+            '#prefix' => '<div class="views-right-70">',
+            '#suffix' => '</div>',
+            '#title' => 'Label class attribute',
+            '#type' => 'textfield',
+            '#size' => '30',
+            '#default_value' => $default_value['label_class'],
+          );
+        }
+      }
+    }
+    $form['skip_blank'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => $this->options['skip_blank'],
+      '#title' => t('Skip empty fields'),
+      '#description' => t('Do not output anything when a field has no content. This has the same outcome as enabling the <em>Hide if empty</em> option for every field in this display.'),
+    );
+  }
+
+  /**
+   * Validate the options form.
+   */
+  function options_validate(&$form, &$form_state) {
+    parent::options_validate($form, $form_state);
+    // TODO: validate that the elements and classes are valid HTML. This is not
+    // a substitute for output filtering.
+  }
+
+  /**
+   * Validate the view.
+   */
+  function validate() {
+    $errors = parent::validate();
+
+    $display_handler = $this->display->handler;
+
+    if (!$display_handler->is_defaulted('fields') && $display_handler->is_defaulted('row_plugin')) {
+      $errors[] = t('Display "@display" overrides fields and must also override the row style plugin.', array('@display' => $this->display->display_title));
+    }
+
+    return $errors;
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/semanticviews/semanticviews_plugin_style_default.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,231 @@
+<?php
+/**
+ * @file
+ * Contains the default style plugin.
+ */
+
+/**
+ * Default style plugin to render rows one after another with no decorations.
+ *
+ * @ingroup views_style_plugins
+ */
+class semanticviews_plugin_style_default extends views_plugin_style {
+  /**
+   * Set default options
+   */
+  function options(&$options) {
+    parent::options($options);
+  }
+
+  /**
+   * Set default options
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+
+    // Group option definition.
+    $options['group'] = array(
+      'contains' => array(
+        'element_type' => array('default' => 'h3'),
+        'class' => array('default' => 'title'),
+      ),
+    );
+
+    // List option definition.
+    $options['list'] = array(
+      'contains' => array(
+        'element_type' => array('default' => ''),
+        'class' => array('default' => ''),
+      ),
+    );
+
+    // Row option definition.
+    $options['row'] = array(
+      'contains' => array(
+        'element_type' => array('default' => 'div'),
+        'class' => array('default' => ''),
+        'first_class' => array('default' => 'first'),
+        'last_class' => array('default' => 'last'),
+        'last_every_nth' => array('default' => '0'),
+        'striping_classes' => array('default' => 'odd even'),
+      ),
+    );
+
+    return $options;
+  }
+
+  /**
+   * Render the given style.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Group options.
+    $form['group'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Grouping title'),
+      '#description' => t('If using groups, the view will insert the grouping&rsquo;s title field.'),
+      '#attributes' => array(
+        'class' => 'clear-block',
+      ),
+    );
+    $form['group']['element_type'] = array(
+      '#prefix' => '<div class="views-left-30">',
+      '#suffix' => '</div>',
+      '#title' => t('Element'),
+      '#type' => 'textfield',
+      '#size' => '10',
+      '#default_value' => $this->options['group']['element_type'],
+    );
+    $form['group']['class'] = array(
+      '#prefix' => '<div class="views-right-70">',
+      '#suffix' => '</div>',
+      '#title' => t('Class attribute'),
+      '#type' => 'textfield',
+      '#size' => '30',
+      '#default_value' => $this->options['group']['class'],
+    );
+
+    // List options.
+    $form['list'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('List'),
+      '#description' => t('If the output should be a HTML list, select the element and class attribute. The row element should also be set to %li.', array('%li' => 'li')),
+      '#attributes' => array(
+        'class' => 'clear-block',
+      ),
+    );
+    $form['list']['element_type'] = array(
+      '#prefix' => '<div class="views-left-30">',
+      '#suffix' => '</div>',
+      '#type' => 'radios',
+      '#title' => t('List type'),
+      '#options' => array(
+        '' => t('None'),
+        'ul' => t('Unordered list'),
+        'ol' => t('Ordered list'),
+        'dl' => t('Definition list'),
+      ),
+      '#default_value' => $this->options['list']['element_type'],
+    );
+    $form['list']['class'] = array(
+      '#prefix' => '<div class="views-right-70">',
+      '#suffix' => '</div>',
+      '#title' => t('Class attribute'),
+      '#type' => 'textfield',
+      '#size' => '30',
+      '#default_value' => $this->options['list']['class'],
+    );
+
+    // Row options.
+    $form['row'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Row'),
+      '#attributes' => array(
+        'class' => 'clear-block',
+      ),
+    );
+    $form['row']['element_type'] = array(
+      '#prefix' => '<div class="clear-block"><div class="views-left-30">',
+      '#suffix' => '</div>',
+      '#title' => t('Element'),
+      '#type' => 'textfield',
+      '#size' => '10',
+      '#default_value' => $this->options['row']['element_type'],
+    );
+    $form['row']['class'] = array(
+      '#prefix' => '<div class="views-right-70">',
+      '#suffix' => '</div></div>',
+      '#title' => t('Class attribute'),
+      '#type' => 'textfield',
+      '#size' => '30',
+      '#default_value' => $this->options['row']['class'],
+      '#description' => t('Insert a %hash where you want row enumeration.', array('%hash' => '#')),
+    );
+
+    // First and last class options.
+    $form['row']['first_last'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('First and last classes'),
+      // The #parents attribute must be set to avoid another array layer around
+      // the group of FIRST/LAST class attribute options.
+      '#parents' => array('style_options', 'row'),
+      '#description' => t('If the %last_every_nth option is empty or zero, the %first_class and %last_class are added once to only the first and last rows in the pager set. If this option is greater than 1, these classes are added to every n<sup>th</sup> row, which may be useful for grid layouts where the initial and final unit&rsquo;s lateral margins must be 0.', array(
+          '%last_every_nth' => 'FIRST/LAST every nth',
+          '%first_class' => 'FIRST class attribute',
+          '%last_class' => 'LAST class attribute',
+        )
+      ),
+      '#attributes' => array(
+        'class' => 'clear-block',
+      ),
+    );
+    $form['row']['first_last']['last_every_nth'] = array(
+      '#type' => 'textfield',
+      '#size' => '10',
+      '#title' => t('FIRST/LAST every n<sup>th</sup>'),
+      '#default_value' => $this->options['row']['last_every_nth'],
+    );
+    $form['row']['first_last']['first_class'] = array(
+      '#prefix' => '<div class="views-left-50">',
+      '#suffix' => '</div>',
+      '#title' => t('FIRST class attribute'),
+      '#type' => 'textfield',
+      '#size' => '30',
+      '#default_value' => $this->options['row']['first_class'],
+    );
+    $form['row']['first_last']['last_class'] = array(
+      '#prefix' => '<div class="views-right-50">',
+      '#suffix' => '</div>',
+      '#title' => t('LAST class attribute'),
+      '#type' => 'textfield',
+      '#size' => '30',
+      '#default_value' => $this->options['row']['last_class'],
+    );
+
+    // Striping class options.
+    $form['row']['striping_classes'] = array(
+      '#title' => t('Striping class attributes'),
+      '#type' => 'textfield',
+      '#size' => '30',
+      '#default_value' => $this->options['row']['striping_classes'],
+      '#description' => t('One striping class attribute is applied to each row. Separate multiple attributes with a space.'),
+    );
+
+    // Get a list of the available fields for token replacement.
+    $options = array();
+    foreach ($this->view->display_handler->get_handlers('field') as $field => $handler) {
+      $options[t('Fields')]["[$field]"] = $handler->ui_name();
+    }
+
+    // Default text.
+    $output = t('<p>Add additional fields to this display in order to get any available replacement patterns.</p>');
+    // We have some options, so make a list.
+    if (!empty($options)) {
+      $output = t('<p>The following replacement patterns are available for this display. Use the pattern shown on the left to display the value indicated on the right.</p>');
+      foreach (array_keys($options) as $type) {
+        if (!empty($options[$type])) {
+          $items = array();
+          foreach ($options[$type] as $key => $value) {
+            $items[] = $key . ' == ' . $value;
+          }
+          $output .= theme('item_list', $items, $type);
+        }
+      }
+    }
+
+    $form['row']['alter'] = array(
+      '#type' => 'markup',
+      '#value' => '<fieldset id="views-tokens-help"><legend>' . t('Replacement patterns') . '</legend>' . $output . '</fieldset>',
+    );
+  }
+
+  /**
+   * Validate the options form.
+   */
+  function options_validate(&$form, &$form_state) {
+    parent::options_validate($form, $form_state);
+    // TODO: validate that the elements and classes are valid HTML. This is not
+    // a substitute for output filtering.
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/CHANGELOG.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,10 @@
+This log does not contain all changes. Instead, it only logs the changes that
+may require action by the user or module developer.
+
+For a full list of changes, refer to the commit log at
+http://drupal.org/node/222959/commits
+
+SPARQL 7.x-2.x-dev
+------------------
+- #1214510: Change 'endpoint' property to 'uri' on endpoint objects
+- #1211898: Change API to take endpoint object.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+SUMMARY
+-------
+SPARQL module provides an API for other modules to use to run SPARQL queries.
+Queries can be run against external SPARQL endpoints or against RDF files,
+either local or on the Web. Running queries against files requires MySQL.
+
+
+BUG REPORTS
+-----------
+Post bug reports and feature requests to the issue tracking system at:
+
+<http://drupal.org/project/issues/sparql>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = SPARQL API
+description = Enables the use of SPARQL queries.
+package = RDF
+dependencies[] = rdf
+dependencies[] = rdfx
+core = 7.x
+files[] = sparql.test
+
+; Information added by drupal.org packaging script on 2011-10-01
+version = "7.x-2.0-alpha4"
+core = "7.x"
+project = "sparql"
+datestamp = "1317447408"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,37 @@
+<?php
+/**
+ * @file
+ * SPARQL API installation/uninstallation.
+ *
+ * @author Arto Bendiken <http://bendiken.net/>
+ * @copyright Copyright (c) 2007-2008 Arto Bendiken. All rights reserved.
+ * @license GPL <http://creativecommons.org/licenses/GPL/2.0/>
+ * @package sparql.module
+ */
+
+//////////////////////////////////////////////////////////////////////////////
+// Core API hooks
+
+/**
+ * Implements hook_enable().
+ */
+function sparql_enable() {
+  drupal_set_message(t('SPARQL API successfully installed.'));
+}
+
+/**
+ * Implements hook_install().
+ */
+function sparql_install() {
+
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function sparql_uninstall() {
+
+
+  db_query("DELETE FROM {variable} WHERE name LIKE 'sparql_%'");
+  cache_clear_all('variables', 'cache');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,180 @@
+<?php
+/*
+ * @file
+ * API function for running queries on external SPARQL endpoints.
+ */
+
+define('SPARQL_ENDPOINT', 'endpoint');
+
+/**
+ * Implements hook_help().
+ */
+function sparql_help($path, $arg = NULL) {
+  switch ($path) {
+    case 'admin/settings/sparql':
+      return '<p>' . t('The sparql module provides an interface for other modules to perform sparql queries') . '</p>'; // TODO
+  }
+}
+
+/**
+ * Executes a SPARQL query.
+ *
+ * @param $query
+ *   The SPARQL query to execute.
+ * @param $endpoint
+ *   An endpoint object, as returned by SPARQL Registry.
+ * @return
+ *   The SPARQL results.
+ */
+function sparql_request($query, $endpoint) {
+  $rows = _sparql_request($query, $endpoint);
+  return $rows;
+}
+
+function sparql_get_store($name, $type = 'store') {
+  $db = $GLOBALS['databases']['default']['default'];
+  $name = "sparql_store_$name";
+
+  $config = array(
+    /* db */
+    'db_host' => $db['host'],
+    'db_name' => $db['database'],
+    'db_user' => $db['username'],
+    'db_pwd' => $db['password'],
+    /* store */
+    'store_name' => $name,
+
+    /* endpoint */
+    'endpoint_features' => array(
+      'select', 'construct', 'ask', 'describe',
+      'load', 'insert', 'delete',
+      'dump' /* dump is a special command for streaming SPOG export */
+    ),
+    'endpoint_timeout' => 60, /* not implemented in ARC2 preview */
+    'endpoint_read_key' => '', /* optional */
+    'endpoint_write_key' => 'somekey', /* optional */
+    'endpoint_max_limit' => 500, /* optional */
+  );
+
+  /* instantiation */
+  if ($type == SPARQL_ENDPOINT) {
+    $store = ARC2::getStoreEndpoint($config);
+  }
+  else {
+    $store = ARC2::getStore($config);
+  }
+  if (!$store->isSetUp()) {
+    $store->setUp();
+  }
+  return $store;
+}
+
+/**
+ * Runs a query against an endpoint.
+ *
+ * @param $query
+ *   The SPARQL query to execute.
+ * @param $endpoint
+ *   The endpoint to try the query against.
+ * @options
+ *   Options to use with the remote or local store, as passed to
+ *   sparql_request.
+ */
+function _sparql_request($query, $endpoint) {
+  // Initialize connection with the endpoint.
+  $store = _sparql_init_remote_store($endpoint);
+
+  // Execute the query.
+  $rs = $store->query($query);
+  if ($errors = $store->getErrors()) {
+    // Log errors.
+    foreach ($errors as $error) {
+      trigger_error($error, E_USER_ERROR);
+    }
+    return NULL;
+  }
+  else {
+    // Success!
+    return $rs;
+  }
+}
+
+/**
+ * Sets up an ARC2 RDF local repository.
+ *
+ * @param $name
+ *   The name of the local repository.
+ * @param $endpoint
+ *   Set to TRUE if this store should also be setup as a SPARQL endpoint.
+ * @return
+ *   An ARC2 store object.
+ */
+function _sparql_init_store($name, $endpoint = FALSE) {
+  // @todo fix this. Error reporting is off because ARC2 throws strict warnings.
+  error_reporting(0);
+
+  $db_spec = $GLOBALS['databases']['default']['default'];
+
+  $config = array(
+    /* db */
+    'db_name' => $db_spec['database'],
+    'db_user' => $db_spec['username'],
+    'db_pwd' => isset($db_spec['password']) ? $db_spec['password'] : '',
+    /* store */
+    'store_name' => $name,
+
+    /* endpoint */
+    'endpoint_features' => array(
+      'select', 'construct', 'ask', 'describe',
+      //'load', 'insert', 'delete',
+      'dump' /* dump is a special command for streaming SPOG export */
+    ),
+    'endpoint_timeout' => 60, /* not implemented in ARC2 preview */
+    'endpoint_read_key' => '', /* optional */
+    'endpoint_write_key' => '', /* optional */
+    'endpoint_max_limit' => 500, /* optional */
+  );
+
+  // If this site is exposing a SPARQL endpoint, instantiate the endpoint with
+  // the endpoint class which can be used for HTTP-based data access.
+  if ($endpoint) {
+    $store = ARC2::getStoreEndpoint($config);
+  }
+  // Otherwise, instantiate a locally accessible store.
+  else {
+    $store = ARC2::getStore($config);
+  }
+  if (!$store->isSetUp()) {
+    $store->setUp();
+  }
+
+  return $store;
+}
+
+/**
+ * Sets up an ARC2 RDF remote store.
+ *
+ * @param $endpoint
+ *   The remote SPARQL endpoint.
+ * @return
+ *   An ARC2 store object.
+ */
+function _sparql_init_remote_store($endpoint) {
+  $endpoint_url = $endpoint->uri;
+
+  // If there are query parameters that need to be added before ARC2 processing,
+  // add them here. Filter the array to remove empty values.
+  if (isset($endpoint->options['query_parameters'])) {
+    $endpoint_url = url($endpoint_url, array('query' => array_filter($endpoint->options['query_parameters'])));
+  }
+
+  $config = array(
+    /* remote endpoint */
+    'remote_store_endpoint' => $endpoint_url,
+  );
+
+  /* instantiation */
+  $store = ARC2::getRemoteStore($config);
+
+  return $store;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Tests for the sparql module.
+ *
+ */
+
+//////////////////////////////////////////////////////////////////////////////
+// SPARQL unit tests (CIA Factbook)
+
+class SPARQL_CIAFactbookTestCase extends DrupalWebTestCase {
+  const ENDPOINT = 'http://www4.wiwiss.fu-berlin.de/factbook/sparql';
+  const COUNTRY  = 'http://www4.wiwiss.fu-berlin.de/factbook/ns#Country';
+
+  public function getInfo() {
+    return array(
+      'name'        => t('CIA Factbook'),
+      'description' => t('Executes queries against the CIA Factbook\'s SPARQL endpoint, attempting to parse resultsets in both JSON and XML format.'),
+      'group'       => t('SPARQL'),
+    );
+  }
+
+  function setup() {
+    parent::setup('rdf', 'sparql');
+  }
+
+  public function test_json_query() {
+    $this->query_classes(t('JSON'), array('format' => 'application/sparql-results+json', 'output' => 'json'));
+  }
+
+  public function test_xml_query() {
+    $this->query_classes(t('XML'), array('format' => 'application/sparql-results+xml', 'output' => 'xml'));
+  }
+
+  private function query_classes($format, array $options = array()) {
+    $results = $this->query('SELECT DISTINCT ?class WHERE { [] a ?class } ORDER BY ?class', $options);
+    $this->assertTrue(empty($this->errors), t('@format: No errors', array('@format' => $format)));
+    $this->assertNotNull($results, t('@format: Has results', array('@format' => $format)));
+    $this->assertEqual(count($results), 1, t('@format: Has one result', array('@format' => $format)));
+    $this->assertTrue(isset($results[0]['class']), t('@format: Contains ?class column', array('@format' => $format)));
+    $this->assertEqual((string)$results[0]['class'], self::COUNTRY, t('@format: Correct answer', array('@format' => $format)));
+  }
+
+  private function query($query, array $options = array()) {
+    $this->errors = array();
+    return sparql_query($query, array_merge(array('endpoint' => self::ENDPOINT), $options), $this->errors);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql_endpoint/sparql_endpoint.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = SPARQL Endpoint
+description = Expose local RDF data in a SPARQL endpoint.
+package = RDF
+dependencies[] = rdfx
+dependencies[] = sparql
+version = VERSION
+core = 7.x
+
+; Information added by drupal.org packaging script on 2011-10-01
+version = "7.x-2.0-alpha4"
+core = "7.x"
+project = "sparql"
+datestamp = "1317447408"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql_endpoint/sparql_endpoint.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Install, update and uninstall functions for the SPARQL Endpoint module.
+ */
+
+/**
+ * Enable sparql module (new dependency).
+ */
+function sparql_endpoint_update_7001() {
+  $t = get_t();
+
+  module_enable(array('sparql'));
+  drupal_set_message($t('The SPARQL module is now required by the SPARQL Endpoint module and has been enabled.'));
+}
+
+/**
+ * Move SPARQL endpoint tables.
+ */
+function sparql_endpoint_update_7002() {
+  $t = get_t();
+
+  $arc2_tables = array('g2t', 'id2val', 'o2val', 's2val', 'setting', 'triple');
+  $old_prefix = 'sparql_endpoint_arc2_';
+  $new_prefix = 'sparql_store_site_endpoint_';
+  foreach ($arc2_tables as $table) {
+    if (db_table_exists($old_prefix . $table)) {
+      db_rename_table($old_prefix . $table, $new_prefix . $table);
+    }
+  }
+
+  drupal_set_message($t('The SPARQL Endpoint database tables have been moved.'), 'status');
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql_endpoint/sparql_endpoint.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,107 @@
+<?php
+
+/**
+ * Implements hook_menu().
+ */
+function sparql_endpoint_menu() {
+  // @todo use access RDF data permission instead of access content.
+  $items['sparql'] = array(
+    'title' => 'SPARQL endpoint',
+    'page callback' => 'sparql_endpoint_sparql_endpoint',
+    'access arguments' => array('access content'),
+  );
+  $items['sparql_endpoint_index'] = array(
+    'title' => 'Build RDF index',
+    'page callback' => 'sparql_endpoint_index_rdf',
+    'access arguments' => array('administer rdf'),
+  );
+  return $items;
+}
+
+function sparql_endpoint_index_rdf() {
+  // Instantiate the ARC2 local store.
+  $store = sparql_get_store('site_endpoint');
+
+  // Emtpy the local store.
+  // FIXME optimize by doing this only when creating/saving a node.
+  $store->reset();
+
+  // Index all the nodes which are published.
+  $query = db_select('node', 'n')->extend('PagerDefault')->extend('TableSort');
+  $query->condition('n.status', 1);
+  $ids = $query
+    ->fields('n',array('nid'))
+    ->limit(500)
+    ->execute()
+    ->fetchCol();
+
+  foreach ($ids as $id) {
+    $rdf = rdfx_get_rdf_model('node', $id);
+    $store->insert($rdf->index, $rdf->uri);
+  }
+
+  // Index all the users.
+  $query = db_select('users', 'u')->extend('PagerDefault')->extend('TableSort');
+  $query->condition('u.uid', 0, '<>');
+  $ids = $query
+    ->fields('u', array('uid'))
+    ->limit(500)
+    ->execute()
+    ->fetchCol();
+
+  foreach ($ids as $id) {
+    $rdf = rdfx_get_rdf_model('user', $id);
+    $store->insert($rdf->index, $rdf->uri);
+  }
+
+  // Index all the terms.
+  $query = db_select('taxonomy_term_data', 't')->extend('PagerDefault')->extend('TableSort');
+  $ids = $query
+    ->fields('t', array('tid'))
+    ->limit(500)
+    ->execute()
+    ->fetchCol();
+
+  foreach ($ids as $id) {
+    $rdf = rdfx_get_rdf_model('taxonomy_term', $id);
+    $store->insert($rdf->index, $rdf->uri);
+  }
+
+  return t('The RDF index of the site has been rebuilt. Browse to the <a href="@endpoint">SPARQL endpoint</a> to query it.', array('@endpoint' => url('sparql')));
+}
+
+function sparql_endpoint_sparql_endpoint() {
+  // Instantiate the ARC2 SPARQL endpoint.
+  $ep = sparql_get_store('site_endpoint', SPARQL_ENDPOINT);
+  $ep->go();
+}
+
+/**
+ * Implements hook_node_insert().
+ */
+function sparql_endpoint_node_insert($node) {
+  // Instantiate the ARC2 local store.
+  $store = sparql_get_store('site_endpoint');
+
+  // Attach RDF mappings and build RDF model for the node.
+  $node = node_load($node->nid);
+  $rdf = rdfx_get_rdf_model('node', $node);
+
+  // Add node to the store.
+  $store->insert($rdf->index, $rdf->uri);
+}
+
+/**
+ * Implements hook_node_update().
+ */
+function sparql_endpoint_node_update($node) {
+  // Instantiate the ARC2 local store.
+  $store = sparql_get_store('site_endpoint');
+
+  // Build RDF model for the node.
+  $rdf = rdfx_get_rdf_model('node', $node);
+
+  // Cleans out the graph and reindex the node.
+  $store->query('DELETE FROM <' . $rdf->uri . '>');
+  $store->insert($rdf->index, $rdf->uri);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql_registry/sparql_registry.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+name = SPARQL Endpoints Registry
+description = SPARQL Endpoints Registry
+package = RDF
+core = 7.x
+files[] = sparql_registry.module
+
+; Information added by drupal.org packaging script on 2011-10-01
+version = "7.x-2.0-alpha4"
+core = "7.x"
+project = "sparql"
+datestamp = "1317447408"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql_registry/sparql_registry.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * Implements hook_schema().
+ *
+ * @see hook_schema()
+ * @link schemaapi Schema API @endlink
+ */
+function sparql_registry_schema() {
+  $schema['sparql_registry'] = array(
+    'description' => 'The base table for SPARQL Endpoints',
+    'fields' => array(
+      'srid' => array(
+        'description' => 'The primary identifier for an endpoint.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'title' => array(
+        'description' => 'The title of this endpoint, always treated as non-markup plain text.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'uri' => array(
+        'description' => 'The URI of this endpoint.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'options' => array(
+        'description' => 'Additional query options.',
+        'type' => 'blob',
+        'not null' => FALSE,
+        'size' => 'big',
+        'serialize' => TRUE,
+      ),
+      'dataset' => array(
+        'description' => 'dataset',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+        'default' => '',
+      ),
+    ),
+    'primary key' => array('srid'),
+  );
+  return $schema;
+}
+
+/**
+ * Change column name from endpoint to uri.
+ */
+function sparql_registry_update_7200() {
+  $schema = array(
+    'description' => 'The URI of this endpoint.',
+    'type' => 'varchar',
+    'length' => 255,
+    'not null' => TRUE,
+    'default' => '',
+  );
+  db_change_field('sparql_registry', 'endpoint', 'uri', $schema);
+}
+
+/**
+ * Add columns to SPARQL Registry database table.
+ */
+function sparql_registry_update_7201() {
+  $schema = array(
+    'description' => 'Additional query options.',
+    'type' => 'blob',
+    'not null' => FALSE,
+    'size' => 'big',
+    'serialize' => TRUE,
+  );
+  db_add_field('sparql_registry', 'options', $schema);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql/sparql_registry/sparql_registry.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,447 @@
+<?php
+
+/**
+ * Implements hook_permission().
+ */
+function sparql_registry_permission() {
+  $perms = array(
+    'administer sparql registry' => array(
+      'title' => t('Administer SPARQL endpoints registry'),
+    ),
+  );
+
+  return $perms;
+}
+
+/**
+ * Implements hook_menu().
+ */
+function sparql_registry_menu() {
+  $items['sparql_registry/%sparql_registry'] = array(
+    'title' => 'SPARQL Endpoint',
+    'title callback' => 'sparql_registry_page_title',
+    'title arguments' => array(1),
+    'page callback' => 'sparql_registry_page',
+    'page arguments' => array(1),
+    'access arguments' => array('administer sparql registry'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['sparql_registry/%sparql_registry/edit'] = array(
+    'title' => 'Edit',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('sparql_registry_form_edit', 1),
+    'access arguments' => array('administer sparql registry'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 10,
+  );
+
+  $items['sparql_registry/%sparql_registry/delete'] = array(
+    'title' => 'Delete',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('sparql_registry_delete_confirm', 1),
+    'access arguments' => array('administer sparql registry'),
+    'weight' => 10,
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['admin/structure/sparql_registry'] = array(
+    'title' => 'SPARQL Endpoints Registry',
+    'description' => 'Manage sparql endpoint entities.',
+    'access arguments' => array('administer sparql registry'),
+    'page callback' => 'sparql_registry_page_admin',
+    'page arguments' => array('list'),
+  );
+
+  $items['admin/structure/sparql_registry/list'] = array(
+    'title' => 'List',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+  );
+
+  $items['admin/structure/sparql_registry/create'] = array(
+    'title' => 'Add SPARQL endpoint',
+    'page arguments' => array('create'),
+    'access arguments' => array('administer sparql registry'),
+    'type' => MENU_LOCAL_ACTION,
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function sparql_registry_entity_info() {
+  $return = array(
+    'sparql_registry' => array(
+      'label' => t('SPARQL Endpoints Registry'),
+      'base table' => 'sparql_registry',
+      'uri callback' => 'sparql_registry_uri',
+      'fieldable' => FALSE,
+      'entity keys' => array(
+        'id' => 'srid',
+      ),
+      'bundles' => array(
+        'sparql_registry' => array(
+          'label' => t('SPARQL Endpoints Registry Item'),
+          'admin' => array(
+            'path' => 'admin/structure/sparql_registry',
+          ),
+        ),
+      ),
+    ),
+  );
+  return $return;
+}
+
+/**
+ * Entity uri callback.
+ */
+function sparql_registry_uri($sparql_registry) {
+  return array(
+    'path' => 'sparql_registry/' . $sparql_registry->srid,
+  );
+}
+
+/**
+ * Implements hook_admin_paths().
+ */
+function sparql_registry_admin_paths() {
+  $paths = array(
+    'sparql_registry/*/edit' => TRUE,
+    'sparql_registry/*/delete' => TRUE,
+  );
+  return $paths;
+}
+
+function sparql_registry_load($srid, $reset = FALSE) {
+  $sparql_registries = sparql_registry_load_multiple(array($srid), array(), $reset);
+  $sparql_registry = reset($sparql_registries);
+  return $sparql_registry;
+}
+
+function sparql_registry_load_by_uri($uri, $reset = FALSE) {
+  $srid = NULL;
+  $sparql_registry = NULL;
+
+  $query = new EntityFieldQuery();
+  $query
+    ->entityCondition('entity_type', 'sparql_registry', '=')
+    ->propertyCondition('uri', $uri, '=');
+  $result = $query->execute();
+
+  if (!empty($result)) {
+    // The endpoint is in a double nested array. Use reset to pull it out.
+    $endpoint = reset(reset($result));
+    $srid = $endpoint->srid;
+    $sparql_registry = sparql_registry_load_multiple(array($srid), array(), $reset);
+    return reset($sparql_registry);
+  }
+
+  return NULL;
+}
+
+function sparql_registry_load_multiple($srids = FALSE, $conditions = array(), $reset = FALSE) {
+  $sparql_registries = entity_load('sparql_registry', $srids, $conditions, $reset);
+  // Unserialize the options array.
+  foreach ($sparql_registries as $sparql_registry) {
+    if (!is_array($sparql_registry->options)) {
+      $sparql_registry->options = unserialize($sparql_registry->options);
+    }
+  }
+  return entity_load('sparql_registry', $srids, $conditions, $reset);
+}
+
+function sparql_registry_delete($srid) {
+  sparql_registry_delete_multiple(array($srid));
+}
+
+function sparql_registry_delete_multiple($srids) {
+  if (!empty($srids)) {
+    db_delete('sparql_registry')
+     ->condition('srid', $srids, 'IN')
+     ->execute();
+
+    entity_get_controller('sparql_registry')->resetCache();
+  }
+}
+
+function sparql_registry_page_title($sparql_registry) {
+  return check_plain($sparql_registry->title);
+}
+
+/**
+ * Save the SPARQL registry form values to the database.
+ */
+function sparql_registry_save(&$edit) {
+  // If there is an existing endpoint record, update the record. Otherwise,
+  // insert a new endpoint record.
+  if (!empty($edit->srid)) {
+    drupal_write_record('sparql_registry', $edit, 'srid');
+    module_invoke_all('entity_update', 'sparql_registry', $edit);
+  }
+  else {
+    drupal_write_record('sparql_registry', $edit);
+    module_invoke_all('entity_insert', 'sparql_registry', $edit);
+  }
+
+  return $edit;
+}
+
+function sparql_registry_page_admin($tab = '') {
+  switch ($tab) {
+    case 'create':
+      $build['sparql_registry_create'] = drupal_get_form('sparql_registry_form_edit');
+      break;
+    default:
+      $build['sparql_registry_list'] = drupal_get_form('sparql_registry_form_list');
+  }
+  return $build;
+}
+
+function sparql_registry_form_list() {
+  $header = array(
+    'title' => array('data' => t('Title'), 'field' => 'sr.title'),
+    'uri' => array('data' => t('Endpoint URI'), 'field' => 'uri'),
+    'dataset' => array('data' => t('Dataset'), 'field' => 'dataset'),
+    'edit' => array('data' => t('Edit')),
+    'delete' => array('data' => t('Delete')),
+  );
+  $query = db_select('sparql_registry', 'sr');
+  $count_query = clone $query;
+  $count_query->addExpression('COUNT(sr.srid)');
+
+  $query = $query->extend('PagerDefault')->extend('TableSort');
+  $query
+    ->fields('sr', array('srid', 'title', 'uri', 'dataset'))
+    ->limit(20)
+    ->orderByHeader($header)
+    ->setCountQuery($count_query);
+  $result = $query->execute();
+
+  $destination = drupal_get_destination();
+
+  $options = array();
+  foreach ($result as $row) {
+    $options[$row->srid] = array(
+      'title' => $row->title,
+      'uri' => $row->uri,
+      'dataset' => $row->dataset,
+      'edit' => array('data' => array(
+        '#type' => 'link',
+        '#title' => t('edit'),
+        '#href' => "sparql_registry/$row->srid/edit",
+        '#options' => array('query' => $destination),
+      )),
+      'delete' => array('data' => array(
+        '#type' => 'link',
+        '#title' => t('delete'),
+        '#href' => "sparql_registry/$row->srid/delete",
+        '#options' => array('query' => $destination),
+      )),
+    );
+  }
+
+  $form['sparql_registry'] = array(
+    '#type' => 'tableselect',
+    '#header' => $header,
+    '#options' => $options,
+    '#empty' => t('No entities available.'),
+  );
+  $form['pager']['#markup'] = theme('pager');
+
+  return $form;
+}
+
+function sparql_registry_form_edit($form, &$form_state, $edit = NULL) {
+  if (!isset($edit)) {
+    $edit = (object) array(
+      'title' => '',
+      'uri' => '',
+      'dataset' => '',
+      'options' => array(
+        'query_parameters' => array(),
+      ),
+    );
+  }
+
+  // Because we have many fields with the same keys, we have to set #tree to
+  // access them.
+  $form['#tree'] = TRUE;
+  $form['title'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Title'),
+    '#default_value' => $edit->title,
+    '#required' => TRUE,
+  );
+  $form['uri'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Endpoint URI'),
+    '#description' => t('The URL used to access the endpoint. For example, !dbpedia.', array('!dbpedia' => 'http://dbpedia.org/sparql')),
+    '#default_value' => $edit->uri,
+    '#required' => TRUE,
+  );
+  $form['dataset'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Dataset'),
+    '#default_value' => $edit->dataset,
+    '#required' => FALSE,
+  );
+
+  $form['options'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Advanced query options'),
+  );
+  $form['options']['query_parameters'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Query parameters'),
+    // Set up the wrapper so that AJAX will be able to replace the fieldset.
+    '#prefix' => '<div id="options-fieldset-wrapper">',
+    '#suffix' => '</div>',
+  );
+
+  // Build the fieldset with the proper number of query parameter fields.
+  if (!isset($form_state['num_query_parameters'])) {
+    if (count($edit->options['query_parameters']) > 0) {
+      $form_state['num_query_parameters'] = count($edit->options['query_parameters']);
+    }
+    else {
+      $form_state['num_query_parameters'] = 1;
+    }
+    $parameters = isset($edit->options['query_parameters']) ? $edit->options['query_parameters'] : array();
+  }
+
+  for ($i = 0; $i < $form_state['num_query_parameters']; $i++) {
+    $key = key($parameters);
+    $value = array_shift($parameters);
+
+    $form['options']['query_parameters'][$i]['key'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Key'),
+      '#default_value' => $key,
+    );
+    $form['options']['query_parameters'][$i]['value'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Value'),
+      '#default_value' => $value,
+    );
+  }
+  $form['options']['add_name'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add one more'),
+    '#submit' => array('sparql_registry_add_more_add_one'),
+    // See the examples in ajax_example.module for more details on the
+    // properties of #ajax.
+    '#ajax' => array(
+      'callback' => 'sparql_registry_add_more_callback',
+      'wrapper' => 'options-fieldset-wrapper',
+    ),
+    '#limit_validation_errors' => array(),
+  );
+  if ($form_state['num_query_parameters'] > 1) {
+    $form['options']['remove_name'] = array(
+      '#type' => 'submit',
+      '#value' => t('Remove one'),
+      '#submit' => array('sparql_registry_add_more_remove_one'),
+      '#ajax' => array(
+        'callback' => 'sparql_registry_add_more_callback',
+        'wrapper' => 'options-fieldset-wrapper',
+      ),
+      '#limit_validation_errors' => array(),
+    );
+  }
+
+  // Store ID if any.
+  if (!empty($edit->srid)) {
+    $form['srid'] = array(
+      '#type' => 'value',
+      '#value' => $edit->srid,
+    );
+  }
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save'),
+    '#weight' => 5,
+  );
+
+  return $form;
+}
+
+/**
+ * Callback for both ajax-enabled buttons.
+ *
+ * This simply selects and returns the fieldset with the names in it.
+ */
+function sparql_registry_add_more_callback($form, $form_state) {
+  return $form['options']['query_parameters'];
+}
+
+/**
+ * Submit handler for the "add-one-more" button.
+ *
+ * It just increments the max counter and causes a rebuild.
+ */
+function sparql_registry_add_more_add_one($form, &$form_state) {
+  $form_state['num_query_parameters']++;
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Submit handler for the "remove one" button.
+ *
+ * Decrements the max counter and causes a form rebuild.
+ */
+function sparql_registry_add_more_remove_one($form, &$form_state) {
+  if ($form_state['num_query_parameters'] > 1) {
+    $form_state['num_query_parameters']--;
+  }
+  $form_state['rebuild'] = TRUE;
+}
+
+function sparql_registry_form_edit_validate($form, &$form_state) {
+  // Check if endpoint has a valid url.
+  if (!valid_url($form_state['values']['uri'], TRUE)) {
+    form_set_error('uri', 'Endpoint URI value is not a valid URI.');
+  }
+}
+
+function sparql_registry_form_edit_submit($form, &$form_state) {
+  $values = $form_state['values'];
+
+  // Take the parameters array structure from the form and restructure it to be
+  // easier to use in the API.
+  $parameters = array();
+  foreach ($values['options']['query_parameters'] as $parameter) {
+    $parameters[$parameter['key']] = $parameter['value'];
+  }
+  $values['options']['query_parameters'] = $parameters;
+
+  // Create an object to pass to drupal_write_record().
+  $edit = (object) $values;
+
+  // Save own data.
+  sparql_registry_save($edit);
+  $form_state['redirect'] = "admin/structure/sparql_registry";
+}
+
+function sparql_registry_delete_confirm($form, &$form_state, $sparql_registry) {
+  $form['#sparql_registry'] = $sparql_registry;
+  $form['srid'] = array('#type' => 'value', '#value' => $sparql_registry->srid);
+  return confirm_form($form,
+    t('Are you sure you want to delete %title?', array('%title' => $sparql_registry->title)),
+    'sparql_registry/' . $sparql_registry->srid,
+    t('This action cannot be undone.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+function sparql_registry_delete_confirm_submit($form, &$form_state) {
+  if ($form_state['values']['confirm']) {
+    $sparql_registry = sparql_registry_load($form_state['values']['srid']);
+    sparql_registry_delete($form_state['values']['srid']);
+    watchdog('sparql_registry', 'deleted %title.', array('%title' => $sparql_registry->title));
+    drupal_set_message(t('%title has been deleted.', array('%title' => $sparql_registry->title)));
+  }
+
+  $form_state['redirect'] = "admin/structure/sparql_registry";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/CHANGELOG.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,20 @@
+This log does not contain all changes. Instead, it only logs the changes that
+affect how views created with earlier versions of the module work and which may
+require action by the user.
+
+For a full list of changes, refer to the commit log at
+http://drupal.org/node/817148/commits
+
+SPARQL Views 7.x-2.x-dev
+------------------------
+- #1234558: Use endpoint_uri instead of srid to connect resource types to endpoints.
+- #1120682: Ensure that relation handling is predictable and robust.
+
+SPARQL Views 7.x-2.x-alpha4
+---------------------------
+- #1206420: Added DISTINCT option, turned on by default.
+
+SPARQL Views 7.x-2.x
+--------------------
+- Changed query building from direct query input to entity/field based input.
+- Removed SPARQL Views UI query builder
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,274 @@
+GNU GENERAL PUBLIC LICENSE
+
+              Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave,
+Cambridge, MA 02139, USA. Everyone is permitted to copy and distribute
+verbatim copies of this license document, but changing it is not allowed.
+
+                  Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users. This General Public License
+applies to most of the Free Software Foundation's software and to any other
+program whose authors commit to using it. (Some other Free Software
+Foundation software is covered by the GNU Library General Public License
+instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the
+freedom to distribute copies of free software (and charge for this service if
+you wish), that you receive source code or can get it if you want it, that you
+can change the software or use pieces of it in new free programs; and that
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to
+deny you these rights or to ask you to surrender the rights. These restrictions
+translate to certain responsibilities for you if you distribute copies of the
+software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or for
+a fee, you must give the recipients all the rights that you have. You must make
+sure that they, too, receive or can get the source code. And you must show
+them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and (2)
+offer you this license which gives you legal permission to copy, distribute
+and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain that
+everyone understands that there is no warranty for this free software. If the
+software is modified by someone else and passed on, we want its recipients
+to know that what they have is not the original, so that any problems
+introduced by others will not reflect on the original authors' reputations.
+
+Finally, any free program is threatened constantly by software patents. We
+wish to avoid the danger that redistributors of a free program will individually
+obtain patent licenses, in effect making the program proprietary. To prevent
+this, we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and modification
+follow.
+
+           GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND
+               MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+placed by the copyright holder saying it may be distributed under the terms
+of this General Public License. The "Program", below, refers to any such
+program or work, and a "work based on the Program" means either the
+Program or any derivative work under copyright law: that is to say, a work
+containing the Program or a portion of it, either verbatim or with
+modifications and/or translated into another language. (Hereinafter, translation
+is included without limitation in the term "modification".) Each licensee is
+addressed as "you".
+
+Activities other than copying, distribution and modification are not covered
+by this License; they are outside its scope. The act of running the Program is
+not restricted, and the output from the Program is covered only if its contents
+constitute a work based on the Program (independent of having been made
+by running the Program). Whether that is true depends on what the Program
+does.
+
+1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that refer to this License
+and to the absence of any warranty; and give any other recipients of the
+Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and you
+may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of it,
+thus forming a work based on the Program, and copy and distribute such
+modifications or work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+a) You must cause the modified files to carry prominent notices stating that
+you changed the files and the date of any change.
+
+b) You must cause any work that you distribute or publish, that in whole or in
+part contains or is derived from the Program or any part thereof, to be
+licensed as a whole at no charge to all third parties under the terms of this
+License.
+
+c) If the modified program normally reads commands interactively when run,
+you must cause it, when started running for such interactive use in the most
+ordinary way, to print or display an announcement including an appropriate
+copyright notice and a notice that there is no warranty (or else, saying that
+you provide a warranty) and that users may redistribute the program under
+these conditions, and telling the user how to view a copy of this License.
+(Exception: if the Program itself is interactive but does not normally print such
+an announcement, your work based on the Program is not required to print
+an announcement.)
+
+These requirements apply to the modified work as a whole. If identifiable
+sections of that work are not derived from the Program, and can be
+reasonably considered independent and separate works in themselves, then
+this License, and its terms, do not apply to those sections when you distribute
+them as separate works. But when you distribute the same sections as part
+of a whole which is a work based on the Program, the distribution of the
+whole must be on the terms of this License, whose permissions for other
+licensees extend to the entire whole, and thus to each and every part
+regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest your rights to
+work written entirely by you; rather, the intent is to exercise the right to
+control the distribution of derivative or collective works based on the
+Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of a
+storage or distribution medium does not bring the other work under the scope
+of this License.
+
+3. You may copy and distribute the Program (or a work based on it, under
+Section 2) in object code or executable form under the terms of Sections 1
+and 2 above provided that you also do one of the following:
+
+a) Accompany it with the complete corresponding machine-readable source
+code, which must be distributed under the terms of Sections 1 and 2 above
+on a medium customarily used for software interchange; or,
+
+b) Accompany it with a written offer, valid for at least three years, to give
+any third party, for a charge no more than your cost of physically performing
+source distribution, a complete machine-readable copy of the corresponding
+source code, to be distributed under the terms of Sections 1 and 2 above on
+a medium customarily used for software interchange; or,
+
+c) Accompany it with the information you received as to the offer to distribute
+corresponding source code. (This alternative is allowed only for
+noncommercial distribution and only if you received the program in object
+code or executable form with such an offer, in accord with Subsection b
+above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source code
+means all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation and
+installation of the executable. However, as a special exception, the source
+code distributed need not include anything that is normally distributed (in
+either source or binary form) with the major components (compiler, kernel,
+and so on) of the operating system on which the executable runs, unless that
+component itself accompanies the executable.
+
+If distribution of executable or object code is made by offering access to
+copy from a designated place, then offering equivalent access to copy the
+source code from the same place counts as distribution of the source code,
+even though third parties are not compelled to copy the source along with the
+object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+expressly provided under this License. Any attempt otherwise to copy,
+modify, sublicense or distribute the Program is void, and will automatically
+terminate your rights under this License. However, parties who have received
+copies, or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+5. You are not required to accept this License, since you have not signed it.
+However, nothing else grants you permission to modify or distribute the
+Program or its derivative works. These actions are prohibited by law if you
+do not accept this License. Therefore, by modifying or distributing the
+Program (or any work based on the Program), you indicate your acceptance
+of this License to do so, and all its terms and conditions for copying,
+distributing or modifying the Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the original
+licensor to copy, distribute or modify the Program subject to these terms and
+conditions. You may not impose any further restrictions on the recipients'
+exercise of the rights granted herein. You are not responsible for enforcing
+compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues), conditions
+are imposed on you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not excuse you from the
+conditions of this License. If you cannot distribute so as to satisfy
+simultaneously your obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute the Program at all.
+For example, if a patent license would not permit royalty-free redistribution
+of the Program by all those who receive copies directly or indirectly through
+you, then the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and
+the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any patents or
+other property right claims or to contest validity of any such claims; this
+section has the sole purpose of protecting the integrity of the free software
+distribution system, which is implemented by public license practices. Many
+people have made generous contributions to the wide range of software
+distributed through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing to
+distribute software through any other system and a licensee cannot impose
+that choice.
+
+This section is intended to make thoroughly clear what is believed to be a
+consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in certain
+countries either by patents or by copyrighted interfaces, the original copyright
+holder who places the Program under this License may add an explicit
+geographical distribution limitation excluding those countries, so that
+distribution is permitted only in or among countries not thus excluded. In such
+case, this License incorporates the limitation as if written in the body of this
+License.
+
+9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will be
+similar in spirit to the present version, but may differ in detail to address new
+problems or concerns.
+
+Each version is given a distinguishing version number. If the Program specifies
+a version number of this License which applies to it and "any later version",
+you have the option of following the terms and conditions either of that
+version or of any later version published by the Free Software Foundation. If
+the Program does not specify a version number of this License, you may
+choose any version ever published by the Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free programs
+whose distribution conditions are different, write to the author to ask for
+permission. For software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we sometimes make
+exceptions for this. Our decision will be guided by the two goals of
+preserving the free status of all derivatives of our free software and of
+promoting the sharing and reuse of software generally.
+
+               NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
+PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE
+STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
+AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR
+ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
+LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL,
+SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE
+PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA
+OR DATA BEING RENDERED INACCURATE OR LOSSES
+SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
+PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN
+IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES.
+
+          END OF TERMS AND CONDITIONS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/README.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,52 @@
+SPARQL Views module
+-------------------
+By Lin Clark, lin-clark.com
+
+This module adds:
+-  A query plugin for Views to query remote SPARQL endpoints, RDF files, and
+   RDFa on Web pages.
+-  An entity type, sparql_views_entity, that is used to maintain an internal
+   representation of the resource/predicate relationship. Bundles of this entity
+   can be created either in code or through Field UI and provide the fields for
+   manipulation with Views. The RDF mapping for the fields in the bundle is what
+   is used to construct the query.
+  
+INSTRUCTIONS
+------------
+1. Enable sparql_views, views_ui, and rdfui.
+2. Register an endpoint at admin/structure/sparql_registry.
+   Example: DBpedia, http://dbpedia.org/sparql
+3. Create namespace prefix mappings for any vocabulary terms you will be using
+   at admin/config/services/rdf/namespaces.
+   Example: dbpprop:name uses a mapping between the 'dbpprop' prefix and the
+   URI 'http://dbpedia.org/property/'.
+4. Create a SPARQL Views resource and indicate which endpoints it is available
+   in at admin/structure/sparql-views.
+   Example: Person, available in DBpedia.
+5. Add fields to the resource and give those fields RDF mappings.
+   Example: Name field with an RDF mapping of dbpprop:name.
+6. Add a new view at admin/structure/views/add, selecting the endpoint's
+   SPARQL Views view type in the drop down. Continue & edit.
+7. Add fields, filters, etc.
+
+SUGGESTED VIEWS CONFIGURATION
+-----------------------------
+In the Settings tab:
+-  Uncheck 'Automatically update preview on changes'
+-  Check 'Show the SQL Query'
+
+HONOR ROLL
+----------
+Thank you to:
+-  Remon Georgy (http://drupal.org/user/143827) for the idea to use an internal
+   representation of the remote resources.
+-  StŽphane 'scor' Corlosquet (http://drupal.org/user/52142) for user testing,
+   documentation, and patches.
+-  Matthias 'netsensei' Vandermaesen (http://drupal.org/user/350460) for patches
+   to the original SPARQL Views and brainstorming.
+-  Laura 'laura s' Scott (http://drupal.org/user/18973) for UI help on the
+   Drupal 6 version.
+-  Mark Birbeck (http://drupal.org/user/101283) for testing and bug reporting.
+-  Google Summer of Code and Drupal's GSOC organizing team for initial support.
+-  Everyone who contributed ideas and suggestions in the issue queue and at
+   Drupal events.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_argument.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,93 @@
+<?php
+/**
+ * SPARQL Views arguments.
+ *
+ * The argument enables re-writing the argument. For instance, if someone goes
+ * to http://example.org/Pittsburgh, this argument could be rewritten to
+ * http://dbpedia.org/resource/Pittsburgh.
+ */
+class sparql_views_handler_argument extends views_handler_argument {
+  // We will use the value type and language form elements for getting
+  // necessary info about replacements that this argument makes.
+  var $selected_sparql_options = array('value_type', 'language');
+
+  /**
+   * Set the options variables.
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['sparql_options']['code'] = array('default' => '');
+    $options = _sparql_views_attach_form_options($options, $this->selected_sparql_options);
+
+    return $options;
+  }
+
+  /**
+   * Provide the form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // Attach the SPARQL specific form elements.
+    $form = _sparql_views_attach_form_elements($form, $this->options, $this->selected_sparql_options);
+
+    $form['sparql_options']['code'] = array(
+      '#type' => 'textarea',
+      '#title' => t('PHP argument rewrite code'),
+      '#default_value' => $this->options['sparql_options']['code'],
+      '#description' => t('Enter PHP code that returns a value to use for this filter. Do not use &lt;?php ?&gt;. You must return only a single value for just this filter. You can use $this->argument in your return. For example, return "http://dbpedia.org/resource/" . $this->argument.'),
+    );
+
+    $this->check_access($form, 'code');
+  }
+
+  /**
+   * If we don't have access to the form but are showing it anyway, ensure that
+   * the form is safe and cannot be changed from user input.
+   */
+  function check_access(&$form, $option_name) {
+    if (!user_access('use PHP for settings')) {
+      $form['sparql_options'][$option_name]['#disabled'] = TRUE;
+      $form['sparql_options'][$option_name]['#value'] = $form[$this->option_name]['#default_value'];
+      $form['sparql_options'][$option_name]['#description'] .= ' <strong>' . t('Note: you do not have permission to modify this. If you change the default argument type, this setting will be lost and you will NOT be able to get it back.') . '</strong>';
+    }
+  }
+
+  /**
+   * Set up the query for this argument.
+   *
+   * The argument sent may be found at $this->argument.
+   */
+  function query() {
+    ob_start();
+    $return = eval($this->options['sparql_options']['code']);
+    ob_end_clean();
+
+    $replacement = !empty($return) ? $return : $this->argument;
+    $relationship = $this->options['relationship'];
+
+    if ($relationship == 'none') {
+      $subject = $this->definition['subject'];
+    }
+    else {
+      $subject = $relationship;
+    }
+    $predicate = $this->definition['rdf_mapping'][0];
+
+    if (!empty($replacement)) {
+      $value_type = $this->options['sparql_options']['value_type'];
+      $language = $this->options['sparql_options']['language'];
+
+      if ($value_type != 'number') {
+        $object = $this->query->format_replacement($replacement, $value_type, $language);
+      }
+      else {
+        $var = '?var' . rand();
+        $this->query->add_filter('=', array($var, $replacement));
+        $object = $var;
+      }
+
+      $this->query->add_triple($subject, $predicate, $object);
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,270 @@
+<?php
+/**
+ * Helper function: Return an array of formatter options for a field type.
+ *
+ * Borrowed from field_ui.
+ */
+function _sparql_views_field_formatter_options($field_type = NULL) {
+  $options = &drupal_static(__FUNCTION__);
+
+  if (!isset($options)) {
+    $field_types = field_info_field_types();
+    $options = array();
+    foreach (field_info_formatter_types() as $name => $formatter) {
+      foreach ($formatter['field types'] as $formatter_field_type) {
+        // Check that the field type exists.
+        if (isset($field_types[$formatter_field_type])) {
+          $options[$formatter_field_type][$name] = $formatter['label'];
+        }
+      }
+    }
+  }
+
+  if ($field_type) {
+    return !empty($options[$field_type]) ? $options[$field_type] : array();
+  }
+  return $options;
+}
+
+/**
+ * Base field handler that has no options and renders an unformatted field.
+ *
+ * Definition terms:
+ * - additional fields: An array of fields that should be added to the query
+ *                      for some purpose. The array is in the form of:
+ *                      array('identifier' => array('table' => tablename,
+ *                      'field' => fieldname); as many fields as are necessary
+ *                      may be in this array.
+ * - click sortable: If TRUE, this field may be click sorted.
+ */
+class sparql_views_handler_field extends views_handler_field {
+  function option_definition() {
+    $options = parent::option_definition();
+
+    if (!empty($this->definition['field_info'])) {
+      // Set the field formatter based on the field definition. This would have
+      // been set either by a user through the Field UI or in a module's code
+      // definition of a bundle.
+      $field = $this->definition['field_info'];
+      $field_type = field_info_field_types($field['type']);
+      $options['type'] = array(
+        'default' => $field_type['default_formatter'],
+      );
+    }
+    else {
+      // Some fields, such as subject URI fields, are not full fledged Field
+      // API fields. Give them a default text handler.
+      // @todo Should non-field API fields just not have this handler as a parent?
+      $options['type'] = array(
+        'default' => 'text_default',
+      );
+    }
+    $options['required'] = array(
+      'default' => TRUE,
+    );
+    $options['settings'] = array(
+      'default' => array(),
+    );
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    // If this is not a Field API field, there are no formatting options.
+    // @todo Should non-field API fields just not have this handler as a parent?
+    if (empty($this->definition['field_info'])) {
+      return;
+    }
+
+    $field = $this->definition['field_info'];
+    $formatters = _sparql_views_field_formatter_options($field['type']);
+
+    $form['required'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Require a value for this field (not OPTIONAL).'),
+      '#default_value' => $this->options['required'],
+      '#ajax' => array(
+        'path' => views_ui_build_form_url($form_state),
+      ),
+    );
+
+    $form['type'] = array(
+      '#type' => 'select',
+      '#title' => t('Formatter'),
+      '#options' => $formatters,
+      '#default_value' => $this->options['type'],
+      '#ajax' => array(
+        'path' => views_ui_build_form_url($form_state),
+      ),
+    );
+
+    // Get the currently selected formatter.
+    if (isset($form_state['values']['options']['type'])) {
+      $format = $form_state['values']['options']['type'];
+    }
+    else {
+      $format = $this->options['type'];
+    }
+    $formatter = field_info_formatter_types($format);
+    $settings = $this->options['settings'] + field_info_formatter_settings($format);
+
+    // Provide an instance array for hook_field_formatter_settings_form().
+    ctools_include('fields');
+    $instance = ctools_fields_fake_field_instance($this->definition['field_info']['field_name'], '_dummy', $formatter, $settings);
+
+    // Store the settings in a '_dummy' view mode.
+    $instance['display']['_dummy'] = array(
+      'type' => $format,
+      'settings' => $settings,
+    );
+
+    // Get the settings form.
+    $settings_form = array('#value' => array());
+    $function = $formatter['module'] . '_field_formatter_settings_form';
+    if (function_exists($function)) {
+      $settings_form = $function($field, $instance, '_dummy', $form, $form_state);
+    }
+
+    $form['settings'] = $settings_form;
+  }
+
+  /**
+   * Called to add the field to a query.
+   */
+  function query() {
+    $object = $this->real_field;
+    $relationship = $this->options['relationship'];
+    $optional = empty($this->options['required']);
+    if ($relationship == 'none') {
+      $subject = $this->definition['subject'];
+    }
+    else {
+      $subject = $relationship;
+    }
+    $predicate = $this->definition['rdf_mapping'][0];
+    $this->field_alias = $this->query->add_triple($subject, $predicate, '?' . $object, array('#select' => TRUE, '#optional' => $optional));
+  }
+
+  function click_sort($order) {
+    $this->query->add_orderby($this->field_alias, $order);
+  }
+
+  /**
+   * This kind of construct makes it relatively easy for a child class
+   * to add or remove functionality by overriding this function and
+   * adding/removing items from this array.
+   */
+  function formatters() {
+    $formatters = &drupal_static(__FUNCTION__);
+
+    if (!isset($options)) {
+      $formatters = array(
+        'list_default' => array(
+          'method' => 'render_field_formatter',
+        ),
+        'list_key' => array(
+          'method' => 'render_field_formatter',
+        ),
+        'number_integer' => array(
+          'method' => 'render_field_formatter',
+        ),
+        'number_decimal' => array(
+          'method' => 'render_field_formatter',
+        ),
+        'number_unformatted' => array(
+          'method' => 'render_field_formatter',
+        ),
+        'text_default' => array(
+          'method' => 'render_field_formatter',
+        ),
+        'text_trimmed' => array(
+          'method' => 'render_field_formatter',
+        ),
+        'text_summary_or_trimmed' => array(
+          'method' => 'render_field_formatter',
+        ),
+        'text_plain' => array(
+          'method' => 'render_field_formatter',
+        ),
+        // Special handling required.
+        'image' => array(
+          'method' => 'image',
+        ),
+      );
+    }
+    return $formatters;
+  }
+
+  /**
+   * Load the entities for all fields that are about to be displayed.
+   */
+  function pre_render(&$values) {
+    // @todo Combine subjects.
+  }
+
+  function render($values) {
+    $output = '';
+    if (is_array($values)) {
+      $items = array();
+      foreach ($values[$this->real_field] as $value) {
+        $val = (object) array($this->field_alias => $value);
+        $items[] = $this->render_value($val);
+      }
+      if (count($items) > 1) {
+        //$output = theme('item_list', array('items' => $items, 'type' => 'ul'));
+        foreach ($items as $item) {
+          $output .= "<div>$item</div>";
+        }
+      }
+      else {
+        $output = $items[0];
+      }
+    }
+    else {
+      $output .= $this->render_value($values);
+    }
+    return $output;
+  }
+
+  function render_value($val) {
+    $formatter = $this->options['type'];
+    $formatters = $this->formatters();
+    if (!empty($formatters[$formatter]['method'])) {
+      return $this->{$formatters[$formatter]['method']}($val, $formatter);
+    }
+    else {
+      vsm("Missing formatter: $formatter");
+      return parent::render($val);
+    }
+  }
+
+  function render_field_formatter($values, $formatter) {
+    $field_name = $this->definition['field_name'];
+    $field = field_info_field($field_name);
+    $value = isset($values->{$this->field_alias}) ? $values->{$this->field_alias} : $this->options['empty'];
+
+    $items[] = array('value' => $value);
+    $instances = field_info_instances('sparql_views_resource', $this->definition['bundle']);
+    $display['type'] = $formatter;
+    $display['settings'] = $this->options['settings'];
+    $formatter_function = $field['module'] . '_field_formatter_view';
+    return render($formatter_function(NULL, NULL, NULL, $instances[$field_name], NULL, $items, $display));
+  }
+
+  function image($values) {
+    $item['path'] = $values->{$this->real_field};
+    $image_style = $this->options['settings']['image_style'];
+    $image_styles = image_styles();
+    if (isset($image_styles[$image_style]['effects'])) {
+      foreach ($image_styles[$image_style]['effects'] as $effect) {
+        if ($effect['name'] == 'image_scale') {
+          $item['width'] = $effect['data']['width'];
+        }
+      }
+    }
+    $output = theme('image', $item);
+    return filter_xss($output, array('img', 'a'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_field_rdftype.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Handler for a subject.
+ */
+class sparql_views_handler_field_rdftype extends sparql_views_handler_field {
+  function render_field_formatter($values, $formatter) {
+    $items[] = array('value' => $values->{$this->real_field});
+    $display['type'] = 'text_plain';
+    return render(text_field_formatter_view(NULL, NULL, NULL, NULL, NULL, $items, $display));
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_field_subject.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Handler for a subject.
+ */
+class sparql_views_handler_field_subject extends sparql_views_handler_field {
+  /**
+  * Called to add the field to a query.
+  */
+  function query() {
+    $this->field_alias = $this->real_field;
+    $this->query->select_fields[] = $this->real_field;
+  }
+
+  function render_field_formatter($values, $formatter) {
+    $items[] = array('value' => $values->{$this->real_field});
+    $display['type'] = 'text_plain';
+    return render(text_field_formatter_view(NULL, NULL, NULL, NULL, NULL, $items, $display));
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_filter.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,125 @@
+<?php
+/**
+ * @file
+ * Views filter handler to display UI for WHERE clauses and prepare them for
+ * the query.
+ */
+
+class sparql_views_handler_filter extends views_handler_filter_string{
+  // We will use the value type and language form elements for getting
+  // necessary info about replacements that this filter makes.
+  var $selected_sparql_options = array('value_type', 'language');
+
+  function option_definition() {
+    $options = parent::option_definition();
+    // Attach the SPARQL specific options.
+    $options = _sparql_views_attach_form_options($options, $this->selected_sparql_options);
+
+    return $options;
+  }
+  
+  /**
+   * This kind of construct makes it relatively easy for a child class
+   * to add or remove functionality by overriding this function and
+   * adding/removing items from this array.
+   */
+  function operators() {
+    $operators = array(
+      '=' => array(
+        'title' => t('Is equal to'),
+        'short' => t('='),
+        'method' => 'op_equal',
+        'values' => 1,
+      ),
+    );
+    return $operators;
+  }
+
+  function admin_summary() {
+    $output = $this->operator . ' ';
+    $output .= check_plain($this->options['value']);
+    $output .= "<i>({$this->options['sparql_options']['value_type']})</i>";
+    return $output;
+  }
+  
+  function value_form(&$form, &$form_state) {
+    // We have to make some choices when creating this as an exposed
+    // filter form. For example, if the operator is locked and thus
+    // not rendered, we can't render dependencies; instead we only
+    // render the form items we need.
+    $which = 'all';
+    if (!empty($form['operator'])) {
+      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+    }
+    if (!empty($form_state['exposed'])) {
+      $identifier = $this->options['expose']['identifier'];
+
+      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+        // exposed and locked.
+        $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+      }
+      else {
+        $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+      }
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $form['value'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Value'),
+        '#size' => 60,
+        '#default_value' => $this->value,
+      );
+      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+        $form_state['input'][$identifier] = $this->value;
+      }
+
+      if ($which == 'all') {
+        $form['value'] += array(
+          '#process' => array('ctools_dependent_process'),
+          '#dependency' => array($source => $this->operator_values(1)),
+        );
+      }
+    }
+
+    if (!isset($form['value'])) {
+      // Ensure there is something in the 'value'.
+      $form['value'] = array(
+        '#type' => 'value',
+        '#value' => NULL
+      );
+    }
+    // Attach the SPARQL specific form elements.
+    $form = _sparql_views_attach_form_elements($form, $this->options, $this->selected_sparql_options);
+  }
+
+  function query() {
+    $info = $this->operators();
+    if (!empty($info[$this->operator]['method'])) {
+      $this->{$info[$this->operator]['method']}();
+    }
+  }
+  
+  function op_equal() {
+    $value_type = $this->options['sparql_options']['value_type'];
+    $language = $this->options['sparql_options']['language'];
+    if ($value_type != 'number') {
+      $object = $this->query->format_replacement($this->value, $value_type, $language);
+    }
+    else {
+      $var = '?var' . rand();
+      $this->query->add_filter('=', array($var, $this->value));
+      $object = $var;
+    }
+    $relationship = $this->options['relationship'];
+
+    if ($relationship == 'none') {
+      $subject = $this->definition['subject'];
+    }
+    else {
+      $subject = $relationship;
+    }
+    $predicate = $this->definition['rdf_mapping'][0];
+    $this->query->add_triple($subject, $predicate, $object);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_filter_field_value.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,95 @@
+<?php
+/**
+ * @file
+ * Views filter handler to display UI for WHERE clauses and prepare them for
+ * the query.
+ */
+
+class sparql_views_handler_filter_field_value extends sparql_views_handler_filter{
+  // We will use the value type and language form elements for getting
+  // necessary info about replacements that this filter makes.
+  var $selected_sparql_options = array('value_type', 'language');
+
+  function option_definition() {
+    $options = parent::option_definition();
+    // Attach the SPARQL specific options.
+    $options = _sparql_views_attach_form_options($options, $this->selected_sparql_options);
+
+    return $options;
+  }
+  
+  /**
+   * This kind of construct makes it relatively easy for a child class
+   * to add or remove functionality by overriding this function and
+   * adding/removing items from this array.
+   */
+  function operators() {
+    $operators = array(
+      '=' => array(
+        'title' => t('Is equal to'),
+        'short' => t('='),
+        'method' => 'op_equal',
+        'values' => 1,
+      ),
+    );
+    return $operators;
+  }
+
+  function admin_summary() {
+    $output = $this->operator . ' ';
+    $output .= check_plain($this->options['value']);
+    $output .= "<i>({$this->options['sparql_options']['value_type']})</i>";
+    return $output;
+  }
+  
+  function value_form(&$form, &$form_state) {
+    // We have to make some choices when creating this as an exposed
+    // filter form. For example, if the operator is locked and thus
+    // not rendered, we can't render dependencies; instead we only
+    // render the form items we need.
+    $which = 'all';
+    if (!empty($form['operator'])) {
+      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+    }
+    if (!empty($form_state['exposed'])) {
+      $identifier = $this->options['expose']['identifier'];
+
+      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+        // exposed and locked.
+        $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+      }
+      else {
+        $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+      }
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $form['value'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Value'),
+        '#size' => 60,
+        '#default_value' => $this->value,
+      );
+      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+        $form_state['input'][$identifier] = $this->value;
+      }
+
+      if ($which == 'all') {
+        $form['value'] += array(
+          '#process' => array('ctools_dependent_process'),
+          '#dependency' => array($source => $this->operator_values(1)),
+        );
+      }
+    }
+
+    if (!isset($form['value'])) {
+      // Ensure there is something in the 'value'.
+      $form['value'] = array(
+        '#type' => 'value',
+        '#value' => NULL
+      );
+    }
+    // Attach the SPARQL specific form elements.
+    $form = _sparql_views_attach_form_elements($form, $this->options, $this->selected_sparql_options);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_filter_language.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,100 @@
+<?php
+/**
+ * @file
+ * Views filter handler to display UI for WHERE clauses and prepare them for
+ * the query.
+ */
+
+class sparql_views_handler_filter_language extends sparql_views_handler_filter{
+
+  function option_definition() {
+    $options = parent::option_definition();
+    return $options;
+  }
+  
+  /**
+   * This kind of construct makes it relatively easy for a child class
+   * to add or remove functionality by overriding this function and
+   * adding/removing items from this array.
+   */
+  function operators() {
+    $operators = array(
+      '=' => array(
+        'title' => t('Is equal to'),
+        'short' => t('='),
+        'method' => 'op_equal',
+        'values' => 1,
+      ),
+    );
+    return $operators;
+  }
+
+  function admin_summary() {
+    $output = $this->operator . ' ';
+    $output .= check_plain($this->options['value']);
+    return $output;
+  }
+  
+  function value_form(&$form, &$form_state) {
+    $languages = array('<none>') + _sparql_views_get_language_list();
+
+    // We have to make some choices when creating this as an exposed
+    // filter form. For example, if the operator is locked and thus
+    // not rendered, we can't render dependencies; instead we only
+    // render the form items we need.
+    $which = 'all';
+    if (!empty($form['operator'])) {
+      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+    }
+    if (!empty($form_state['exposed'])) {
+      $identifier = $this->options['expose']['identifier'];
+
+      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+        // exposed and locked.
+        $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+      }
+      else {
+        $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+      }
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $form['value'] = array(
+        '#type' => 'select',
+        '#title' => t('Language'),
+        '#options' => $languages,
+        '#default_value' => $this->value,
+      );
+      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+        $form_state['input'][$identifier] = $this->value;
+      }
+
+      if ($which == 'all') {
+        $form['value'] += array(
+          '#process' => array('ctools_dependent_process'),
+          '#dependency' => array($source => $this->operator_values(1)),
+        );
+      }
+    }
+
+    if (!isset($form['value'])) {
+      // Ensure there is something in the 'value'.
+      $form['value'] = array(
+        '#type' => 'value',
+        '#value' => NULL
+      );
+    }
+  }
+
+  function query() {
+    $field_name = $this->definition['base field'];
+    $info = $this->operators();
+    if (!empty($info[$this->operator]['method'])) {
+      $this->{$info[$this->operator]['method']}($field_name);
+    }
+  }
+  
+  function op_equal($field_name) {
+    $this->query->add_filter('langMatches', array("lang(?$field_name)", '"' . strtoupper($this->value) . '"'));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_filter_rdftype.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,108 @@
+<?php
+/**
+ * @file
+ * Views filter handler to display UI for WHERE clauses and prepare them for
+ * the query.
+ */
+
+class sparql_views_handler_filter_rdftype extends sparql_views_handler_filter{  
+  /**
+   * This kind of construct makes it relatively easy for a child class
+   * to add or remove functionality by overriding this function and
+   * adding/removing items from this array.
+   */
+  function operators() {
+    $operators = array(
+      '=' => array(
+        'title' => t('Is equal to'),
+        'short' => t('='),
+        'method' => 'op_equal',
+        'values' => 1,
+      ),
+    );
+    return $operators;
+  }
+
+  function admin_summary() {
+    $output = $this->operator . ' ';
+    $output .= check_plain($this->options['value']);
+    return $output;
+  }
+  
+  function value_form(&$form, &$form_state) {
+    // We have to make some choices when creating this as an exposed
+    // filter form. For example, if the operator is locked and thus
+    // not rendered, we can't render dependencies; instead we only
+    // render the form items we need.
+    $which = 'all';
+    if (!empty($form['operator'])) {
+      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+    }
+    if (!empty($form_state['exposed'])) {
+      $identifier = $this->options['expose']['identifier'];
+
+      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator'])) {
+        // exposed and locked.
+        $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+      }
+      else {
+        $source = 'edit-' . drupal_html_id($this->options['expose']['operator']);
+      }
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $value = $this->value;
+      if (empty($this->value) && count($this->definition['rdf_type']) > 0) {
+        $value = reset($this->definition['rdf_type']);
+      }
+      $form['value'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Value'),
+        '#size' => 60,
+        '#default_value' => $value,
+      );
+      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+        $form_state['input'][$identifier] = $this->value;
+      }
+
+      if ($which == 'all') {
+        $form['value'] += array(
+          '#process' => array('ctools_dependent_process'),
+          '#dependency' => array($source => $this->operator_values(1)),
+        );
+      }
+    }
+
+    if (!isset($form['value'])) {
+      // Ensure there is something in the 'value'.
+      $form['value'] = array(
+        '#type' => 'value',
+        '#value' => NULL
+      );
+    }
+  }
+
+  function query() {
+    $field_name = $this->real_field;
+    $info = $this->operators();
+    if (!empty($info[$this->operator]['method'])) {
+      $this->{$info[$this->operator]['method']}($field_name);
+    }
+  }
+  
+  function op_equal($field_name) {
+    $object = $this->query->format_replacement($this->options['value'], 'uri');
+    $relationship = $this->options['relationship'];
+
+    if ($relationship == 'none') {
+      $subject = $this->definition['subject'];
+    }
+    else {
+      $subject = $relationship;
+    }
+
+    // All RDF types have predicate rdf:type.
+    $predicate = 'rdf:type';
+    $this->query->add_triple($subject, $predicate, $object);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_relationship.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @file
+ * SPARQL Views relationship handler.
+ */
+
+/**
+ * Simple relationship handler that allows traversing a graph through
+ * relationships between resources.
+ */
+class sparql_views_handler_relationship extends views_handler_relationship {
+  /**
+   * We override the query function to avoid the call to ensure_mytable. We
+   * aren't using tables, so we don't need to ensure one.
+   */
+  function query() {
+    $object = $this->options['id'];
+    $relationship = $this->options['relationship'];
+
+    if ($relationship == 'none') {
+      $subject = $this->definition['subject'];
+    }
+    else {
+      $subject = $relationship;
+    }
+    $predicate = $this->definition['rdf_mapping'][0];
+    $this->field_alias = $this->query->add_triple($subject, $predicate, '?' . $object);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/handlers/sparql_views_handler_sort.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Base sort handler that performs a simple sort.
+ */
+class sparql_views_handler_sort extends views_handler_sort {
+  /**
+   * Called to add the sort to a query.
+   */
+  function query() {
+    $this->query->add_orderby($this->real_field, $this->options['order']);
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/includes/sparql_views.controller.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * @file
+ * Provides a controller building upon the core controller but providing more
+ * features like full CRUD functionality.
+ */
+
+/**
+ * A controller implementing EntityAPIControllerInterface for the database 
+ * which can deal with exportable SPARQL Views resources.
+ */
+class SparqlViewsController extends EntityAPIControllerExportable implements EntityAPIControllerInterface {
+
+  /**
+   * Implements EntityAPIControllerInterface.
+   *
+   * @param $transaction
+   *   Optionally a DatabaseTransaction object to use. Allows overrides to pass
+   *   in their transaction object.
+   */
+  public function save($entity, DatabaseTransaction $transaction = NULL) {
+    $transaction = isset($transaction) ? $transaction : db_transaction();
+    $entity_record = parent::save($entity, $transaction);
+
+    // Add the endpoints that this resource works with.
+    if (isset($entity->endpoints)) {
+      $entity_id = db_query("SELECT id FROM {sparql_views_resource_type} WHERE name = :name", array(':name' => $entity->name))->fetch();
+      $svid = $entity_id->id;
+      $delete = db_delete('sparql_views_resource_type_endpoint')->condition('svid', $svid)->execute();
+      $insert = db_insert('sparql_views_resource_type_endpoint')->fields(array('svid', 'endpoint_uri'));
+      foreach ($entity->endpoints as $endpoint_uri => $selected) {
+        if ($selected) {
+          $insert->values(array('svid' => $svid, 'endpoint_uri' => $endpoint_uri));
+        }
+      }
+      $insert->execute();
+    }
+
+    field_info_cache_clear();
+    return $entity_record;
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/plugins/sparql_views_plugin_argument_default_field.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,68 @@
+<?php
+/**
+ * @file
+ * Argument default to retrieve a field value from the node.
+ */
+
+/**
+ * The fixed argument default handler; also used as the base.
+ */
+class sparql_views_plugin_argument_default_field extends views_plugin_argument_default {
+  // We will use the value type and language form elements for getting
+  // necessary info about replacements that this argument makes.
+  var $selected_sparql_options = array('value_type', 'language');
+  /**
+   * Return the default argument.
+   *
+   * This needs to be overridden by every default argument handler to properly do what is needed.
+   */
+  function get_argument() {
+    foreach (range(1, 3) as $i) {
+      $node = menu_get_object('node', $i);
+      if (!empty($node)) {
+        $nid = $node->nid;
+        $source_field = $this->options['sparql_options']['source_field'];
+        $field = field_get_items('node', $node, $source_field);
+        $replacement = $field[0]['value'];
+
+        return $replacement;
+      }
+    }
+  }
+
+  /**
+   * Retrieve the options when this is a new access
+   * control plugin
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['source_field'] = array('default' => '');
+    // Attach the SPARQL specific options.
+
+    return $options;
+  }
+
+  /**
+   * Provide the default form for setting options.
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+
+    $fields = array();
+    $instance_info = field_info_instances('node');
+    foreach ($instance_info as $bundle) {
+      foreach ($bundle as $field_name => $field_info) {
+        $fields[$field_name] = check_plain(t($field_info['label']));
+      }
+    }
+    $form['sparql_options']['source_field'] = array(
+      '#type' => 'select',
+      '#title' => t('Source Field'),
+      '#options' => $fields,
+      '#default_value' => $this->options['sparql_options']['source_field'],
+      '#description' => t('The variable in the query will be replaced with the value of this field on the node.'),
+      '#weight' => -1,
+    );
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/plugins/sparql_views_plugin_query_sparql.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,383 @@
+<?php
+/**
+ * Object used to create a SELECT query.
+ */
+class sparql_views_plugin_query_sparql extends views_plugin_query {
+  /**
+   * Namespaces that are used in this query.
+   */
+  var $required_namespaces = array();
+
+  /**
+   * An array of fields which have been specified for selection. Fields may be
+   * included in the triple patterns (i.e. in filters or for path traversal)
+   * without being selected for retrieval.
+   */
+  var $select_fields = array();
+
+  /**
+   * An array of sections of the triple pattern. Each section is in itself
+   * an array of pieces.
+   */
+  var $triples = array();
+
+  /**
+   * An array of URIs and resources that are used as replacements for variables.
+   */
+  var $replacements = array();
+
+  /**
+   * An array of filter functions and parameters.
+   */
+  var $filters = array();
+
+  /**
+   * An array of fields to order by and the ordering direction.
+   */
+  var $orderby = array();
+
+  /**
+   * A pager plugin that should be provided by the display.
+   */
+  var $pager = NULL;
+
+  /**
+   * Constructor; Create the basic query object and fill with default values.
+   */
+  function init($base_table, $base_field, $options) {
+    parent::init($base_table, $base_field, $options);
+    $this->base_table = $base_table;
+    $this->base_field = $base_field;
+    $this->unpack_options($this->options, $options);
+
+    // Check to see whether the necessary requirements are met in order to
+    // create a valid query.
+    $data = views_fetch_data();
+    unset($data[$base_table]['table']);
+    if (count($data[$base_table]) === 0) {
+      $config = l(t('resource configuration'), 'admin/structure/sparql-views');
+      drupal_set_message(t('No resources are available for this endpoint. Please edit the !config to indicate which resources can be used with this endpoint.', array('!config' => $config)), 'warning', FALSE);
+    }
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['consolidate'] = array(
+      'default' => FALSE,
+      'bool' => TRUE,
+    );
+    $options['distinct'] = array(
+      'default' => TRUE,
+      'bool' => TRUE,
+    );
+
+    return $options;
+  }
+  
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    // Some form elements belong in a fieldset for presentation, but can't
+    // be moved into one because of the form_state['values'] hierarchy. Those
+    // elements can add a #fieldset => 'fieldset_name' property, and they'll
+    // be moved to their fieldset during pre_render.
+    // @todo Remove this when issue #1208824 is resolved.
+    $form['#pre_render'][] = 'views_ui_pre_render_add_fieldset_markup';
+
+    $form['consolidate'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Consolidate Results'),
+      '#description' => t('This will combine all the properties for a given subject into one result. This will override any field-level consolidation.'),
+      '#default_value' => !empty($this->options['consolidate']),
+    );
+
+    $form['advanced_settings'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Advanced settings'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+
+    $form['distinct'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Use DISTINCT query'),
+      '#description' => t("This eliminates duplicate rows by using !distinct. This can negatively effect the performance of the query, so you may want to turn off this option if you know that your dataset does not return duplicates for this query.", array('!distinct' => l('DISTINCT', 'http://www.w3.org/TR/rdf-sparql-query/#modDistinct'))),
+      '#default_value' => !empty($this->options['distinct']),
+      '#fieldset' => 'advanced_settings',
+    );
+  }
+
+ /**
+  * Generate a query and a countquery from all of the information supplied
+  * to the object.
+  *
+  * @param $get_count
+  *   Provide a countquery if this is true, otherwise provide a normal query.
+  */
+  function query($view, $get_count = FALSE) {
+    $triple_pattern = '';
+    $optionals = '';
+    $filters = '';
+    $orderby = '';
+    $ns = rdf_get_namespaces();
+    $bindings = array();
+    $prefixes = '';
+
+    // Create the SELECT clause.
+    $select = 'SELECT';
+
+    // Add DISTINCT if selected in Query Settings.
+    if ($this->options['distinct'] == TRUE) {
+      $select .= ' DISTINCT';
+    }
+
+    // Add fields that the user has added to the Fields section in Views UI.
+    foreach ($this->select_fields as $key => $field) {
+      // Do not add variable to SELECT if it will be replaced with a value.
+      if (!isset($this->replacements[$field])) {
+        // Add a question mark before each variable.
+        $select .= " ?$field";
+      }
+    }
+
+    // Create the WHERE clause.
+    $where = '';
+
+    // Form the triple pattern.
+    foreach($this->triples as $s => $pattern) {
+      $statements = array();
+      $triple_pattern .= isset($this->replacements[$s]) ? $this->replacements[$s]['replacement_formatted'] : "?$s";
+      foreach($pattern['pred_obj'] as $pred_obj) {
+        $p = isset($this->replacements[$pred_obj['p']]) ? $this->replacements[$pred_obj['p']]['replacement_formatted'] : $this->validate_curie($pred_obj['p']);
+
+        // If there is a preset value for the object, use the formatted version
+        // of it. Otherwise, use the field_alias as a variable.
+        $o = isset($this->replacements[$pred_obj['o']]) ? $this->replacements[$pred_obj['o']]['replacement_formatted'] : $pred_obj['o'];
+
+        // If this field is optional, wrap it in an OPTIONAL clause.
+        if ($pred_obj['#optional'] == TRUE) {
+          $optionals .= "OPTIONAL {?$s $p $o}\n";
+        }
+        else {
+          $statements[] = " $p $o";
+        }
+      }
+      $triple_pattern .= implode(';', $statements) . ".\n";
+    }
+
+    // Get namespaces.
+    $required_namespaces = array_unique($this->required_namespaces);
+    foreach($required_namespaces as $prefix) {
+      if (isset($ns[$prefix])) {
+        $namespace = $ns[$prefix];
+        $prefixes .= "PREFIX $prefix: <$namespace>\n";
+      }
+    }
+    // If no triples were added, run a generic ?s ?p ?o query.
+    if (empty($triple_pattern)) {
+      $triple_pattern = "?$field ?p ?o";
+    }
+
+    foreach ($this->filters as $filter) {
+      $filters .= "FILTER $filter\n";
+    }
+
+    if (!empty($this->orderby)) {
+      $orderby = "ORDER BY";
+      foreach ($this->orderby as $field => $order) {
+        $orderby .= " $order(?$field)\n";
+      }
+    }
+    $limit = isset($this->limit) ? "LIMIT $this->limit" : 'LIMIT 10';
+    
+    $query = $prefixes;
+    $query .= $select . "\n";
+    $query .= "WHERE {\n$triple_pattern $optionals $filters} \n";
+    $query .= $orderby;
+    $query .= $limit;
+    return $query;
+  }
+
+  /**
+   * Let modules modify the query just prior to finalizing it.
+   */
+  function alter(&$view) {  }
+
+  /**
+   * Builds the necessary info to execute the query.
+   */
+  function build(&$view) {
+    $view->init_pager();
+
+    // Let the pager modify the query to add limits.
+    $this->pager->query($view);
+
+    $view->build_info['query'] = $this->query($view);
+  }
+
+  /**
+   * Executes the query and fills the associated view object with according
+   * values.
+   *
+   * Values to set: $view->result, $view->total_rows, $view->execute_time,
+   * $view->pager['current_page'].
+   */
+  function execute(&$view) {
+    $views_result = array();
+    $query = $view->build_info['query'];
+    $views_data = sparql_views_views_data();
+    $endpoint_uri = $views_data[$this->base_table]['table']['endpoint']->uri;
+    $endpoint = sparql_registry_load_by_uri($endpoint_uri);
+    $start = microtime(TRUE);
+
+    $sparql_result = sparql_request($query, $endpoint);
+    if (empty($sparql_result) || empty($sparql_result['result']['rows'])) {
+      $view->result = array();
+      vsm(t('No result returned. Please check your query and the endpoint status.'));
+      return;
+    }
+    $rows = $sparql_result['result']['rows'];
+    $fields = $sparql_result['result']['variables'];
+
+    // Add the fields that were replaced by values so that we can render the
+    // preset values as part of the result.
+    $fields = array_merge($fields, array_keys($this->replacements));
+    foreach ($rows as $row) {
+      $views_row = array();
+      foreach($fields as $field) {
+        if (isset($row[$field])) {
+          $views_row[$field] = $row[$field];
+        }
+        else if (isset($this->replacements[$field])) {
+          $views_row[$field] = $this->replacements[$field]['replacement_raw'];
+        }
+      }
+      $views_result[] = (object) $views_row;
+    }
+    if ($this->options['consolidate']) {
+      $view->result = $this->consolidate_results($views_result);
+    }
+    else {
+      $view->result = $views_result;
+    }
+    $view->total_rows = count($view->result);
+    $view->execute_time = microtime(TRUE) - $start;
+    $view->pager['current_page'] = 0;
+  }
+
+  function add_triple($subject, $predicate, $object, $options = array()) {
+    $i = 1;
+    $alias = $object;
+
+    $defaults = array(
+      '#select' => FALSE,
+      '#optional' => FALSE,
+    );
+
+    $options = array_merge($defaults, $options);
+    while (in_array(preg_replace('/^\?/', '', $alias), $this->select_fields)) {
+      $alias = $object . '_' . $i;
+      $i++;
+    }
+
+    $o = $alias;
+    if ($options['#select'] == TRUE) {
+      $alias = preg_replace('/^\?/', '', $alias);
+      $this->select_fields[] = $alias;
+    }
+    $this->triples[$subject]['pred_obj'][] = array_merge(array('p' => $predicate, 'o' => $o), $options);
+
+    return $alias;
+  }
+
+  function add_filter($function, $params) {
+    $operators = array('=', '<', '>');
+    if (in_array($function, $operators)) {
+      $this->filters[] = "({$params[0]} $function {$params[1]})";
+    }
+    else {
+      $params = implode(', ',$params);
+      $this->filters[] = "$function($params)";
+    }
+  }
+
+  function add_orderby($field_name, $order) {
+    $this->orderby[$field_name] = $order;
+  }
+
+  /**
+   * Set a LIMIT on the query, specifying a maximum number of results.
+   */
+  function set_limit($limit) {
+    $this->limit = $limit;
+  }
+
+  function consolidate_results($views_result) {
+    $results = array();
+    $columns = array_keys((array) $views_result[0]);
+    $triples = $this->triples;
+    $subjects = array_keys($triples);
+    $properties = array_diff($columns, $subjects);
+
+    // Get all the rows that share the same subject
+    foreach ($views_result as $key => $value) {
+      foreach ($subjects as $subject) {
+        $row_subjects[$key][$subject] = $value->{$subject};
+        foreach ($triples[$subject]['pred_obj'] as $pred_obj) {
+          $field = $pred_obj['o'];
+          if (in_array($field, $properties)) {
+            $subject_uris[$subject][$value->{$subject}][$field][$value->{$field}] = $value->{$field};
+          }
+        }
+      }
+    }
+    $rows = _sparql_views_super_unique($row_subjects);
+    foreach ($rows as $key => $row) {
+      foreach ($row as $subject_field_name => $subject) {
+        $results[$key][$subject_field_name][] = $subject;
+        $results[$key] += $subject_uris[$subject_field_name][$subject];
+      }
+    }
+    return $results;
+  }
+
+  function validate_curie($curie) {
+    // If this starts with http, it isn't a CURIE.
+    if (preg_match('/^http/', $curie)) {
+      return $curie;
+    }
+
+    $split = explode(':', $curie);
+    if(count($split) == 2) {
+      $this->required_namespaces[] = $split[0];
+    }
+    return $curie; 
+  }
+
+  function format_replacement($replacement, $value_type, $language = NULL) {
+    switch($value_type){
+      case 'uri':
+        $replacement_formatted = preg_match('/^http/', $replacement) ? "<$replacement>" : $this->validate_curie($replacement);
+        break;
+      case 'string':
+        $replacement_formatted = '"' . $replacement . '"';
+        if (!empty($language)) {
+          $replacement_formatted .= "@$language";
+        }
+        break;
+    }
+    return $replacement_formatted;
+  }
+}
+
+function _sparql_views_super_unique($array)
+{
+  $result = array_map("unserialize", array_unique(array_map("serialize", $array)));
+
+  foreach ($result as $key => $value) {
+    if (is_array($value)) {
+      $result[$key] = _sparql_views_super_unique($value);
+    }
+  }
+
+  return $result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/sparql_views.admin.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,109 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * SPARQL Views type editing UI.
+ */
+
+/**
+ * UI controller.
+ */
+class SparqlViewsResourceTypeUIController extends EntityDefaultUIController {
+
+  /**
+   * Overrides hook_menu() defaults.
+   */
+  public function hook_menu() {
+    $items = parent::hook_menu();
+    $items[$this->path]['description'] = 'Manage SPARQL Views resource types, including fields.';
+    return $items;
+  }
+}
+
+/**
+ * Generates the resource type editing form.
+ */
+function sparql_views_resource_type_form($form, &$form_state, $resource_type, $op = 'edit') {
+  if ($op == 'clone') {
+    $resource_type->label .= ' (cloned)';
+    $resource_type->name .= '_clone';
+  }
+
+  $form['label'] = array(
+    '#title' => t('Label'),
+    '#type' => 'textfield',
+    '#default_value' => $resource_type->label,
+    '#description' => t('The human-readable label of this resource type.'),
+    '#required' => TRUE,
+  );
+  // Machine-readable type name.
+  $form['name'] = array(
+    '#type' => 'machine_name',
+    '#default_value' => isset($resource_type->name) ? $resource_type->name : '',
+    '#disabled' => entity_has_status('sparql_views_resource_type', $resource_type, ENTITY_IN_CODE),
+    '#machine_name' => array(
+      'exists' => 'sparql_views_resource_type_load',
+      'source' => array('label'),
+    ),
+    '#description' => t('A unique machine-readable name for this resource type. It must only contain lowercase letters, numbers, and underscores.'),
+  );
+
+  field_attach_form('sparql_views_resource_type', $resource_type, $form, $form_state);
+
+  $selected_endpoints = db_query("SELECT endpoint_uri FROM {sparql_views_resource_type_endpoint} WHERE svid = :svid", array(':svid' => $resource_type->id))->fetchCol();
+  $endpoints = sparql_registry_load_multiple();
+  $options = array();
+  foreach ($endpoints as $endpoint) {
+    $options[$endpoint->uri] = $endpoint->title . ': <span class="description">' . $endpoint->uri . '</span>';
+  }
+  $form['endpoints'] = array(
+    '#title' => t('Endpoints this resource can be found in'),
+    '#type' => 'checkboxes',
+    '#default_value' => !empty($selected_endpoints) ? $selected_endpoints : array(),
+    '#description' => t('Different endpoints often have different ways of describing similar things. Select the endpoints that this resource can be used with and the resource and it\'s fields will show up as options in queries on the endpoints.'),
+    '#options' => $options,
+  );
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save resource type'),
+    '#weight' => 40,
+  );
+
+  if (!entity_has_status('sparql_views_resource_type', $resource_type, ENTITY_IN_CODE) && $op != 'add') {
+    $form['actions']['delete'] = array(
+      '#type' => 'submit',
+      '#value' => t('Delete resource type'),
+      '#weight' => 45,
+      '#limit_validation_errors' => array(),
+      '#submit' => array('sparql_views_resource_type_form_submit_delete')
+    );
+  }
+  return $form;
+}
+
+/**
+ * Validation callback.
+ */
+function sparql_views_resource_type_form_validate($form, &$form_state) {
+  entity_form_field_validate('sparql_views_resource_type', $form, $form_state);
+}
+
+/**
+ * Form API submit callback for the type form.
+ */
+function sparql_views_resource_type_form_submit(&$form, &$form_state) {
+  $resource_type = entity_ui_form_submit_build_entity($form, $form_state);
+  // Save and go back.
+  $resource_type->save();
+  $form_state['redirect'] = 'admin/structure/sparql-views';
+}
+
+/**
+ * Form API submit callback for the delete button.
+ */
+function sparql_views_resource_type_form_submit_delete(&$form, &$form_state) {
+  $form_state['redirect'] = 'admin/structure/sparql-views/manage/' . $form_state['sparql_views_resource_type']->name . '/delete';
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/sparql_views.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,35 @@
+name = SPARQL Views
+description = A module for creating SPARQL queries on external endpoints and displaying them using Views.
+dependencies[] = views
+dependencies[] = entity
+dependencies[] = sparql
+dependencies[] = sparql_registry
+dependencies[] = rdfx
+package = RDF
+core = 7.x
+files[] = sparql_views.admin.inc
+files[] = sparql_views.views.inc
+files[] = includes/sparql_views.controller.inc
+files[] = handlers/sparql_views_handler_argument.inc
+files[] = handlers/sparql_views_handler_field.inc
+files[] = handlers/sparql_views_handler_field_rdftype.inc
+files[] = handlers/sparql_views_handler_field_subject.inc
+files[] = handlers/sparql_views_handler_sort.inc
+files[] = handlers/sparql_views_handler_relationship.inc
+files[] = handlers/sparql_views_handler_filter.inc
+files[] = handlers/sparql_views_handler_filter_field_value.inc
+files[] = handlers/sparql_views_handler_filter_language.inc
+files[] = handlers/sparql_views_handler_filter_rdftype.inc
+files[] = plugins/sparql_views_plugin_query_sparql.inc
+files[] = plugins/sparql_views_plugin_argument_default_field.inc
+files[] = tests/sparql_views.test
+files[] = tests/sparql_views_query.test
+files[] = tests/sparql_views_basic.test
+files[] = tests/sparql_views_formatter.test
+
+; Information added by drupal.org packaging script on 2011-08-09
+version = "7.x-2.0-beta1"
+core = "7.x"
+project = "sparql_views"
+datestamp = "1312904520"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/sparql_views.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,156 @@
+<?php
+/**
+ * @file
+ * Install, update, and uninstall functions for the sparql_views_resource module.
+ */
+
+/**
+ * Implementation of hook_schema().
+ */
+function sparql_views_schema() {
+  // Defines schema fields required for exportable entities.
+  $entity_exportable_schema_fields = array(
+    'status' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      // Set the default to ENTITY_CUSTOM without using the constant as it is
+      // not safe to use it at this point.
+      'default' => 0x01,
+      'size' => 'tiny',
+      'description' => 'The exportable status of the entity.',
+    ),
+    'module' => array(
+      'description' => 'The name of the providing module if the entity has been defined in code.',
+      'type' => 'varchar',
+      'length' => 255,
+      'not null' => FALSE,
+    ),
+  );
+
+  $schema['sparql_views_resource_type'] = array(
+    'description' => 'Storage for user-defined sparql_views_resource types.',
+    'fields' => array(
+      // Although the "name" should be enough as the primary key, the numeric ID
+      // is required for the internal use of entity API.
+      'id' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Numeric sparql_views_resource type ID.',
+      ),
+      'name' => array(
+        'description' => 'The unified identifier for a sparql_views_resource type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'label' => array(
+        'description' => 'Label for this sparql_views_resource.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ) + $entity_exportable_schema_fields,
+    'primary key' => array('id'),
+    'unique keys' => array(
+      'name' => array('name'),
+    ),
+  );
+
+  $schema['sparql_views_resource'] = array(
+    'description' => 'An instance of a sparql_views_resource type (e.g. like a node is an instance of a node type).',
+    'fields' => array(
+      'svid' => array(
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'description' => 'The Unique ID of the sparql_views_resource.',
+      ),
+      'name' => array(
+        'description' => 'Reference to a sparql_views_resource a type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'uid' => array(
+        'description' => 'The user ID of the acting user.',
+        'type' => 'int',
+        'default value' => NULL,
+        'unsigned' => TRUE,
+      ),
+      'timestamp' => array(
+        'description' => 'When the sparql_views_resource instance was recorded.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+      ),
+    ),
+    'foreign keys' => array(
+      'sparql_views_resource_type' => array(
+        'table' => 'sparql_views_resource_type',
+        'columns' => array('name' => 'name'),
+      ),
+    ),
+    'primary key' => array('svid'),
+  );
+
+  $schema['sparql_views_resource_type_endpoint'] = _sparql_views_schema_7200();
+
+  return $schema;
+}
+
+/**
+ * Change endpoint identifier from SRID to endpoint URI in sparql_views_resource_type_endpoint database table.
+ */
+function sparql_views_update_7211() {
+  $result = db_query("SELECT * FROM {sparql_views_resource_type_endpoint}");
+
+  db_drop_table('sparql_views_resource_type_endpoint');
+
+  db_create_table('sparql_views_resource_type_endpoint', _sparql_views_schema_7200());
+  foreach ($result as $record) {
+    $svid = $record->svid;
+    $endpoint = sparql_registry_load($record->srid);
+    $db_insert = db_insert('sparql_views_resource_type_endpoint')
+      ->fields(array(
+        'svid' => $svid,
+        'endpoint_uri' => $endpoint->uri,
+      ))
+      ->execute();
+  }
+}
+
+function _sparql_views_schema_7200() {
+  $schema = array(
+    'description' => 'Defines which resource types can be used with which endpoints.',
+    'fields' => array(
+      'svid' => array(
+        'description' => 'The SVID of the resource.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'unsigned' => TRUE,
+      ),
+      'endpoint_uri' => array(
+        'description' => 'The URI of the endpoint that this resource is found in.',
+        'type' => 'varchar',
+        // IE8's max length.
+        'length' => 2083,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'foreign keys' => array(
+      'svid' => array(
+        'table' => 'sparql_views_resource_type',
+        'columns' => array('svid' => 'svid'),
+      ),
+      'endpoint_uri' => array(
+        'table' => 'sparql_registry',
+        'columns' => array('endpoint_uri' => 'uri'),
+      ),
+    ),
+  );
+
+  return $schema;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/sparql_views.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,468 @@
+<?php
+/**
+ * @file
+ * API functions to manipulate SPARQL Views resources.
+ */
+function sparql_views_views_api() {
+  return array(
+    'api' => '3',
+    'path' => drupal_get_path('module', 'sparql_views'),
+  );
+}
+
+/*
+ * Implements hook_permission().
+ */
+function sparql_views_permission() {
+  return array(
+    'administer sparql_views types' => array(
+      'title' => t('Administer SPARQL Views entities'), 
+      'description' => t('Add new entities and manage fields to be used in SPARQL Views queries.'),
+    ),
+  );
+}
+
+/**
+ * Implement hook_entity_info().
+ */
+function sparql_views_entity_info() {
+  $items['sparql_views_resource_type'] = array(
+    'label' => t('SPARQL Views resource type'),
+    'controller class' => 'SparqlViewsController',
+    'entity class' => 'SparqlViewsResourceType',
+    'base table' => 'sparql_views_resource_type',
+    'fieldable' => TRUE,
+    'entity keys' => array(
+      'id' => 'id',
+      'label' => 'label',
+      'name' => 'name',
+    ),
+    'exportable' => TRUE,
+    'export' => array(
+      'default hook' => 'default_sparql_views_type',
+    ),
+    'bundle of' => 'sparql_views_resource',
+    'module' => 'sparql_views',
+    'access callback' => 'sparql_views_resource_type_access',
+    // Enable the entity API's admin UI.
+    'admin ui' => array(
+      'path' => 'admin/structure/sparql-views',
+      'file' => 'sparql_views.admin.inc',
+      'controller class' => 'SparqlViewsResourceTypeUIController',
+    ),
+  );
+  $items['sparql_views_resource'] = array(
+    'label' => t('SPARQL Views resource'),
+    'controller class' => 'SparqlViewsController',
+    'entity class' => 'SparqlViewsResource',
+    'base table' => 'sparql_views_resource',
+    'fieldable' => TRUE,
+    'access callback' => 'sparql_views_resource_access',
+    'entity keys' => array(
+      'id' => 'svid',
+      // The resource has no label.
+      'label' => FALSE,
+      'bundle' => 'name',
+    ),
+    'bundles' => array(),
+    'bundle keys' => array(
+      'bundle' => 'name',
+    ),
+    'view modes' => array(
+      'full' => array(
+        'label' => t('Full'),
+        'custom settings' => FALSE,
+      ),
+    ),
+    'module' => 'sparql_views',
+  );
+
+  // Attach all the bundles that have been defined by the user.
+  $bundles = db_query("SELECT name, label FROM {sparql_views_resource_type}")->fetchAll();
+  foreach ($bundles as $key => $bundle) {
+    $items['sparql_views_resource']['bundles'][$bundle->name] = array(
+      'label' => $bundle->label,
+      'admin' => array(
+        'path' => 'admin/structure/sparql-views/manage/%sparql_views_resource_type',
+        'real path' => 'admin/structure/sparql-views/manage/' . $bundle->name,
+        'bundle argument' => 4,
+        'access arguments' => array('administer sparql_views types'),
+      ),
+    );
+  }
+
+  return $items;
+}
+
+/**
+ * @defgroup sparql_views_api SPARQL Views API
+ * @{
+ * SPARQL Views can be defined in code using modules. This means any dataset
+ * can have endpoints, SPARQL Views resource types, and default Views defined
+ * in a module. These defaults will be automatically installed upon module
+ * installation, but can be changed through the user interface by the site
+ * administrator.
+ *
+ * Modules must define their SPARQL Views types in their .install file.
+ * Defining SPARQL Views consists of the following steps:
+ * In .install
+ *   1. Register the endpoints used with sparql_views_register_endpoints.
+ *   2. Define the SPARQL Views resource types, setting the endpoints where this
+ *      resource is available, and save with sparql_views_resource_type_save.
+ *   3. Add field definitions for fields that will be used.
+ *   4. Add field instances to the SPARQL Views resource types.
+ * In .module
+ *   1. Define namespace mappings using hook_rdf_mapping. Try to use standard
+ *      prefixes for common vocabularies, such as those listed on
+ *      http://prefix.cc.
+ *   2. Define RDF mappings for SPARQL Views types using hook_rdf_mappings.
+ */
+
+/*
+ * Register SPARQL endpoints used by this module and get a list of the
+ * corresponding IDs for the submitted endpoints. If an endpoint is already
+ * registered for a URI, the ID for the pre-existing endpoint will be returned
+ * with no other action taken on that endpoint.
+ *
+ * @param $endpoints
+ *   An array of endpoint objects, keyed by label. If the endpoint is already
+ *   registered, the existing values are maintained.
+ *   
+ *   Required properties:
+ *     $endpoint->title - The human-readable name of the endpoint.
+ *     $endpoint->endpoint - The URI of the endpoint.
+ *   
+ * @return $endpoint_ids
+ *   An array of IDs, keyed by the labels passed by the caller.
+ *   For example:
+ *     array('DBpedia' => 2);
+ */
+function sparql_views_register_endpoints($endpoints = array()) {
+  $endpoint_ids = array();
+
+  foreach ($endpoints as $key => $endpoint) {
+    $endpoint_record = sparql_registry_load_by_uri($endpoint->uri);
+
+    if (empty($endpoint_record)) {
+      $endpoint_record = sparql_registry_save($endpoint);
+      $srid = $endpoint_record->srid;
+    }
+    else {
+      // In order to merge the two SPARQL registry objects, we convert to arrays
+      // and then convert the result to an object.
+      $updated_endpoint = (object) array_merge((array) $endpoint, (array) $endpoint_record);
+      sparql_registry_save($updated_endpoint);
+      $srid = $endpoint_record->srid;
+    }
+
+    $endpoint_ids[$key] = $srid;
+  }
+
+  return $endpoint_ids;
+}
+
+/**
+ * @} End of "defgroup sparql_views_api".
+ */
+
+/**
+ * A class used for SPARQL Views resource types.
+ */
+class SparqlViewsResourceType extends Entity {
+
+  public $name;
+  public $id;
+  public $label = '';
+
+  public function __construct($values = array()) {
+    parent::__construct($values, 'sparql_views_resource_type');
+  }
+}
+
+/**
+ * Creates a new resource type.
+ *
+ * If a resource type already exists, an exception will be thrown.
+ *
+ * @return SparqlViewsResourceType
+ *   Returns a new resource type object.
+ */
+function sparql_views_resource_type_create($name, $values = array()) {
+  // Make sure the resource type doesn't already exist to prevent duplicate key
+  // error.
+  if (sparql_views_resource_type_load($name)) {
+    throw new Exception('SPARQL Views resource type ' . check_plain($name) . ' already exists.');
+  }
+  $values['name'] = $name;
+  $return = entity_create('sparql_views_resource_type', $values);
+
+  return $return;
+}
+
+/**
+ * SparqlViewsResource type loader.
+ *
+ * @param $type_name
+ *   (optional) The name for this resource type. If no type is given all existing
+ *   types are returned.
+ *
+ * @return SparqlViewsResourceType
+ *   Returns a fully-loaded resource type definition if a type name is passed.
+ *   Else an array containing all types is returned.
+ */
+function sparql_views_resource_type_load($name = NULL) {
+  // Replace dashes with underscores so this can be used as menu argument
+  // loader too.
+  $types = entity_load_multiple_by_name('sparql_views_resource_type', isset($name) ? array(strtr($name, array('-' => '_'))) : FALSE);
+  if (isset($name)) {
+    return isset($types[$name]) ? $types[$name] : FALSE;
+  }
+  return $types;
+}
+
+/**
+ * Inserts or updates a resource object into the database.
+ *
+ * @param $resource
+ *   The resource object to be inserted.
+ *
+ * @return
+ *   Failure to write a record will return FALSE. Otherwise SAVED_NEW or
+ *   SAVED_UPDATED is returned depending on the operation performed.
+ */
+function sparql_views_resource_type_save($resource) {
+  return entity_save('sparql_views_resource_type', $resource);
+}
+
+/**
+ * Deletes an existing resource.
+ *
+ * @param $resource
+ *   The name of the resource type to be deleted.
+ */
+function sparql_views_resource_type_delete($resource) {
+  return entity_delete('sparql_views_resource_type', $resource);
+}
+
+/**
+ * A class used for resources.
+ */
+class SparqlViewsResource extends Entity {
+
+  public $name;
+  public $timestamp;
+
+  public function __construct($values = array()) {
+    if (isset($values['user'])) {
+      $values['uid'] = $values['user']->uid;
+      unset($values['user']);
+    }
+
+    parent::__construct($values, 'sparql_views_resource');
+    if (!isset($this->uid)) {
+      $this->uid = $GLOBALS['user']->uid;
+    }
+    if (!isset($this->timestamp)) {
+      $this->timestamp = time();
+    }
+  }
+
+  /**
+   * Returns the user associated with the resource.
+   */
+  public function user() {
+    return user_load($this->uid);
+  }
+
+  /**
+   * Sets a new user associated with the resource.
+   *
+   * @param $account
+   *   The user account object or the user account id (uid).
+   */
+  public function setUser($account) {
+    $this->uid = is_object($account) ? $account->uid : $account;
+  }
+
+  /**
+   * Gets the associated resource type.
+   *
+   * @return SparqlViewsResourceType
+   */
+  public function getType() {
+    return sparql_views_resource_type_load($this->name);
+  }
+
+  /**
+   * Generate an array for rendering the entity.
+   *
+   * @see entity_view()
+   */
+  public function view($view_mode = 'full', $langcode = NULL) {
+    $view =  parent::view($view_mode, $langcode);
+
+    $key = !empty($this->is_new) ? 0 : $this->svid;
+    // @todo Figure out what to render
+    $view['sparql_views_resource'][$key]['sparql_views_resource_render'] = array();
+    return $view;
+  }
+}
+
+/**
+ * Helper to easily create resources.
+ *
+ * @param $name
+ *   The resource type name.
+ * @param $values
+ *   Array with the following keys:
+ *   - "timestamp" - The unix timestamp of the creation time of the resource. If
+ *     empty the current time will be used.
+ * @param $account
+ *   Optional; The user object to associate the resource with. If empty, the
+ *   current user will be used.
+ */
+function sparql_views_resource_create($name, $values = array(), $account = NULL) {
+  $values['name'] = $name;
+  $values['user'] = $account;
+  return entity_create('sparql_views_resource', $values);
+}
+
+/**
+ * SparqlViewsResource load.
+ *
+ * @param $mid
+ *   The resource ID.
+ * @return SparqlViewsResource
+ *   A resource object.
+ */
+function sparql_views_resource_load($svid) {
+  $result = entity_load_multiple_by_name('sparql_views_resource', array($svid));
+  return $result ? reset($result) : FALSE;
+}
+
+/**
+ * Loads multiple resources.
+ *
+ * @see entity_load_multiple_by_name().
+ */
+function sparql_views_resource_load_multiple($svids, $conditions = array()) {
+  return entity_load_multiple_by_name('sparql_views_resource', $svids, $conditions);
+}
+
+/**
+ * SparqlViewsResource save.
+ *
+ * @param $resource_instance
+ *   A resource instance object.
+ * @return
+ *   The saved resource instance object.
+ */
+function sparql_views_resource_save($resource) {
+  return entity_save('sparql_views_resource', $resource);
+}
+
+/**
+ * SparqlViewsResource delete.
+ *
+ * @param $iid
+ *   SparqlViewsResource instance IDs array.
+ */
+function sparql_views_resource_delete_multiple($svids = array()) {
+  entity_delete_multiple('sparql_views_resource', $svids);
+}
+
+/**
+ * Access callback for the resource entity.
+ */
+function sparql_views_resource_access($op, $entity, $account = NULL, $entity_type = 'sparql_views_resource') {
+  return user_access('create sparql_views resources');
+}
+
+/**
+ * Access callback for the resource type entities.
+ */
+function sparql_views_resource_type_access($op, $entity, $account, $entity_type) {
+  return user_access('administer sparql_views types', $account);
+}
+
+/**
+ * Implements hook_entity_insert().
+ */
+function sparql_views_entity_insert($type, $entity) {
+  switch ($type) {
+    // When a new SPARQL Endpoint is registered, clear the views cache so the
+    // new view type shows up.
+    case 'sparql_registry':
+      cache_clear_all('*', 'cache_views', TRUE);
+      return $entity;
+    // @todo Once #1123676 is fixed, add cache clear for
+    // sparql_views_resource_type.
+  }
+}
+
+/**
+ * Implements hook_entity_update().
+ */
+function sparql_views_entity_update($entity, $type) {
+  switch ($type) {
+    // When someone updates a SPARQL Views resource type (i.e. by adding an
+    // endpoint), refresh the Views cache so its fields are available in Views
+    // on that endpoint.
+    case 'sparql_views_resource_type':
+      cache_clear_all('*', 'cache_views', TRUE);
+      return $entity;
+  }
+}
+
+function _sparql_views_get_variable_value_types() {
+  return array(
+    'uri' => 'URI',
+    'string' => 'String',
+    'number' => 'Number',
+  );
+}
+
+function _sparql_views_attach_form_options($options, array $selected) {
+  $op['value_type'] = array('default' => '');
+  $op['language'] = array('default' => '');
+  foreach ($selected as $key) {
+    $options['sparql_options'][$key] = $op[$key];
+  }
+  return $options;
+}
+
+function _sparql_views_attach_form_elements($form, $options, array $selected) {
+  $languages = array('<none>') + _sparql_views_get_language_list();
+  $form_elements['value_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Value Type'),
+    '#options' => _sparql_views_get_variable_value_types(),
+    '#default_value' => $options['sparql_options']['value_type'],
+  );
+  $form_elements['language'] = array(
+    '#type' => 'select',
+    '#title' => t('Language'),
+    '#options' => $languages,
+    '#default_value' => $options['sparql_options']['language'],
+  );
+
+  $form['sparql_options'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('SPARQL Settings'),
+    '#weight' => 0,
+  );
+  foreach ($selected as $key) {
+    $form['sparql_options'][$key] = $form_elements[$key];
+  }
+  return $form;
+}
+
+function _sparql_views_get_language_list() {
+  $languages = array();
+  // ISO 639-1 language codes.
+  $lang_list = array('ab','aa','af','ak','sq','am','ar','an','hy','as','av','ae','ay','az','bm','ba','eu','be','bn','bh','bi','bs','br','bg','my','ca','ch','ce','ny','zh','cv','kw','co','cr','hr','cs','da','dv','nl','dz','en','eo','et','ee','fo','fj','fi','fr','ff','gl','ka','de','el','gn','gu','ht','ha','he','hz','hi','ho','hu','ia','id','ie','ga','ig','ik','io','is','it','iu','ja','jv','kl','kn','kr','ks','kk','km','ki','rw','ky','kv','kg','ko','ku','kj','la','lb','lg','li','ln','lo','lt','lu','lv','gv','mk','mg','ms','ml','mt','mi','mr','mh','mn','na','nv','nb','nd','ne','ng','nn','no','ii','nr','oc','oj','cu','om','or','os','pa','pi','fa','pl','ps','pt','qu','rm','rn','ro','ru','sa','sc','sd','se','sm','sg','sr','gd','sn','si','sk','sl','so','st','es','su','sw','ss','sv','ta','te','tg','th','ti','bo','tk','tl','tn','to','tr','ts','tt','tw','ty','ug','uk','ur','uz','ve','vi','vo','wa','cy','wo','fy','xh','yi','yo','za','zu');
+  foreach ($lang_list as $lang) {
+    $languages[$lang] = $lang;
+  }
+  return $languages;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/sparql_views.views.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,244 @@
+<?php
+
+define('SPARQL_VIEWS_ENTITY', 'sparql_views_resource');
+
+function sparql_views_views_data() {
+  $data = array();
+
+  // For each registered endpoint, create a new base table.
+  foreach (sparql_views_get_endpoints() as $endpoint) {
+    $data[$endpoint->table_id]['table']['group'] = t('SPARQL Views');
+  
+    $data[$endpoint->table_id]['table']['base'] = array(
+      'field' =>'vsid',
+      'title' => t('SPARQL Views: ' . $endpoint->title),
+      'query class' => 'sparql_views_query',
+      'help' => t('Views SPARQL query builder'),
+    );
+
+    $data[$endpoint->table_id]['table']['endpoint'] = $endpoint;
+  }
+
+  if (!isset($data)) {
+    drupal_set_message(t('There are no SPARQL Views view types available. To make one available, !register.', array('!register' => l(t('register a SPARQL endpoint'), 'admin/structure/sparql_registry'))), 'warning');
+    return;
+  }
+
+  return $data;
+}
+
+/*
+ * Implements hook_views_data_alter().
+ *
+ * Each endpoint gets its own set of fields based on which SPARQL Views
+ * resource types are enabled for it.
+ */
+function sparql_views_views_data_alter(&$data) {
+  $entity_info = entity_get_info(SPARQL_VIEWS_ENTITY);
+  // Create the data definition for each endpoint.
+  foreach (sparql_views_get_endpoints() as $endpoint) {
+    $select = db_select('sparql_views_resource_type', 'svrt')
+      ->fields('svrt', array('name'));
+    $select->join('sparql_views_resource_type_endpoint', 'e', 'svrt.id = e.svid AND e.endpoint_uri = :endpoint', array(':endpoint' => $endpoint->uri));
+    $bundles = $select->execute()->fetchCol();
+    foreach($bundles as $bundle_type) {
+      $rdf_mapping = $entity_info['bundles'][$bundle_type]['rdf_mapping'];
+      $group = $entity_info['bundles'][$bundle_type]['label'];  
+      $new_fields = array();
+
+      // Attach handlers for the subject URI.
+      $new_fields[$bundle_type] = array(
+        'title' => t('URI'),
+        'group' => t($group),
+        'field' => array(
+          'handler' => 'sparql_views_handler_field_subject',
+          'field_name' => 'subject',
+          'bundle' => $bundle_type,
+          'rdf_mapping' => isset($rdf_mapping['rdftype']) ? $rdf_mapping['rdftype'] : NULL,
+          'click sortable' => TRUE,
+        ),
+        'sort' => array(
+          'help' => t('Order the results of the query. This can make your query very slow and will time out on some endpoints, such as DBpedia.'),
+          'handler' => 'sparql_views_handler_sort',
+        ),
+        'argument' => array(
+          'help' => t('Replace part of the query'),
+          'group' => t($group),
+          'base' => $endpoint->table_id,
+          'base field' => $bundle_type,
+          'handler' => 'sparql_views_handler_argument',
+          'label' => t($bundle_type),
+        ),
+      );
+
+      // Attach handlers for the subject RDF type.
+      $new_fields[$bundle_type . '_type'] = array(
+        'title' => t('RDF type'),
+        'group' => t($group),
+        'field' => array(
+          'handler' => 'sparql_views_handler_field_rdftype',
+          'field_name' => 'rdftype',
+          'bundle' => $bundle_type,
+          'rdf_mapping' => array('rdf:type'),
+          'subject' => $bundle_type,
+          'click sortable' => TRUE,
+        ),
+        'sort' => array(
+          'help' => t('Order the results of the query. This can make your query very slow and will time out on some endpoints, such as DBpedia.'),
+          'handler' => 'sparql_views_handler_sort',
+        ),
+        'filter' => array(
+          'help' => t('Replace part of the query'),
+          'group' => t($group),
+          'base' => $endpoint->table_id,
+          'base field' => $bundle_type,
+          'handler' => 'sparql_views_handler_filter_rdftype',
+          'label' => t($bundle_type),
+          'rdf_type' => isset($rdf_mapping['rdftype']) ? $rdf_mapping['rdftype'] : NULL,
+          'subject' => $bundle_type,
+        ),
+        'argument' => array(
+          'help' => t('Replace part of the query'),
+          'group' => t($group),
+          'base' => $endpoint->table_id,
+          'base field' => $bundle_type,
+          'handler' => 'sparql_views_handler_argument',
+          'label' => t($bundle_type),
+          'rdf_type' => isset($rdf_mapping['rdftype']) ? $rdf_mapping['rdftype'] : NULL,
+          'subject' => $bundle_type,
+        ),
+      );
+
+      // Attach handlers for the individual field.
+      foreach ($rdf_mapping as $field_name => $field ) {
+        // If this is the rdftype part of the RDF mapping, skip it.
+        if($field_name == 'rdftype') {
+          continue;
+        }
+
+        $field_info = field_info_field($field_name);
+        $instance_info = field_info_instance(SPARQL_VIEWS_ENTITY, $field_name, $bundle_type);
+        $field_label = $instance_info['label'];
+
+        $new_field = array(
+          'title' => t($field_label),
+          'help' => t('RDF mapping: %rdf-mapping', array('%rdf-mapping' => implode(', ', $field['predicates']))),
+          'group' => t($group),
+          'field' => array(
+            'handler' => 'sparql_views_handler_field',
+            'field_info' => $field_info,
+            'field_name' => $field_name,
+            'bundle' => $bundle_type,
+            'rdf_mapping' => $field['predicates'],
+            'subject' => $bundle_type,
+            'click sortable' => TRUE,
+          ),
+          'filter' => array(
+            'help' => t('Compare values.'),
+            'group' => t($group),
+            'base' => $endpoint->table_id,
+            'base field' => $field_name,
+            'handler' => 'sparql_views_handler_filter_field_value',
+            'label' => t($field_label),
+            'rdf_mapping' => $field['predicates'],
+            'subject' => $bundle_type,
+          ),
+          'argument' => array(
+            'help' => t('Replace part of the query'),
+            'group' => t($group),
+            'base' => $endpoint->table_id,
+            'base field' => $field_name,
+            'handler' => 'sparql_views_handler_argument',
+            'label' => t($field_label),
+            'rdf_mapping' => $field['predicates'],
+            'subject' => $bundle_type,
+          ),
+          'sort' => array(
+            'help' => t('Order the results of the query. This can make your query very slow and will time out on some endpoints, such as DBpedia.'),
+            'handler' => 'sparql_views_handler_sort',
+          ),
+        );
+
+        if ($field_info['type'] == 'sparql_views_related_resource') {
+          $new_field['relationship'] = array(
+            'help' => t('The last comment of a node.'),
+            'group' => t($group),
+            'base' => $endpoint->table_id,
+            'base field' => $field_name,
+            'handler' => 'sparql_views_handler_relationship',
+            'label' => t($field_label),
+            'rdf_mapping' => $field['predicates'],
+            'subject' => $bundle_type,
+          );
+        }
+
+        $new_fields[$bundle_type.'_'.$field_name] = $new_field;
+        $new_fields[$bundle_type.'_'.$field_name . '_language']['filter'] = array(
+          'title' => t($field_name . ' language'),
+            'help' => t('Choose the language for return values.'),
+            'group' => t($group),
+            'base' => $endpoint->table_id,
+            'base field' => $bundle_type.'_'.$field_name,
+            'handler' => 'sparql_views_handler_filter_language',
+            'label' => t('Language'),
+            'rdf_mapping' => $field['predicates'],
+            'subject' => $bundle_type,
+          );
+      }
+      $data[$endpoint->table_id] = array_merge($data[$endpoint->table_id], $new_fields);
+    }
+  }
+}
+
+/**
+ * Implementation of hook_views_plugins().
+ */
+function sparql_views_views_plugins() {
+  return array(
+    'query' => array(
+      'sparql_views_query' => array(
+        'title' => t('SPARQL Query'),
+        'help' => t('SPARQL Query'),
+        'handler' => 'sparql_views_plugin_query_sparql'
+      ),
+    ),
+    'argument default' => array(
+      'sparql_views_argument_default_field' => array(
+        'title' => t('Field Value (Node)'),
+        'help' => t('Replace a variable in the query with a node\'s field value.'),
+        'handler' => 'sparql_views_plugin_argument_default_field',
+      ),
+    ),
+  );
+}
+
+/*
+ * Helper function to get one endpoint with base table hash.
+ */
+function sparql_views_get_endpoint($uri) {
+  $endpoint = sparql_registry_load_by_uri($uri);
+  return _sparql_views_hash($endpoint);
+}
+
+/*
+ * Helper function to get base tables with hashes.
+ */
+function sparql_views_get_endpoints() {
+  $endpoints = sparql_registry_load_multiple();
+  foreach ($endpoints as $key => $endpoint) {
+    $endpoints[$key] = _sparql_views_hash($endpoint);
+  }
+  return $endpoints;
+}
+
+/*
+ * Private helper function to get hashes.
+ */
+function _sparql_views_hash($endpoint) {
+  // We create a hash of the endpoint URI so that we can have a short base
+  // table name while still ensuring exportability of Views between sites.
+  $hash = crc32(str_replace('http://', '', $endpoint->uri));
+  $endpoint->table_id = 'sparql_views_' . $hash;
+
+  return $endpoint;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/sparql_views_related_resource/sparql_views_related_resource.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,12 @@
+name = Related Resource
+description = Defines a field type for referencing one SPARQL Views resource type from another.
+package = Views
+core = 7.x
+dependencies[] = field
+
+; Information added by drupal.org packaging script on 2011-08-09
+version = "7.x-2.0-beta1"
+core = "7.x"
+project = "sparql_views"
+datestamp = "1312904520"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/sparql_views_related_resource/sparql_views_related_resource.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Defines a field type for referencing one SPARQL Views resource type from
+ * another.
+ */
+
+/**
+ * Implements hook_field_info().
+ */
+function sparql_views_related_resource_field_info() {
+  return array(
+    'sparql_views_related_resource' => array(
+      'label'             => t('Related Resource'),
+      'description'       => t('This field creates a relationship between one RDF resource and another.'),
+      'settings'          => array(
+        'referenceable_types' => array(),
+        'view' => array(
+          'view_name' => '',
+          'display_name' => '',
+          'args' => array(),
+        ),
+      ),
+      'default_widget'    => 'options_select',
+      'default_formatter' => 'text_default',
+      // Support hook_entity_property_info() from contrib "Entity API".
+      'property_type' => 'sparql_views_resource',
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function sparql_views_related_resource_field_is_empty($item, $field) {
+  return empty($item['value']);
+}
+
+function sparql_views_related_resource_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $element = array();
+  foreach ($items as $delta => $item) {
+    $element[$delta]['#markup'] = check_url($item['value']);
+  }
+  return $element;
+}
+
+/**
+ * Implements hook_field_widget_info_alter().
+ *
+ * The List module does not implement widgets of its own, but reuses the
+ * widgets defined in options.module.
+ *
+ * @see hook_options_list()
+ */
+function sparql_views_related_resource_field_widget_info_alter(&$info) {
+  $widgets = array(
+    'options_select' => array('sparql_views_related_resource'),
+  );
+
+  foreach ($widgets as $widget => $field_types) {
+    $info[$widget]['field types'] = array_merge($info[$widget]['field types'], $field_types);
+  }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Test the SPARQL Views resource CRUD handling.
+ */
+class SparqlViewsResourceTypeCrud extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'SPARQL Views resource type CRUD',
+      'description' => 'Test the create, update and remove of SPARQL Views resource types and resources.',
+      'group' => 'SPARQL Views',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('sparql_views');
+  }
+
+  /**
+   * Test CRUD of resource entity.
+   */
+  function testSparqlViewsResourceTypeCrud() {
+    $web_user = $this->drupalCreateUser();
+
+    $resource_type = sparql_views_resource_type_create('foo');
+    $resource_type->save();
+
+    $resource = sparql_views_resource_create('foo', array(), $web_user);
+    $resource->save();
+    $svid = $resource->svid;
+
+    // Reload the resource to see it was saved.
+    $resource = sparql_views_resource_load($svid);
+    $this->assertTrue(!empty($resource->svid), t('Resource was saved to the database.'));
+
+    $this->assertEqual($resource->uid, $web_user->uid, 'Resource has been saved for the right user.');
+
+    // Make sure an exception is thrown if resource type already exists.
+    try {
+      $resource_type = sparql_views_resource_type_create('foo');
+      $this->fail("Creating the same resource type hasn't created an exception.");
+    }
+    catch (Exception $e) {
+      $this->pass("Exception was thrown: ". $e->getMessage());
+    }
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views_basic.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,257 @@
+<?php
+
+/**
+ * Tests basic query functionality.
+ *
+ * This ensures that the query plugin itself can be used and is able to run
+ * queries. It does not test whether SPARQL Views resource fields are available
+ * and can be used in queries.
+ */
+class SparqlViewsBasicQueryTest extends SparqlViewsQueryTest {
+  
+  public static function getInfo() {
+    return array(
+      'name' => 'Tests basic SPARQL Views querying',
+      'description' => 'Tests some basic functions of SPARQL Views',
+      'group' => 'SPARQL Views',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp();
+  }
+
+  public function testFieldQuery() {
+    $view = $this->getBasicView();
+
+    // Execute the view.
+    $view->execute();
+
+    // Test that the query pulled something from the endpoint.
+    $this->assertEqual(10, count($view->result), t('The number of returned rows match.'));
+
+    // Test that the query pulled foaf:name from the endpoint.
+    $this->assertTrue($view->result[0]->{$this->field_name}, t('The query returned values for foaf:name.'));
+  }
+
+  public function testFilterRdfTypeQuery() {
+    $view = $this->getBasicView();
+    $endpoint = sparql_views_get_endpoint($this->endpoint['uri']);
+
+    $expected_clause = "/{$this->main_resource} rdf:type foaf:Person\;/";
+
+    $rdftype_filter = array(
+      'rdftype' => array(
+        'operator' => '=',
+        'value' => 'foaf:Person',
+        'group' => '0',
+        'exposed' => FALSE,
+        'expose' => array(
+          'operator' => FALSE,
+          'label' => '',
+        ),
+        'id' => $this->main_resource_rdftype,
+        'table' => $endpoint->table_id,
+        'field' => $this->main_resource_rdftype,
+        'relationship' => 'none',
+      ),
+    );
+
+    $view->display['default']->handler->override_option('filters', $rdftype_filter);
+
+    // Execute the view.
+    $view->execute();
+
+    $query = $view->build_info['query'];
+
+    // Test that the query is built properly.
+    $this->assertTrue((preg_match($expected_clause, $query) == TRUE), t('RDF type filter adds type restriction.'));
+  }
+
+  public function testFilterLanguageQuery() {
+    $view = $this->getBasicView();
+    $endpoint = sparql_views_get_endpoint($this->endpoint['uri']);
+
+    $existing_fields = $view->display['default']->handler->get_option('fields');
+    $new_fields = array(
+      'field_affiliation' => array(
+        'id' => $this->field_affiliation,
+        'table' => $endpoint->table_id,
+        'field' => $this->field_affiliation,
+        'relationship' => 'none',
+      ),
+    );
+    $view->display['default']->handler->override_option('fields', array_merge($existing_fields, $new_fields));
+
+    $lang_filter = array(
+      'language' => array(
+        'operator' => '=',
+        'value' => 'ie',
+        'group' => '0',
+        'exposed' => FALSE,
+        'expose' => array(
+          'operator' => FALSE,
+          'label' => '',
+        ),
+        'id' => $this->field_affiliation . '_language',
+        'table' => $endpoint->table_id,
+        'field' => $this->field_affiliation . '_language',
+        'relationship' => 'none',
+      ),
+    );
+
+    $view->display['default']->handler->override_option('filters', $lang_filter);
+
+    // Execute the view.
+    $view->execute();
+
+    $query = $view->build_info['query'];
+
+    // Test that the query is built properly.
+    $this->assertTrue(count($view->result) == 1 && preg_match('/Gaillimh/', $view->result[0]->{$this->field_affiliation}), t('Filter (language) query returns correct result.'));  }
+
+  public function testRelationshipQuery() {
+    $view = $this->getBasicView();
+    $endpoint = sparql_views_get_endpoint($this->endpoint['uri']);
+
+    $view->display['default']->handler->override_option('relationships', array(
+      $this->rel_1 => array(
+        'id' => $this->rel_1,
+        'table' => $endpoint->table_id,
+        'field' => $this->rel_1,
+        'relationship' => 'none',
+      ),
+    ));
+
+    $existing_fields = $view->display['default']->handler->get_option('fields');
+    $new_fields = array(
+      $this->rel_1_field_name => array(
+        'id' => $this->rel_1_field_name,
+        'table' => $endpoint->table_id,
+        'field' => $this->rel_1_field_name,
+        'relationship' => $this->rel_1,
+      ),
+    );
+    $view->display['default']->handler->override_option('fields', array_merge($existing_fields, $new_fields));
+
+    // Execute the view.
+    $view->execute();
+
+    // Test that the right result was returned.
+    $this->assertTrue($view->result[0]->{$this->rel_1_field_name} === 'SPARQL Views: A Visual SPARQL Query Builder for Drupal', t('Relationship query returns correct result.'));
+  }
+
+  /**
+   * Test whether the name field can be retrieved from two people, related
+   * resources of the same type. This can pose a problem because the query
+   * could potentially end up looking for two related people with the same
+   * name.
+   */
+  public function testRelationshipDuplicatedFieldQuery() {
+    $view = $this->getBasicView();
+    $endpoint = sparql_views_get_endpoint($this->endpoint['uri']);
+
+    $view->display['default']->handler->override_option('relationships', array(
+      $this->rel_knows => array(
+        'id' => $this->rel_knows,
+        'table' => $endpoint->table_id,
+        'field' => $this->rel_knows,
+        'relationship' => 'none',
+      ),
+    ));
+
+    $existing_fields = $view->display['default']->handler->get_option('fields');
+    $new_fields = array(
+      'field_name' => array(
+        'id' => $this->field_name,
+        'table' => $endpoint->table_id,
+        'field' => $this->field_name,
+        'relationship' => $this->rel_knows,
+      ),
+    );
+    $view->display['default']->handler->override_option('fields', array_merge($existing_fields, $new_fields));
+
+    // Execute the view.
+    $view->execute();
+
+    // Test that the right result was returned. Add _1 to the end of the field
+    // name because that is how it would be aliased.
+    $this->assertTrue(count($view->result) == 3 && $view->result[0]->{$this->field_name . '_1'} === 'Vinny Reynolds', t('Relationship query using same field on related resource returns correct result.'));
+  }
+
+  /**
+   * Test simple argument.
+   */
+  public function testSimpleArgument() {
+    $view = $this->getBasicView();
+    $endpoint = sparql_views_get_endpoint($this->endpoint['uri']);
+
+    // Add a argument.
+    $view->display['default']->handler->override_option('arguments', array(
+      $this->field_name => array(
+        'default_action' => 'ignore',
+        'id' => $this->field_name,
+        'table' => $endpoint->table_id,
+        'field' => $this->field_name,
+        'relationship' => 'none',
+        'sparql_options' => array(
+          'value_type' => 'string',
+          'language' => '0',
+          'code' => '',
+        ),
+      )
+    ));
+
+    $saved_view = clone $view;
+
+    // Execute with a view
+    $view->set_arguments(array('Lin Clark'));
+    $view->execute();
+
+    $this->assertTrue(count($view->result) == 1 && $view->result[0]->{$this->main_resource} === 'http://data.semanticweb.org/person/lin-clark', t('Argument query returns correct result.'));
+  }
+
+  /**
+   * Test complex relationship + argument.
+   */
+  public function testRelationshipArgument() {
+    $view = $this->getBasicView();
+    $endpoint = sparql_views_get_endpoint($this->endpoint['uri']);
+
+    // Add extra field.
+    $existing_fields = $view->display['default']->handler->get_option('fields');
+    $new_fields = array(
+      // Won't have to add the field once #1104074 is fixed.
+      'rel 1' => array(
+        'id' => $this->rel_1,
+        'table' => $endpoint->table_id,
+        'field' => $this->rel_1,
+        'relationship' => 'none',
+      ),
+    );
+    $view->display['default']->handler->override_option('fields', array_merge($existing_fields, $new_fields));
+    // Add a argument.
+    $view->display['default']->handler->override_option('arguments', array(
+      $this->field_name => array(
+        'default_action' => 'ignore',
+        'id' => $this->rel_1_field_name,
+        'table' => $endpoint->table_id,
+        'field' => $this->rel_1_field_name,
+        'relationship' => $this->rel_1,
+        'sparql_options' => array(
+          'value_type' => 'string',
+          'language' => '0',
+          'code' => '',
+        ),
+      )
+    ));
+
+    $saved_view = clone $view;
+
+    // Execute with a view
+    $view->set_arguments(array('SPARQL Views: A Visual SPARQL Query Builder for Drupal'));
+    $view->execute();
+
+    $this->assertTrue(count($view->result) == 1 && $view->result[0]->{$this->rel_1} === 'http://data.semanticweb.org/conference/iswc/2010/paper/518', t('Argument/relationship query returns correct result.'));
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views_formatter.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * Tests basic query functionality.
+ *
+ * This ensures that the query plugin itself can be used and is able to run
+ * queries. It does not test whether SPARQL Views resource fields are available
+ * and can be used in queries.
+ */
+class SparqlViewsFormatterTest extends SparqlViewsQueryTest {
+  public static function getInfo() {
+    return array(
+      'name' => 'Tests SPARQL Views field formatters',
+      'description' => 'Tests some basic functions of SPARQL Views',
+      'group' => 'SPARQL Views',
+    );
+  }
+
+  protected function setUp() {
+    parent::setUp('libraries', 'sparql_views', 'sparql_registry', 'views', 'views_ui', 'sparql_views_test');
+
+    $web_user = $this->drupalCreateUser(array('administer sparql_views types', 'administer views'));
+    $this->drupalLogin($web_user);
+  }
+
+  public function testFieldQuery() {
+    views_invalidate_cache();
+    $this->drupalGet('sparql_views_test_formatters');
+
+    // Text fields should display properly. If not, something is completely
+    // borked.
+    $this->assertRaw('<span class="field-content">Lin Clark</span>', t('Text field formatter works.'));
+  
+    // Number field.
+    $this->assertRaw('<span class="field-content">11,101</span>', t('Number field formatter works'));
+
+    // Image field.
+    $img = $this->xpath('//img[contains(@src, "http://lin-clark.com/sites/default/files/linclark-front.jpg")]');
+    $this->assertTrue(!empty($img), t('Image field created.'));
+  }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views_query.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,62 @@
+<?php
+
+abstract class SparqlViewsQueryTest extends ViewsTestCase {
+  var $endpoint = array(
+    'title' => 'SPARQL Views test',
+    'uri' => 'http://localhost/arc2/sparql_views_test/sparql.php',
+  );
+
+  // Field names.
+  var $main_resource = 'sparql_views_test_person';
+  var $main_resource_rdftype = 'sparql_views_test_person_type';
+  var $field_name = 'sparql_views_test_person_sparql_views_test_name';
+  var $field_affiliation = 'sparql_views_test_person_sparql_views_test_affiliation';
+  var $rel_1 = 'sparql_views_test_person_sparql_views_test_paper';
+  var $rel_1_field_name = 'sparql_views_test_paper_sparql_views_test_name';
+  var $rel_knows = 'sparql_views_test_person_sparql_views_test_knows';
+
+  protected function setUp() {
+    parent::setUp('sparql_views', 'sparql_registry', 'views', 'views_ui', 'sparql_views_test');
+  }
+
+  /**
+   * Build and return a basic view of the views_test table.
+   */
+  protected function getBasicView() {
+    views_include('view');
+
+    $endpoint = sparql_views_get_endpoint($this->endpoint['uri']);
+
+    // Create the basic view.
+    $view = new view();
+    $view->name = 'sparql_views_test';
+    $view->description = '';
+    $view->tag = 'default';
+    $view->base_table = $endpoint->table_id;
+    $view->human_name = 'SPARQL Views Test';
+    $view->core = 7;
+    $view->api_version = '3.0';
+    $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+    $display = $view->new_display('default', 'Master', 'default');
+    $display->override_option('query', array(
+      'type' => 'sparql_views_query',
+    ));
+    $display->override_option('fields', array(
+      'main resource' => array(
+        'id' => $this->main_resource,
+        'table' => $endpoint->table_id,
+        'field' => $this->main_resource,
+        'relationship' => 'none',
+      ),
+      'field 1' => array(
+        'id' => $this->field_name,
+        'table' => $endpoint->table_id,
+        'field' => $this->field_name,
+        'relationship' => 'none',
+      ),
+    ));
+
+    return $view;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views_test.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,17 @@
+name = SPARQL Views Test
+description = Test module for SPARQL Views.
+package = SPARQL Views
+core = 7.x
+dependencies[] = views
+dependencies[] = sparql_views
+dependencies[] = sparql_views_related_resource
+files[] = sparql_views_test.views_default.inc
+hidden = TRUE
+
+
+; Information added by drupal.org packaging script on 2011-08-09
+version = "7.x-2.0-beta1"
+core = "7.x"
+project = "sparql_views"
+datestamp = "1312904520"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views_test.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,176 @@
+<?php
+
+/**
+ * @file
+ * Install file for SPARQL Views Test module.
+ */
+
+/**
+ * Implements hook_install().
+ */
+function sparql_views_test_install() {
+  // Create the SPARQL Views resource type.
+  _sparql_views_test_create_resource_type();
+
+  // Create all the fields we are adding to our resource type.
+  foreach (_sparql_views_test_installed_fields() as $field) {
+    field_create_field($field);
+  }
+
+  // Create all the instances for our fields.
+  foreach (_sparql_views_test_installed_instances() as $bundle_name => $bundle) {
+    foreach ($bundle as $instance) {
+      $instance['bundle'] = $bundle_name;
+      field_create_instance($instance);
+    }
+  }
+}
+
+/**
+ * Implements hook_uninstall().
+ */
+function sparql_views_test_uninstall() {
+  // Delete the fields.
+  foreach (_sparql_views_test_installed_fields() as $field) {
+    field_delete_field($field['field_name']);
+  }
+
+  // Delete the resource type.
+  sparql_views_resource_type_delete('sparql_views_test_country');
+
+  // Delete the node type.
+  node_type_delete('sparql_views_test_leader');
+}
+
+/**
+ * Save the SPARQL Views resource type.
+ */
+function _sparql_views_test_create_resource_type() {
+  $t = get_t();
+
+  // Create an array of endpoint objects.
+  $endpoints = array();
+  $endpoints['sparql_views_test'] = (object) array(
+    'title' => 'SPARQL Views test',
+    'uri' => 'http://localhost/arc2/sparql_views_test/sparql.php',
+  );
+  // Save the endpoints and get an array of endpoint ids.
+  sparql_views_register_endpoints($endpoints);
+
+  // Define the SPARQL Views resource type - Person.
+  $sparql_views_test_person = array(
+    'name' => 'sparql_views_test_person',
+    'label' => $t('Person (SV test)'),
+    'base' => 'sparql_views_resource',
+    'description' => $t('This is a person as modeled in the ISWC2010 dataset.'),
+    // For each endpoint where this resource can be used, select that endpoint.
+    'endpoints' => array(
+      $endpoints['sparql_views_test']->uri => TRUE,
+    ),
+  );
+
+  // Define the SPARQL Views resource type - Paper.
+  $sparql_views_test_paper = array(
+    'name' => 'sparql_views_test_paper',
+    'label' => $t('Paper (SV test)'),
+    'base' => 'sparql_views_resource',
+    'description' => $t('This is a paper as modeled in the ISWC2010 dataset.'),
+    // For each endpoint where this resource can be used, select that endpoint.
+    'endpoints' => array(
+      $endpoints['sparql_views_test']->uri => TRUE,
+    ),
+  );
+
+  sparql_views_resource_type_save((object) $sparql_views_test_person);
+  sparql_views_resource_type_save((object) $sparql_views_test_paper);
+}
+
+/**
+ * Return a structured array defining the fields created by this resource type.
+ * Note that field names must be shorter than 32 characters.
+ */
+function _sparql_views_test_installed_fields() {
+  $t = get_t();
+
+  $return = array(
+    array(
+      'field_name' => 'sparql_views_test_name',
+      'type'        => 'text',
+    ),
+    array(
+      'field_name' => 'sparql_views_test_age',
+      'type'        => 'number_decimal',
+    ),
+    array(
+      'field_name' => 'sparql_views_test_person_image',
+      'type'        => 'image',
+    ),
+    array(
+      'field_name' => 'sparql_views_test_paper',
+      'type'        => 'sparql_views_related_resource',
+    ),
+    array(
+      'field_name' => 'sparql_views_test_knows',
+      'type'        => 'sparql_views_related_resource',
+    ),
+    array(
+      'field_name' => 'sparql_views_test_affiliation',
+      'type'        => 'text',
+    ),
+  );
+
+  return $return;
+}
+
+/**
+ * Return a structured array defining the instances for this content type.
+ */
+function _sparql_views_test_installed_instances() {
+  $t = get_t();
+  $instances = array();
+
+  // Add the fields to the resource type (Person).
+  $instances['sparql_views_test_person'] = array(
+    array(
+      'field_name'  => 'sparql_views_test_name',
+      'label'       => $t('Name'),
+      'entity_type' => 'sparql_views_resource',
+    ),
+    array(
+      'field_name'  => 'sparql_views_test_age',
+      'label'       => $t('Age'),
+      'entity_type' => 'sparql_views_resource',
+    ),
+    array(
+      'field_name'  => 'sparql_views_test_person_image',
+      'label'       => $t('Image'),
+      'entity_type' => 'sparql_views_resource',
+    ),
+    array(
+      'field_name'  => 'sparql_views_test_paper',
+      'label'       => $t('Authored Paper'),
+      'entity_type' => 'sparql_views_resource',
+    ),
+    array(
+      'field_name'  => 'sparql_views_test_knows',
+      'label'       => $t('Knows'),
+      'entity_type' => 'sparql_views_resource',
+    ),
+    array(
+      'field_name'  => 'sparql_views_test_affiliation',
+      'label'       => $t('Employer'),
+      'entity_type' => 'sparql_views_resource',
+    ),
+  );
+
+  // Add the fields to the resource type (Paper).
+  $instances['sparql_views_test_paper'] = array(
+    array(
+      'field_name'  => 'sparql_views_test_name',
+      'label'       => $t('Name'),
+      'entity_type' => 'sparql_views_resource',
+    ),
+  );
+
+  return $instances;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views_test.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * Implements hook_views_api().
+ */
+function sparql_views_test_views_api() {
+  return array(
+    'api' => '3.0',
+  );
+}
+
+/**
+ * Implements hook_rdf_mapping().
+ */
+function sparql_views_test_rdf_mapping() {
+  $return = array(
+    array(
+      'type' => 'sparql_views_resource',
+      'bundle' => 'sparql_views_test_person',
+      'mapping' => array(
+        'rdftype' => array('foaf:Person'),
+        'sparql_views_test_name' => array(
+          'predicates' => array('foaf:name'),
+        ),
+        'sparql_views_test_age' => array(
+          'predicates' => array('foaf:age'),
+        ),
+        'sparql_views_test_person_image' => array(
+          'predicates' => array('foaf:img'),
+        ),
+        'sparql_views_test_paper' => array(
+          'predicates' => array('foaf:made'),
+        ),
+        'sparql_views_test_knows' => array(
+          'predicates' => array('foaf:knows'),
+        ),
+        'sparql_views_test_affiliation' => array(
+          'predicates' => array('swc:affiliation'),
+        ),
+      ),
+    ),
+    array(
+      'type' => 'sparql_views_resource',
+      'bundle' => 'sparql_views_test_paper',
+      'mapping' => array(
+        'rdftype' => array('http://swrc.ontoware.org/ontology#InProceedings'),
+        'sparql_views_test_name' => array(
+          'predicates' => array('rdfs:label'),
+        ),
+      ),
+    ),
+  );
+
+  return $return;
+}
+
+/**
+ * Implements hook_rdf_namespaces().
+ */
+function sparql_views_test_rdf_namespaces() {
+  return array(
+    'swc' => 'http://data.semanticweb.org/ns/swc/ontology#',
+  );
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views_test.rdf	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,225 @@
+<?xml version="1.0"?>
+<rdf:RDF
+    xmlns:time="http://data.semanticweb.org/conference/iswc/2010/time/"
+    xmlns:iswc2010="http://data.semanticweb.org/conference/iswc/2010/"
+    xmlns:dc="http://purl.org/dc/elements/1.1/"
+    xmlns:dbpedia="http://dbpedia.org/resource/"
+    xmlns:org="http://data.semanticweb.org/organization/"
+    xmlns:person="http://data.semanticweb.org/person/"
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns:swc="http://data.semanticweb.org/ns/swc/ontology#"
+    xmlns:foaf="http://xmlns.com/foaf/0.1/"
+    xmlns:paper="http://data.semanticweb.org/conference/iswc/2010/paper/"
+    xmlns:ical="http://www.w3.org/2002/12/cal/ical#"
+    xmlns:owl="http://www.w3.org/2002/07/owl#"
+    xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
+    xmlns="http://data.semanticweb.org/conference/iswc/2010/complete#"
+    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+    xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
+    xmlns:shicc="http://www.shicc.net/ontoloy#"
+    xmlns:swrc="http://swrc.ontoware.org/ontology#"
+    xml:base="http://data.semanticweb.org/conference/iswc/2010/complete" > 
+
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/lin-clark">
+    <rdfs:label>Lin Clark</rdfs:label>
+    <foaf:status>Academia</foaf:status>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/research/pcmember"/>
+    <foaf:mbox>lin.clark@deri.org</foaf:mbox>
+    <foaf:family_name>Clark</foaf:family_name>
+    <foaf:made rdf:resource="http://data.semanticweb.org/conference/iswc/2010/paper/518"/>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/industry-2-chair"/>
+    <foaf:firstName>Lin</foaf:firstName>
+    <foaf:name>Lin Clark</foaf:name>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Ireland"/>
+    <swc:affiliation>National University of Ireland, Galway</swc:affiliation>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/chair/webmaster"/>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/national-university-of-ireland-galway"/>
+    <foaf:homepage>http://lin-clark.com/</foaf:homepage>
+    <foaf:mbox_sha1sum>579441ea0e0e9f41346d8241f8dd2b81cb2fa5fc</foaf:mbox_sha1sum>
+
+    <!-- Image for formatter testing -->
+    <foaf:img rdf:resource="http://lin-clark.com/sites/default/files/linclark-front.jpg"/>
+    <!-- Number for formatter testing -->
+    <foaf:age>11101</foaf:age>
+    <!-- Language for filter testing -->
+    <swc:affiliation xml:lang="ie">Ollscoil na hÉireann, Gaillimh</swc:affiliation>
+    <!-- Person for foaf:knows -->
+    <foaf:knows rdf:resource="http://data.semanticweb.org/person/vinny-reynolds"/>
+  </rdf:Description>
+
+  <!-- Authored Paper -->
+  <rdf:Description rdf:about="http://data.semanticweb.org/conference/iswc/2010/paper/518">
+    <foaf:maker rdf:resource="http://data.semanticweb.org/person/lin-clark"/>
+    <swc:authorList rdf:resource="http://data.semanticweb.org/conference/iswc/2010/paper/518/authorlist"/>
+    <swrc:url rdf:resource="http://iswc2010.semanticweb.org/pdf/518.pdf"/>
+    <dc:creator rdf:resource="http://data.semanticweb.org/person/lin-clark"/>
+    <dc:subject>End-user Programming</dc:subject>
+    <dc:subject>User Interfaces</dc:subject>
+    <dc:subject>CMS</dc:subject>
+    <rdfs:label>SPARQL Views: A Visual SPARQL Query Builder for Drupal</rdfs:label>
+    <swrc:author rdf:resource="http://data.semanticweb.org/person/lin-clark"/>
+    <swrc:month>November</swrc:month>
+    <swc:isPartOf rdf:resource="http://data.semanticweb.org/conference/iswc/2010/poster-demo-proceedings"/>
+    <swrc:abstract>Publishing Linked Data on the Web has become much easier with tools such as Drupal. However, consuming that data and presenting it in a meaningful way is still difficult for both Web developers and for Semantic Web practitioners. We demonstrate a module for Drupal which supports visual query building for SPARQL queries and enables meaningful displays of the query result.</swrc:abstract>
+    <rdf:type rdf:resource="http://swrc.ontoware.org/ontology#InProceedings"/>
+    <dc:title>SPARQL Views: A Visual SPARQL Query Builder for Drupal</dc:title>
+    <swrc:year>2010</swrc:year>
+  </rdf:Description>
+
+  <!-- 10 people for basic query testing -->
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/michael-hausenblas">
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/national-university-of-ireland-galway"/>
+    <foaf:firstName>Michael</foaf:firstName>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Ireland"/>
+    <rdfs:label>Michael Hausenblas</rdfs:label>
+    <swc:affiliation>National University of Ireland, Galway</swc:affiliation>
+    <foaf:name>Michael Hausenblas</foaf:name>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <foaf:family_name>Hausenblas</foaf:family_name>
+    <foaf:mbox>michael.hausenblas@deri.org</foaf:mbox>
+    <foaf:status>Academia</foaf:status>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/in-use/pcmember"/>
+    <foaf:homepage>http://sw-app.org/mic.xhtml</foaf:homepage>
+    <foaf:mbox_sha1sum>327b61f3721afbd39dceadf5e5b4fc2d79d5dcc8</foaf:mbox_sha1sum>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/vinny-reynolds">
+    <swc:affiliation>National University of Ireland, Galway</swc:affiliation>
+    <foaf:firstName>Vinny</foaf:firstName>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/research/reviewer"/>
+    <foaf:family_name>Reynolds</foaf:family_name>
+    <foaf:mbox>vinny.reynolds@deri.org</foaf:mbox>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Ireland"/>
+    <foaf:mbox_sha1sum>2e5fe5458ea3e457515f91d5f32d5bf3ee27eb0e</foaf:mbox_sha1sum>
+    <foaf:name>Vinny Reynolds</foaf:name>
+    <foaf:homepage>http://www.deri.ie/about/team/member/vinny_reynolds/</foaf:homepage>
+    <foaf:made rdf:resource="http://data.semanticweb.org/conference/iswc/2010/paper/503"/>
+    <foaf:status>Academia</foaf:status>
+    <rdfs:label>Vinny Reynolds</rdfs:label>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/national-university-of-ireland-galway"/>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/nuno-lopes">
+    <foaf:homepage>http://www.deri.ie/about/team/member/nuno_lopes/</foaf:homepage>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Ireland"/>
+    <foaf:status>Academia</foaf:status>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/national-university-of-ireland-galway"/>
+    <foaf:made rdf:resource="http://data.semanticweb.org/conference/iswc/2010/paper/442"/>
+    <foaf:mbox_sha1sum>f55387fb8cb7af2a64a81ddeb4f1e8affb000ed0</foaf:mbox_sha1sum>
+    <rdfs:label>Nuno Lopes</rdfs:label>
+    <foaf:mbox>nuno.lopes@deri.org</foaf:mbox>
+    <foaf:family_name>Lopes</foaf:family_name>
+    <foaf:firstName>Nuno</foaf:firstName>
+    <foaf:made rdf:resource="http://data.semanticweb.org/conference/iswc/2010/paper/51"/>
+    <swc:affiliation>National University of Ireland, Galway</swc:affiliation>
+    <foaf:name>Nuno Lopes</foaf:name>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/aidan-hogan">
+    <foaf:status>Academia</foaf:status>
+    <foaf:homepage>http://sw.deri.org/~aidanh/</foaf:homepage>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/national-university-of-ireland-galway"/>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/research/reviewer"/>
+    <swc:affiliation>National University of Ireland, Galway</swc:affiliation>
+    <foaf:family_name>Hogan</foaf:family_name>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Ireland"/>
+    <foaf:firstName>Aidan</foaf:firstName>
+    <foaf:mbox>aidan.hogan@deri.org</foaf:mbox>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <foaf:mbox_sha1sum>d2163e057507f828085f322cc77dc43b4105a158</foaf:mbox_sha1sum>
+    <foaf:name>Aidan Hogan</foaf:name>
+    <foaf:made rdf:resource="http://data.semanticweb.org/conference/iswc/2010/paper/305"/>
+    <rdfs:label>Aidan Hogan</rdfs:label>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/josiane-xavier-parreira">
+    <foaf:mbox_sha1sum>a69a534c7a5802053569792e8c769d8981487eb4</foaf:mbox_sha1sum>
+    <foaf:made rdf:resource="http://data.semanticweb.org/conference/iswc/2010/paper/503"/>
+    <foaf:firstName>Josiane</foaf:firstName>
+    <rdfs:label>Josiane Xavier Parreira</rdfs:label>
+    <foaf:family_name>Parreira</foaf:family_name>
+    <foaf:homepage>http://www.deri.ie/about/team/member/josiane_parreira/</foaf:homepage>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Ireland"/>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <swc:affiliation>National University of Ireland, Galway</swc:affiliation>
+    <foaf:mbox>josiane.parreira@deri.org</foaf:mbox>
+    <foaf:status>Academia</foaf:status>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/national-university-of-ireland-galway"/>
+    <foaf:name>Josiane Xavier Parreira</foaf:name>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/knud-moeller">
+    <foaf:name>Knud Moeller</foaf:name>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/research/pcmember"/>
+    <foaf:homepage>http://kantenwerk.org/</foaf:homepage>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/national-university-of-ireland-galway"/>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Ireland"/>
+    <foaf:mbox>knud.moeller@deri.org</foaf:mbox>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <foaf:mbox_sha1sum>b15d1e7efb11374644555fa9734bf75a553a362c</foaf:mbox_sha1sum>
+    <foaf:status>Academia</foaf:status>
+    <foaf:firstName>Knud</foaf:firstName>
+    <rdfs:label>Knud Moeller</rdfs:label>
+    <swc:affiliation>National University of Ireland, Galway</swc:affiliation>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/in-use/pcmember"/>
+    <foaf:family_name>Moeller</foaf:family_name>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/denny-vrandecic">
+    <swc:affiliation>Karlsruhe Institute of Technology</swc:affiliation>
+    <foaf:firstName>Denny</foaf:firstName>
+    <foaf:mbox>denny.vrandecic@kit.edu </foaf:mbox>
+    <foaf:mbox_sha1sum>724da1947282453da70768fab5ab29e1ba12d88a</foaf:mbox_sha1sum>
+    <foaf:name>Denny Vrandecic</foaf:name>
+    <foaf:status>Academia</foaf:status>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/research/reviewer"/>
+    <foaf:homepage>http://www.aifb.kit.edu/web/Denny_Vrandecic/en</foaf:homepage>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Germany"/>
+    <rdfs:label>Denny Vrandecic</rdfs:label>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/karlsruhe-institute-of-technology"/>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/dc/pcmember"/>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <foaf:family_name>Vrandecic</foaf:family_name>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/elena-simperl">
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/dc/pcmember"/>
+    <swc:affiliation>Universitat Innsbruck</swc:affiliation>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/Austria"/>
+    <foaf:mbox_sha1sum>09814d21068fb5bacc73c395dfd09780f462748a</foaf:mbox_sha1sum>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/universitat-innsbruck"/>
+    <foaf:family_name>Simperl</foaf:family_name>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <foaf:status>Academia</foaf:status>
+    <foaf:mbox>elena.simperl@sti2.at</foaf:mbox>
+    <foaf:firstName>Elena</foaf:firstName>
+    <rdfs:label>Elena Simperl</rdfs:label>
+    <foaf:homepage>http://members.sti2.at/~elenas/</foaf:homepage>
+    <foaf:name>Elena Simperl</foaf:name>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/person/leigh-dodds">
+    <foaf:firstName>Leigh</foaf:firstName>
+    <swrc:affiliation rdf:resource="http://data.semanticweb.org/organization/talis"/>
+    <foaf:status>Industry</foaf:status>
+    <foaf:mbox>leigh.dodds@talis.com</foaf:mbox>
+    <rdfs:label>Leigh Dodds</rdfs:label>
+    <foaf:homepage>http://www.ldodds.com/</foaf:homepage>
+    <foaf:mbox_sha1sum>3605b869216404d54ebcf0d2a7e045c39eb3109e</foaf:mbox_sha1sum>
+    <foaf:name>Leigh Dodds</foaf:name>
+    <foaf:based_near rdf:resource="http://dbpedia.org/resource/United_Kingdom"/>
+    <swc:holdsRole rdf:resource="http://data.semanticweb.org/conference/iswc/2010/in-use/pcmember"/>
+    <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/>
+    <swc:affiliation>Talis</swc:affiliation>
+    <foaf:family_name>Dodds</foaf:family_name>
+  </rdf:Description>
+  <rdf:Description rdf:about="http://data.semanticweb.org/conference/iswc/2010/paper/550">
+    <swrc:author rdf:resource="http://data.semanticweb.org/person/silver-oliver"/>
+    <swc:authorList rdf:resource="http://data.semanticweb.org/conference/iswc/2010/paper/550/authorlist"/>
+    <dc:title>Enhancing the BBC's World Cup coverage with an ontology driven information architecture</dc:title>
+    <rdfs:label>Enhancing the BBC's World Cup coverage with an ontology driven information architecture</rdfs:label>
+    <swrc:year>2010</swrc:year>
+    <dc:creator rdf:resource="http://data.semanticweb.org/person/silver-oliver"/>
+    <swc:isPartOf rdf:resource="http://data.semanticweb.org/conference/iswc/2010/industry-track-proceedings"/>
+    <swrc:url rdf:resource="http://iswc2010.semanticweb.org/pdf/550.pdf"/>
+    <rdf:type rdf:resource="http://swrc.ontoware.org/ontology#InProceedings"/>
+    <swrc:month>November</swrc:month>
+    <foaf:maker rdf:resource="http://data.semanticweb.org/person/silver-oliver"/>
+  </rdf:Description>
+
+  </rdf:RDF>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/sparql_views/tests/sparql_views_test.views_default.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,82 @@
+<?php
+/**
+ * @file
+ *   Test views
+ */
+
+define('TABLE_ID', 'sparql_views_' . crc32('localhost/arc2/sparql_views_test/sparql.php'));
+
+/**
+ * Implements hook_views_default_views().
+ */
+function sparql_views_test_views_default_views() {
+  $views['sparql_views_test_formatters'] = sparql_views_test_formatters();
+
+  return $views;
+}
+
+function sparql_views_test_formatters() {
+  $view = new view;
+  $view->name = 'sparql_views_test_formatters';
+  $view->description = '';
+  $view->tag = '';
+  $view->view_php = '';
+  $view->base_table = TABLE_ID;
+  $view->is_cacheable = FALSE;
+  $view->api_version = 3;
+  $view->version = 7;
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Master */
+  $handler = $view->new_display('default', 'Master', 'default');
+  $handler->display->display_options['access']['type'] = 'none';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '10';
+  $handler->display->display_options['style_plugin'] = 'default';
+  $handler->display->display_options['row_plugin'] = 'fields';
+
+  // Main resource.
+  $handler->display->display_options['fields']['sparql_views_test_person']['id'] = 'sparql_views_test_person';
+  $handler->display->display_options['fields']['sparql_views_test_person']['table'] = TABLE_ID;
+  $handler->display->display_options['fields']['sparql_views_test_person']['field'] = 'sparql_views_test_person';
+
+  // Text field.
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_name']['id'] = 'sparql_views_test_person_sparql_views_test_name';
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_name']['table'] = TABLE_ID;
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_name']['field'] = 'sparql_views_test_person_sparql_views_test_name';
+
+  // Number field.
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_age']['id'] = 'sparql_views_test_person_sparql_views_test_age';
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_age']['table'] = TABLE_ID;
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_age']['field'] = 'sparql_views_test_person_sparql_views_test_age';
+
+  // Image field.
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_person_image']['id'] = 'sparql_views_test_person_sparql_views_test_person_image';
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_person_image']['table'] = TABLE_ID;
+  $handler->display->display_options['fields']['sparql_views_test_person_sparql_views_test_person_image']['field'] = 'sparql_views_test_person_sparql_views_test_person_image';
+  
+  $handler->display->display_options['filters']['sparql_views_test_person_sparql_views_test_name']['id'] = 'sparql_views_test_person_sparql_views_test_name';
+  $handler->display->display_options['filters']['sparql_views_test_person_sparql_views_test_name']['table'] = TABLE_ID;
+  $handler->display->display_options['filters']['sparql_views_test_person_sparql_views_test_name']['field'] = 'sparql_views_test_person_sparql_views_test_name';
+  $handler->display->display_options['filters']['sparql_views_test_person_sparql_views_test_name']['value'] = 'Lin Clark';
+  $handler->display->display_options['filters']['sparql_views_test_person_sparql_views_test_name']['group'] = 0;
+  $handler->display->display_options['filters']['sparql_views_test_person_sparql_views_test_name']['expose']['operator'] = FALSE;
+  $handler->display->display_options['filters']['sparql_views_test_person_sparql_views_test_name']['sparql_options'] = array(
+    'value_type' => 'string',
+    'language' => '0',
+  );
+
+  $handler = $view->new_display('page', 'Page', 'page_1');
+  $handler->display->display_options['defaults']['fields'] = TRUE;
+
+  $handler->display->display_options['path'] = 'sparql_views_test_formatters';
+
+  return $view;
+}
+
+function sparql_views_test_table_id() {
+  return 'sparql_views_' . crc32('localhost/arc2/sparql_views_test/sparql.php');
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/url/LICENSE.txt	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/url/url.field.css	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,5 @@
+div.field-type-url div.field-value-url,
+div.field-type-url div.field-value-title {
+  float: left;
+  margin-right: 1em;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/url/url.info	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,14 @@
+name = URL
+description = Defines a simple URL field type.
+package = Fields
+core = 7.x
+dependencies[] = field
+recommends[] = elements
+files[] = url.test
+
+; Information added by drupal.org packaging script on 2013-01-26
+version = "7.x-1.0"
+core = "7.x"
+project = "url"
+datestamp = "1359196701"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/url/url.install	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Implements hook_field_schema().
+ */
+function url_field_schema($field) {
+  $schema['columns']['value'] = array(
+    'description' => 'The URL string.',
+    'type' => 'text',
+    'size' => 'big',
+    'not null' => FALSE,
+  );
+  $schema['columns']['title'] = array(
+    'description' => 'The title of the URL.',
+    'type' => 'varchar',
+    'length' => 1024,
+    'not null' => FALSE,
+  );
+  $schema['columns']['attributes'] = array(
+    'description' => 'The serialized array of attributes of the URL.',
+    'type' => 'blob',
+    'size' => 'big',
+    'not null' => FALSE,
+    'serialize' => TRUE,
+  );
+
+  return $schema;
+}
+
+/**
+ * Fix incorrect default values of URL field instances.
+ */
+function url_update_7100() {
+  $fields = field_read_fields(array('type' => 'url'));
+  foreach ($fields as $field) {
+    $instances = field_read_instances(array('field_name' => $field['field_name']));
+    foreach ($instances as $instance) {
+      _url_fix_field_default_value($field, $instance);
+    }
+  }
+}
+
+/**
+ * Helper function to fix incorrect default values of URL field instances.
+ *
+ * @see http://drupal.org/node/1899498
+ */
+function _url_fix_field_default_value($field, &$instance) {
+  if (!empty($instance['default_value'])) {
+    $items = $instance['default_value'];
+    url_field_presave(NULL, NULL, $field, $instance, LANGUAGE_NONE, $items);
+    if ($items !== $instance['default_value']) {
+      $instance['default_value'] = $items;
+      field_update_instance($instance);
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/url/url.module	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,373 @@
+<?php
+
+/**
+ * @file
+ * Provides a URL field type that stores external links with optional titles.
+ */
+
+/**
+ * Implements hook_help().
+ */
+function url_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#url':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The URL module defines a simple link field type for the Field module. Links are external URLs, can have an optional title for each link, and they can be formatted when displayed. See the <a href="@field-help">Field module help page</a> for more information about fields.', array('@field-help' => url('admin/help/field'))) . '</p>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_field_info().
+ */
+function url_field_info() {
+  $info['url'] = array(
+    'label' => t('URL'),
+    'description' => t('This field stores URLs with an optional title.'),
+    'instance_settings' => array(
+      'title_field' => 0,
+      'title_fetch' => 0,
+    ),
+    'default_widget' => 'url_external',
+    'default_formatter' => 'url_default',
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_field_instance_settings_form().
+ */
+function url_field_instance_settings_form($field, $instance) {
+  $settings = $instance['settings'];
+
+  $form['title_field'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Enable <em>Title</em> field'),
+    '#default_value' => $settings['title_field'],
+    '#description' => t('The title attribute is displayed when the link is displayed.'),
+  );
+  $form['title_fetch'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Attempt to fetch the title value from the URL if the <em>Title field</em> is empty.'),
+    '#default_value' => $settings['title_fetch'],
+  );
+
+  return $form;
+}
+
+/**
+ * Implements hook_field_load().
+ */
+function url_field_load($entity_type, $entities, $field, $instances, $langcode, &$items, $age) {
+  foreach ($entities as $id => $entity) {
+    foreach ($items[$id] as $delta => &$item) {
+      if (empty($item['attributes'])) {
+        $item['attributes'] = array();
+      }
+      else {
+        $item['attributes'] = unserialize($item['attributes']);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_is_empty().
+ */
+function url_field_is_empty($item, $field) {
+  return !isset($item['value']) || $item['value'] === '';
+}
+
+/**
+ * Implements hook_field_presave().
+ */
+function url_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
+  $settings = $instance['settings'];
+
+  foreach ($items as $delta => &$item) {
+    // If the link title is empty, and auto-fetching is enabled, then attempt
+    // to extract the title from a request to the URL.
+    // Skip this process if $entity is empty (field default value form)
+    if (!empty($entity) && !empty($settings['title_fetch']) && !empty($item['value']) && empty($item['title'])) {
+      // Parse the URL into a form ready for url().
+      $parsed = drupal_parse_url($item['value']);
+      $url = url($parsed['path'], array('query' => $parsed['query'], 'fragment' => $parsed['fragment'], 'absolute' => TRUE));
+      $item['title'] = url_fetch_title($url);
+    }
+
+    // Trim any spaces around the URL title.
+    $item['title'] = isset($item['title']) && is_string($item['title']) ? trim($item['title']) : '';
+
+    // Serialize the attributes array.
+    $item['attributes'] = !empty($item['attributes']) && is_array($item['attributes']) ? serialize($item['attributes']) : NULL;
+  }
+}
+
+/**
+ * Implements hook_field_widget_info().
+ */
+function url_field_widget_info() {
+  $info['url_external'] = array(
+    'label' => t('External URL field'),
+    'field types' => array('url'),
+    'settings' => array('size' => 60),
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_field_widget_settings_form().
+ */
+function url_field_widget_settings_form($field, $instance) {
+  $widget = $instance['widget'];
+  $settings = $widget['settings'];
+
+  $form['size'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Size of URL field'),
+    '#default_value' => $settings['size'],
+    '#required' => TRUE,
+    '#element_validate' => array('element_validate_integer_positive'),
+    '#weight' => -1,
+  );
+
+  return $form;
+}
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function url_field_widget_form($form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  $settings = $instance['settings'];
+
+  // Display this element in a fieldset if there is only one value.
+  if ($field['cardinality'] == 1) {
+    $element['#type'] = 'fieldset';
+  }
+
+  // URL field.
+  $element['value'] = array(
+    '#type' => 'urlfield', // Assumes elements module is enabled.
+    '#title' => t('URL'),
+    '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : '',
+    '#size' => $instance['widget']['settings']['size'],
+    '#maxlength' => 2048,
+    '#required' => !empty($element['#required']),
+    '#prefix' => '<div class="field-value field-value-url">',
+    '#suffix' => '</div>',
+  );
+
+  if (!module_exists('elements')) {
+    $element['value']['#type'] = 'textfield';
+    $element['value']['#element_validate'] = array('url_validate_url');
+  }
+
+  // Title field.
+  if (!empty($settings['title_field'])) {
+    $element['title'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Title'),
+      '#default_value' => isset($items[$delta]['title']) ? $items[$delta]['title'] : '',
+      '#maxlength' => 1024,
+      '#weight' => 10,
+      '#prefix' => '<div class="field-value field-value-title">',
+      '#suffix' => '</div>',
+    );
+
+    // Add additional styling to make both fields work together visually.
+    $element['#attached']['css'][] = drupal_get_path('module', 'url') . '/url.field.css';
+  }
+  else {
+    $element['title'] = array(
+      '#type' => 'value',
+      '#default_value' => isset($items[$delta]['title']) ? $items[$delta]['title'] : '',
+    );
+  }
+
+  // Exposing the attributes array in the widget is left for alternate and more
+  // advanced field widgets.
+  $element['attributes'] = array(
+    '#type' => 'value',
+    '#value' => !empty($items[$delta]['attributes']) ? $items[$delta]['attributes'] : array(),
+  );
+
+  // If the widget is being used on a default value form, due to a core bug we
+  // need to set the attributes default value to be an already serialized
+  // value so that it saves properly.
+  // @todo Remove when http://drupal.org/node/1899498 is fixed.
+  if (empty($element['#entity']) && !isset($items[$delta]['attributes'])) {
+    $element['attributes']['#value'] = NULL;
+  }
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_prepare_view().
+ */
+function url_field_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items) {
+  foreach ($entities as $id => $entity) {
+    foreach ($items[$id] as $delta => &$item) {
+      // Split out the link into the parts required for url(): path and options.
+      $parsed = drupal_parse_url($item['value']);
+      $item['path'] = $parsed['path'];
+      $item['options'] = array(
+        'query' => $parsed['query'],
+        'fragment' => $parsed['fragment'],
+        'attributes' => &$item['attributes'],
+      );
+    }
+  }
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function url_field_formatter_info() {
+  $info['url_default'] = array(
+    'label' => t('Link'),
+    'field types' => array('url'),
+    'settings' => array(
+      'trim_length' => 80,
+      'nofollow' => FALSE,
+    ),
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function url_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $element['trim_length'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Trim the link text to certain number of characters'),
+    '#description' => t('To leave long link text alone, leave this blank.'),
+    '#default_value' => $settings['trim_length'],
+    '#size' => 10,
+    '#element_validate' => array('element_validate_integer_positive'),
+  );
+
+  $element['nofollow'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Add rel="nofollow" to all links'),
+    '#default_value' => $settings['nofollow'],
+  );
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function url_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $summary = array();
+
+  if (!empty($settings['trim_length'])) {
+    $summary[] = t('Link text trimmed to @char characters.', array('@char' => $settings['trim_length']));
+  }
+  else {
+    $summary[] = t('Link text not trimmed.');
+  }
+
+  if (!empty($settings['nofollow'])) {
+    $summary[] = t('Add rel="nofollow"');
+  }
+
+  return implode('<br />', $summary);
+}
+
+/**
+ * Implements hook_field_formatter_prepare_view().
+ */
+function url_field_formatter_prepare_view($entity_type, $entities, $field, $instances, $langcode, &$items, $displays) {
+  foreach ($entities as $id => $entity) {
+    $settings = $displays[$id]['settings'];
+
+    foreach ($items[$id] as $delta => &$item) {
+      // If the formatter is configured to add rel="nofollow" to links, then
+      // add them here.
+      if (!empty($settings['nofollow'])) {
+        $item['options']['attributes']['rel'] = 'nofollow';
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function url_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $element = array();
+  $intance_settings = $instance['settings'];
+  $settings = $display['settings'];
+
+  foreach ($items as $delta => $item) {
+    // By default use the full URL as the link title.
+    $link_title = $item['value'];
+
+    // If the title field value is available, use it for the link title.
+    if (!empty($item['title'])) {
+      // Unsanitizied token replacement here because $options['HTML'] is FALSE
+      // by default in theme_link().
+      $link_title = token_replace($item['title'], array($entity_type => $entity), array('sanitize' => FALSE, 'clear' => TRUE));
+    }
+
+    // Trim the link title to the desired length.
+    if (!empty($settings['trim_length'])) {
+      $link_title = truncate_utf8($link_title, $settings['trim_length'], FALSE, TRUE);
+    }
+
+    $element[$delta] = array(
+      '#type' => 'link',
+      '#title' => $link_title,
+      '#href' => $item['path'],
+      '#options' => $item['options'],
+    );
+  }
+
+  return $element;
+}
+
+/**
+ * Return the HTML title from an URL.
+ *
+ * @param string $url
+ *   An URL to request with drupal_http_request().
+ *
+ * @return string
+ *   The HTML title of the URL if found.
+ */
+function url_fetch_title($url) {
+  $request = drupal_http_request($url);
+  if (empty($request->error) && $request->code == 200 && !empty($request->data)) {
+    if (preg_match('!<title>(.*?)</title>!iu', $request->data, $matches)) {
+      // Title tags should be encoded, but we want the raw value.
+      return decode_entities($matches[1]);
+    }
+  }
+}
+
+/**
+ * This is a copy of the form_validate_url() function from Drupal 8.
+ *
+ * Note that #maxlength and #required is validated by _form_validate() already.
+ */
+function url_validate_url(&$element, &$form_state) {
+  $value = trim($element['#value']);
+  form_set_value($element, $value, $form_state);
+
+  if ($value !== '' && !valid_url($value, TRUE)) {
+    form_error($element, t('The URL %url is not valid.', array('%url' => $value)));
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/url/url.test	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,225 @@
+<?php
+
+/**
+ * @file
+ * Tests for url.module.
+ */
+
+/**
+ * Tests for URL field types.
+ */
+class URLFieldTestCase extends DrupalWebTestCase {
+  protected $field;
+  protected $instance;
+  protected $web_user;
+
+  public static function getInfo() {
+    return array(
+      'name'  => 'URL field',
+      'description'  => 'Test the creation of URL fields.',
+      'group' => 'Field types',
+    );
+  }
+
+  function setUp() {
+    parent::setUp(array('url', 'field_test'));
+    $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer content types'));
+    $this->drupalLogin($this->web_user);
+  }
+
+  /**
+   * Test number_decimal field.
+   */
+  function testURLFieldValidation() {
+    // Create a field with settings to validate.
+    $this->field = array(
+      'field_name' => drupal_strtolower($this->randomName()),
+      'type' => 'url',
+    );
+    field_create_field($this->field);
+    $this->instance = array(
+      'field_name' => $this->field['field_name'],
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
+      'settings' => array(
+        'title_field' => FALSE,
+        'title_fetch' => FALSE,
+      ),
+      'widget' => array(
+        'type' => 'url_external',
+      ),
+      'display' => array(
+        'default' => array(
+          'type' => 'url_default',
+        ),
+      ),
+    );
+    field_create_instance($this->instance);
+
+    // Display creation form.
+    $this->drupalGet('test-entity/add/test-bundle');
+    $langcode = LANGUAGE_NONE;
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value]", '', 'URL value field is displayed');
+    $this->assertNoFieldByName("{$this->field['field_name']}[$langcode][0][title]", '', 'URL title field is not displayed');
+
+    // Submit a signed URL value.
+    $value = 'http://www.google.com/';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value]" => $value,
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    $id = $match[1];
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $this->assertRaw($value, 'Value is displayed.');
+
+    // Try to create entries with invalid URLs.
+    $wrong_entries = array(
+      // Missing protcol
+      'not-an-url',
+      // Invalid protocol
+      'invalid://not-a-valid-protocol',
+      // Missing host name
+      'http://',
+    );
+
+    foreach ($wrong_entries as $wrong_entry) {
+      $this->drupalGet('test-entity/add/test-bundle');
+      $edit = array(
+        "{$this->field['field_name']}[$langcode][0][value]" => $wrong_entry,
+      );
+      $this->drupalPost(NULL, $edit, t('Save'));
+      $this->assertText(t('The URL @url is not valid.', array('@url' => $wrong_entry)), 'Correctly failed to save invalid URL');
+    }
+  }
+
+  function _testURLFieldWithTitles() {
+    // Create a field with settings to validate.
+    $this->field = array(
+      'field_name' => drupal_strtolower($this->randomName()),
+      'type' => 'url',
+    );
+    field_create_field($this->field);
+    $this->instance = array(
+      'field_name' => $this->field['field_name'],
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
+      'settings' => array(
+        'title_field' => TRUE,
+        'title_fetch' => FALSE,
+      ),
+      'widget' => array(
+        'type' => 'url_external',
+      ),
+      'display' => array(
+        'default' => array(
+          'type' => 'url_default',
+        ),
+      ),
+    );
+    field_create_instance($this->instance);
+
+    // Display creation form.
+    $this->drupalGet('test-entity/add/test-bundle');
+    $langcode = LANGUAGE_NONE;
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][value]", '', 'URL value field is displayed');
+    $this->assertFieldByName("{$this->field['field_name']}[$langcode][0][title]", '', 'URL title field is displayed');
+
+    // Submit a signed URL value.
+    $value = 'http://www.google.com/';
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value]" => $value,
+      "{$this->field['field_name']}[$langcode][0][title]" => '',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    $id = $match[1];
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+
+    $expected_link = l($value, $value);
+    $this->assertRaw($expected_link, 'Link with URL as the title is displayed.');
+
+    $title = $this->randomName();
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][title]" => $title,
+    );
+    $this->drupalPost("test-entity/manage/$id/edit", $edit, t('Save'));
+    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
+
+    $expected_link = l($title, $value);
+    $this->assertRaw($expected_link, 'Link with overridden title is displayed.');
+  }
+
+  function testURLFieldAutomaticTitles() {
+    $node = $this->drupalCreateNode(array('title' => 'Node "title"'));
+
+    // Create a field with settings to validate.
+    $this->field = array(
+      'field_name' => drupal_strtolower($this->randomName()),
+      'type' => 'url',
+    );
+    field_create_field($this->field);
+    $this->instance = array(
+      'field_name' => $this->field['field_name'],
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
+      'settings' => array(
+        'title_field' => FALSE,
+        'title_fetch' => TRUE,
+      ),
+      'widget' => array(
+        'type' => 'url_external',
+      ),
+      'display' => array(
+        'default' => array(
+          'type' => 'url_default',
+        ),
+      ),
+    );
+    field_create_instance($this->instance);
+
+    // Submit an URL on the current site.
+    $langcode = LANGUAGE_NONE;
+    $value = url('node/' . $node->nid, array('absolute' => TRUE));
+    $edit = array(
+      "{$this->field['field_name']}[$langcode][0][value]" => $value,
+    );
+    $this->drupalPost('test-entity/add/test-bundle', $edit, t('Save'));
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
+    $id = $match[1];
+
+    $entity = field_test_entity_test_load($id);
+    $expected_title = t('!title | !sitename', array('!title' => $node->title, '!sitename' => variable_get('site_name', 'Drupal')));
+    $this->assertEqual($entity->{$this->field['field_name']}[$langcode][0]['title'], $expected_title, 'Title fetched and decoded from URL');
+  }
+
+  /**
+   * Test URL field creation from the UI.
+   */
+  function testURLFieldCreation() {
+    // Display the "Add content type" form.
+    $this->drupalGet('admin/structure/types/add');
+
+    // Add a content type.
+    $name = $this->randomName();
+    $type = drupal_strtolower($name);
+    $edit = array('name' => $name, 'type' => $type);
+    $this->drupalPost(NULL, $edit, t('Save and add fields'));
+
+    // Add an URL field to the newly-created type.
+    $label = $this->randomName();
+    $field_name = drupal_strtolower($label);
+    $edit = array(
+      'fields[_add_new_field][label]'=> $label,
+      'fields[_add_new_field][field_name]' => $field_name,
+      'fields[_add_new_field][type]' => 'url',
+      'fields[_add_new_field][widget_type]' => 'url_external',
+    );
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Load the formatter page to check that the settings summary does not
+    // generate warnings.
+    // @todo Mess with the formatter settings a bit here.
+    $this->drupalGet("admin/structure/types/manage/$type/display");
+  }
+}